mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-26 02:10:59 +00:00
Merge pull request #1127 from mitmproxy/tcp-flows
mitmdump: Add Basic Support for TCP Flows
This commit is contained in:
commit
ebaad91484
@ -320,7 +320,6 @@ class DumpMaster(flow.FlowMaster):
|
|||||||
self.outfile.flush()
|
self.outfile.flush()
|
||||||
|
|
||||||
def _process_flow(self, f):
|
def _process_flow(self, f):
|
||||||
self.state.delete_flow(f)
|
|
||||||
if self.filt and not f.match(self.filt):
|
if self.filt and not f.match(self.filt):
|
||||||
return
|
return
|
||||||
|
|
||||||
@ -328,6 +327,7 @@ class DumpMaster(flow.FlowMaster):
|
|||||||
|
|
||||||
def handle_request(self, f):
|
def handle_request(self, f):
|
||||||
flow.FlowMaster.handle_request(self, f)
|
flow.FlowMaster.handle_request(self, f)
|
||||||
|
self.state.delete_flow(f)
|
||||||
if f:
|
if f:
|
||||||
f.reply()
|
f.reply()
|
||||||
return f
|
return f
|
||||||
|
@ -3,7 +3,6 @@
|
|||||||
"""
|
"""
|
||||||
from __future__ import absolute_import
|
from __future__ import absolute_import
|
||||||
|
|
||||||
import traceback
|
|
||||||
from abc import abstractmethod, ABCMeta
|
from abc import abstractmethod, ABCMeta
|
||||||
import hashlib
|
import hashlib
|
||||||
import sys
|
import sys
|
||||||
@ -18,12 +17,13 @@ from typing import List, Optional, Set
|
|||||||
from netlib import wsgi, odict
|
from netlib import wsgi, odict
|
||||||
from netlib.exceptions import HttpException
|
from netlib.exceptions import HttpException
|
||||||
from netlib.http import Headers, http1, cookies
|
from netlib.http import Headers, http1, cookies
|
||||||
|
from netlib.utils import clean_bin
|
||||||
from . import controller, tnetstring, filt, script, version, flow_format_compat
|
from . import controller, tnetstring, filt, script, version, flow_format_compat
|
||||||
from .onboarding import app
|
from .onboarding import app
|
||||||
from .proxy.config import HostMatcher
|
from .proxy.config import HostMatcher
|
||||||
from .protocol.http_replay import RequestReplayThread
|
from .protocol.http_replay import RequestReplayThread
|
||||||
from .exceptions import Kill, FlowReadException
|
from .exceptions import Kill, FlowReadException
|
||||||
from .models import ClientConnection, ServerConnection, HTTPFlow, HTTPRequest, FLOW_TYPES
|
from .models import ClientConnection, ServerConnection, HTTPFlow, HTTPRequest, FLOW_TYPES, TCPFlow
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
|
|
||||||
@ -651,8 +651,9 @@ class FlowMaster(controller.ServerMaster):
|
|||||||
if server:
|
if server:
|
||||||
self.add_server(server)
|
self.add_server(server)
|
||||||
self.state = state
|
self.state = state
|
||||||
self.server_playback = None
|
self.active_flows = set() # type: Set[Flow]
|
||||||
self.client_playback = None
|
self.server_playback = None # type: Optional[ServerPlaybackState]
|
||||||
|
self.client_playback = None # type: Optional[ClientPlaybackState]
|
||||||
self.kill_nonreplay = False
|
self.kill_nonreplay = False
|
||||||
self.scripts = [] # type: List[script.Script]
|
self.scripts = [] # type: List[script.Script]
|
||||||
self.pause_scripts = False
|
self.pause_scripts = False
|
||||||
@ -898,6 +899,17 @@ class FlowMaster(controller.ServerMaster):
|
|||||||
self.handle_response(f)
|
self.handle_response(f)
|
||||||
if f.error:
|
if f.error:
|
||||||
self.handle_error(f)
|
self.handle_error(f)
|
||||||
|
elif isinstance(f, TCPFlow):
|
||||||
|
messages = f.messages
|
||||||
|
f.messages = []
|
||||||
|
f.reply = controller.DummyReply()
|
||||||
|
self.handle_tcp_open(f)
|
||||||
|
while messages:
|
||||||
|
f.messages.append(messages.pop(0))
|
||||||
|
self.handle_tcp_message(f)
|
||||||
|
if f.error:
|
||||||
|
self.handle_tcp_error(f)
|
||||||
|
self.handle_tcp_close(f)
|
||||||
else:
|
else:
|
||||||
raise NotImplementedError()
|
raise NotImplementedError()
|
||||||
|
|
||||||
@ -1020,6 +1032,7 @@ class FlowMaster(controller.ServerMaster):
|
|||||||
return
|
return
|
||||||
if f not in self.state.flows: # don't add again on replay
|
if f not in self.state.flows: # don't add again on replay
|
||||||
self.state.add_flow(f)
|
self.state.add_flow(f)
|
||||||
|
self.active_flows.add(f)
|
||||||
self.replacehooks.run(f)
|
self.replacehooks.run(f)
|
||||||
self.setheaders.run(f)
|
self.setheaders.run(f)
|
||||||
self.process_new_request(f)
|
self.process_new_request(f)
|
||||||
@ -1040,6 +1053,7 @@ class FlowMaster(controller.ServerMaster):
|
|||||||
return f
|
return f
|
||||||
|
|
||||||
def handle_response(self, f):
|
def handle_response(self, f):
|
||||||
|
self.active_flows.discard(f)
|
||||||
self.state.update_flow(f)
|
self.state.update_flow(f)
|
||||||
self.replacehooks.run(f)
|
self.replacehooks.run(f)
|
||||||
self.setheaders.run(f)
|
self.setheaders.run(f)
|
||||||
@ -1085,18 +1099,47 @@ class FlowMaster(controller.ServerMaster):
|
|||||||
self.add_event('"{}" reloaded.'.format(s.filename), 'info')
|
self.add_event('"{}" reloaded.'.format(s.filename), 'info')
|
||||||
return ok
|
return ok
|
||||||
|
|
||||||
def handle_tcp_message(self, m):
|
def handle_tcp_open(self, flow):
|
||||||
self.run_script_hook("tcp_message", m)
|
# TODO: This would break mitmproxy currently.
|
||||||
m.reply()
|
# self.state.add_flow(flow)
|
||||||
|
self.active_flows.add(flow)
|
||||||
|
self.run_script_hook("tcp_open", flow)
|
||||||
|
flow.reply()
|
||||||
|
|
||||||
|
def handle_tcp_message(self, flow):
|
||||||
|
self.run_script_hook("tcp_message", flow)
|
||||||
|
message = flow.messages[-1]
|
||||||
|
direction = "->" if message.from_client else "<-"
|
||||||
|
self.add_event("{client} {direction} tcp {direction} {server}".format(
|
||||||
|
client=repr(flow.client_conn.address),
|
||||||
|
server=repr(flow.server_conn.address),
|
||||||
|
direction=direction,
|
||||||
|
), "info")
|
||||||
|
self.add_event(clean_bin(message.content), "debug")
|
||||||
|
flow.reply()
|
||||||
|
|
||||||
|
def handle_tcp_error(self, flow):
|
||||||
|
self.add_event("Error in TCP connection to {}: {}".format(
|
||||||
|
repr(flow.server_conn.address),
|
||||||
|
flow.error
|
||||||
|
), "info")
|
||||||
|
self.run_script_hook("tcp_error", flow)
|
||||||
|
flow.reply()
|
||||||
|
|
||||||
|
def handle_tcp_close(self, flow):
|
||||||
|
self.active_flows.discard(flow)
|
||||||
|
if self.stream:
|
||||||
|
self.stream.add(flow)
|
||||||
|
self.run_script_hook("tcp_close", flow)
|
||||||
|
flow.reply()
|
||||||
|
|
||||||
def shutdown(self):
|
def shutdown(self):
|
||||||
super(FlowMaster, self).shutdown()
|
super(FlowMaster, self).shutdown()
|
||||||
|
|
||||||
# Add all flows that are still active
|
# Add all flows that are still active
|
||||||
if self.stream:
|
if self.stream:
|
||||||
for i in self.state.flows:
|
for flow in self.active_flows:
|
||||||
if not i.response:
|
self.stream.add(flow)
|
||||||
self.stream.add(i)
|
|
||||||
self.stop_stream()
|
self.stop_stream()
|
||||||
|
|
||||||
self.unload_scripts()
|
self.unload_scripts()
|
||||||
|
@ -7,9 +7,11 @@ from .http import (
|
|||||||
from netlib.http import decoded
|
from netlib.http import decoded
|
||||||
from .connections import ClientConnection, ServerConnection
|
from .connections import ClientConnection, ServerConnection
|
||||||
from .flow import Flow, Error
|
from .flow import Flow, Error
|
||||||
|
from .tcp import TCPFlow
|
||||||
|
|
||||||
FLOW_TYPES = dict(
|
FLOW_TYPES = dict(
|
||||||
http=HTTPFlow
|
http=HTTPFlow,
|
||||||
|
tcp=TCPFlow,
|
||||||
)
|
)
|
||||||
|
|
||||||
__all__ = [
|
__all__ = [
|
||||||
@ -18,5 +20,6 @@ __all__ = [
|
|||||||
"make_connect_response", "expect_continue_response",
|
"make_connect_response", "expect_continue_response",
|
||||||
"ClientConnection", "ServerConnection",
|
"ClientConnection", "ServerConnection",
|
||||||
"Flow", "Error",
|
"Flow", "Error",
|
||||||
|
"TCPFlow"
|
||||||
"FLOW_TYPES"
|
"FLOW_TYPES"
|
||||||
]
|
]
|
||||||
|
@ -40,6 +40,9 @@ class Error(stateobject.StateObject):
|
|||||||
def __str__(self):
|
def __str__(self):
|
||||||
return self.msg
|
return self.msg
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return self.msg
|
||||||
|
|
||||||
@classmethod
|
@classmethod
|
||||||
def from_state(cls, state):
|
def from_state(cls, state):
|
||||||
# the default implementation assumes an empty constructor. Override
|
# the default implementation assumes an empty constructor. Override
|
||||||
@ -99,6 +102,12 @@ class Flow(stateobject.StateObject):
|
|||||||
self._backup = state.pop("backup")
|
self._backup = state.pop("backup")
|
||||||
super(Flow, self).set_state(state)
|
super(Flow, self).set_state(state)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_state(cls, state):
|
||||||
|
f = cls(None, None)
|
||||||
|
f.set_state(state)
|
||||||
|
return f
|
||||||
|
|
||||||
def copy(self):
|
def copy(self):
|
||||||
f = copy.copy(self)
|
f = copy.copy(self)
|
||||||
|
|
||||||
|
@ -191,12 +191,6 @@ class HTTPFlow(Flow):
|
|||||||
response=HTTPResponse
|
response=HTTPResponse
|
||||||
)
|
)
|
||||||
|
|
||||||
@classmethod
|
|
||||||
def from_state(cls, state):
|
|
||||||
f = cls(None, None)
|
|
||||||
f.set_state(state)
|
|
||||||
return f
|
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
s = "<HTTPFlow"
|
s = "<HTTPFlow"
|
||||||
for a in ("request", "response", "error", "client_conn", "server_conn"):
|
for a in ("request", "response", "error", "client_conn", "server_conn"):
|
||||||
|
50
mitmproxy/models/tcp.py
Normal file
50
mitmproxy/models/tcp.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
import time
|
||||||
|
from typing import List
|
||||||
|
|
||||||
|
from netlib.utils import Serializable
|
||||||
|
from .flow import Flow
|
||||||
|
|
||||||
|
|
||||||
|
class TCPMessage(Serializable):
|
||||||
|
def __init__(self, from_client, content, timestamp=None):
|
||||||
|
self.content = content
|
||||||
|
self.from_client = from_client
|
||||||
|
if timestamp is None:
|
||||||
|
timestamp = time.time()
|
||||||
|
self.timestamp = timestamp
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def from_state(cls, state):
|
||||||
|
return cls(*state)
|
||||||
|
|
||||||
|
def get_state(self):
|
||||||
|
return self.from_client, self.content, self.timestamp
|
||||||
|
|
||||||
|
def set_state(self, state):
|
||||||
|
self.from_client = state.pop("from_client")
|
||||||
|
self.content = state.pop("content")
|
||||||
|
self.timestamp = state.pop("timestamp")
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "{direction} {content}".format(
|
||||||
|
direction="->" if self.from_client else "<-",
|
||||||
|
content=repr(self.content)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
|
class TCPFlow(Flow):
|
||||||
|
"""
|
||||||
|
A TCPFlow is a simplified representation of a TCP session.
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self, client_conn, server_conn, live=None):
|
||||||
|
super(TCPFlow, self).__init__("tcp", client_conn, server_conn, live)
|
||||||
|
self.messages = [] # type: List[TCPMessage]
|
||||||
|
|
||||||
|
_stateobject_attributes = Flow._stateobject_attributes.copy()
|
||||||
|
_stateobject_attributes.update(
|
||||||
|
messages=List[TCPMessage]
|
||||||
|
)
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
return "<TCPFlow ({} messages)>".format(len(self.messages))
|
@ -9,29 +9,26 @@ from netlib.exceptions import TcpException
|
|||||||
from netlib.tcp import ssl_read_select
|
from netlib.tcp import ssl_read_select
|
||||||
from netlib.utils import clean_bin
|
from netlib.utils import clean_bin
|
||||||
from ..exceptions import ProtocolException
|
from ..exceptions import ProtocolException
|
||||||
|
from ..models import Error
|
||||||
|
from ..models.tcp import TCPFlow, TCPMessage
|
||||||
|
|
||||||
from .base import Layer
|
from .base import Layer
|
||||||
|
|
||||||
|
|
||||||
class TcpMessage(object):
|
|
||||||
|
|
||||||
def __init__(self, client_conn, server_conn, sender, receiver, message):
|
|
||||||
self.client_conn = client_conn
|
|
||||||
self.server_conn = server_conn
|
|
||||||
self.sender = sender
|
|
||||||
self.receiver = receiver
|
|
||||||
self.message = message
|
|
||||||
|
|
||||||
|
|
||||||
class RawTCPLayer(Layer):
|
class RawTCPLayer(Layer):
|
||||||
chunk_size = 4096
|
chunk_size = 4096
|
||||||
|
|
||||||
def __init__(self, ctx, logging=True):
|
def __init__(self, ctx, ignore=False):
|
||||||
self.logging = logging
|
self.ignore = ignore
|
||||||
super(RawTCPLayer, self).__init__(ctx)
|
super(RawTCPLayer, self).__init__(ctx)
|
||||||
|
|
||||||
def __call__(self):
|
def __call__(self):
|
||||||
self.connect()
|
self.connect()
|
||||||
|
|
||||||
|
if not self.ignore:
|
||||||
|
flow = TCPFlow(self.client_conn, self.server_conn, self)
|
||||||
|
self.channel.ask("tcp_open", flow)
|
||||||
|
|
||||||
buf = memoryview(bytearray(self.chunk_size))
|
buf = memoryview(bytearray(self.chunk_size))
|
||||||
|
|
||||||
client = self.client_conn.connection
|
client = self.client_conn.connection
|
||||||
@ -59,30 +56,16 @@ class RawTCPLayer(Layer):
|
|||||||
return
|
return
|
||||||
continue
|
continue
|
||||||
|
|
||||||
tcp_message = TcpMessage(
|
tcp_message = TCPMessage(dst == server, buf[:size].tobytes())
|
||||||
self.client_conn, self.server_conn,
|
if not self.ignore:
|
||||||
self.client_conn if dst == server else self.server_conn,
|
flow.messages.append(tcp_message)
|
||||||
self.server_conn if dst == server else self.client_conn,
|
self.channel.ask("tcp_message", flow)
|
||||||
buf[:size].tobytes())
|
dst.sendall(tcp_message.content)
|
||||||
self.channel.ask("tcp_message", tcp_message)
|
|
||||||
dst.sendall(tcp_message.message)
|
|
||||||
|
|
||||||
if self.logging:
|
|
||||||
# log messages are prepended with the client address,
|
|
||||||
# hence the "weird" direction string.
|
|
||||||
if dst == server:
|
|
||||||
direction = "-> tcp -> {}".format(repr(self.server_conn.address))
|
|
||||||
else:
|
|
||||||
direction = "<- tcp <- {}".format(repr(self.server_conn.address))
|
|
||||||
data = clean_bin(tcp_message.message)
|
|
||||||
self.log(
|
|
||||||
"{}\r\n{}".format(direction, data),
|
|
||||||
"info"
|
|
||||||
)
|
|
||||||
|
|
||||||
except (socket.error, TcpException, SSL.Error) as e:
|
except (socket.error, TcpException, SSL.Error) as e:
|
||||||
six.reraise(
|
if not self.ignore:
|
||||||
ProtocolException,
|
flow.error = Error("TCP connection closed unexpectedly: {}".format(repr(e)))
|
||||||
ProtocolException("TCP connection closed unexpectedly: {}".format(repr(e))),
|
self.channel.tell("tcp_error", flow)
|
||||||
sys.exc_info()[2]
|
finally:
|
||||||
)
|
if not self.ignore:
|
||||||
|
self.channel.tell("tcp_close", flow)
|
||||||
|
@ -65,7 +65,7 @@ class RootContext(object):
|
|||||||
else:
|
else:
|
||||||
ignore = self.config.check_ignore((client_hello.sni, 443))
|
ignore = self.config.check_ignore((client_hello.sni, 443))
|
||||||
if ignore:
|
if ignore:
|
||||||
return RawTCPLayer(top_layer, logging=False)
|
return RawTCPLayer(top_layer, ignore=True)
|
||||||
|
|
||||||
# 2. Always insert a TLS layer, even if there's neither client nor server tls.
|
# 2. Always insert a TLS layer, even if there's neither client nor server tls.
|
||||||
# An inline script may upgrade from http to https,
|
# An inline script may upgrade from http to https,
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
def tcp_message(ctx, tm):
|
def tcp_message(ctx, flow):
|
||||||
if tm.sender == tm.server_conn:
|
message = flow.messages[-1]
|
||||||
tm.message = tm.message.replace("foo", "bar")
|
if not message.from_client:
|
||||||
|
message.content = message.content.replace("foo", "bar")
|
||||||
|
@ -680,6 +680,10 @@ class TestSerialize:
|
|||||||
for i in range(3):
|
for i in range(3):
|
||||||
f = tutils.tflow(err=True)
|
f = tutils.tflow(err=True)
|
||||||
w.add(f)
|
w.add(f)
|
||||||
|
f = tutils.ttcpflow()
|
||||||
|
w.add(f)
|
||||||
|
f = tutils.ttcpflow(err=True)
|
||||||
|
w.add(f)
|
||||||
|
|
||||||
sio.seek(0)
|
sio.seek(0)
|
||||||
return flow.FlowReader(sio)
|
return flow.FlowReader(sio)
|
||||||
@ -1151,6 +1155,10 @@ class TestError:
|
|||||||
e3 = e.copy()
|
e3 = e.copy()
|
||||||
assert e3.get_state() == e.get_state()
|
assert e3.get_state() == e.get_state()
|
||||||
|
|
||||||
|
def test_repr(self):
|
||||||
|
e = Error("yay")
|
||||||
|
assert repr(e)
|
||||||
|
|
||||||
|
|
||||||
class TestClientConnection:
|
class TestClientConnection:
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ from pathod import pathoc, pathod
|
|||||||
|
|
||||||
from mitmproxy.proxy.config import HostMatcher
|
from mitmproxy.proxy.config import HostMatcher
|
||||||
from mitmproxy.exceptions import Kill
|
from mitmproxy.exceptions import Kill
|
||||||
from mitmproxy.models import Error, HTTPResponse
|
from mitmproxy.models import Error, HTTPResponse, HTTPFlow
|
||||||
|
|
||||||
from . import tutils, tservers
|
from . import tutils, tservers
|
||||||
|
|
||||||
@ -177,9 +177,9 @@ class TcpMixin:
|
|||||||
assert n.status_code == 304
|
assert n.status_code == 304
|
||||||
assert i.status_code == 305
|
assert i.status_code == 305
|
||||||
assert i2.status_code == 306
|
assert i2.status_code == 306
|
||||||
assert any(f.response.status_code == 304 for f in self.master.state.flows)
|
assert any(f.response.status_code == 304 for f in self.master.state.flows if isinstance(f, HTTPFlow))
|
||||||
assert not any(f.response.status_code == 305 for f in self.master.state.flows)
|
assert not any(f.response.status_code == 305 for f in self.master.state.flows if isinstance(f, HTTPFlow))
|
||||||
assert not any(f.response.status_code == 306 for f in self.master.state.flows)
|
assert not any(f.response.status_code == 306 for f in self.master.state.flows if isinstance(f, HTTPFlow))
|
||||||
|
|
||||||
# Test that we get the original SSL cert
|
# Test that we get the original SSL cert
|
||||||
if self.ssl:
|
if self.ssl:
|
||||||
|
@ -50,9 +50,8 @@ class TestMaster(flow.FlowMaster):
|
|||||||
def clear_log(self):
|
def clear_log(self):
|
||||||
self.log = []
|
self.log = []
|
||||||
|
|
||||||
def handle_log(self, l):
|
def add_event(self, message, level=None):
|
||||||
self.log.append(l.msg)
|
self.log.append(message)
|
||||||
l.reply()
|
|
||||||
|
|
||||||
|
|
||||||
class ProxyThread(threading.Thread):
|
class ProxyThread(threading.Thread):
|
||||||
|
@ -3,6 +3,8 @@ import shutil
|
|||||||
import tempfile
|
import tempfile
|
||||||
import argparse
|
import argparse
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
|
from mitmproxy.models.tcp import TCPMessage
|
||||||
from six.moves import cStringIO as StringIO
|
from six.moves import cStringIO as StringIO
|
||||||
from contextlib import contextmanager
|
from contextlib import contextmanager
|
||||||
|
|
||||||
@ -12,7 +14,7 @@ import netlib.utils
|
|||||||
import netlib.tutils
|
import netlib.tutils
|
||||||
from mitmproxy import utils, controller
|
from mitmproxy import utils, controller
|
||||||
from mitmproxy.models import (
|
from mitmproxy.models import (
|
||||||
ClientConnection, ServerConnection, Error, HTTPRequest, HTTPResponse, HTTPFlow
|
ClientConnection, ServerConnection, Error, HTTPRequest, HTTPResponse, HTTPFlow, TCPFlow
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
||||||
@ -45,6 +47,26 @@ def skip_appveyor(fn):
|
|||||||
return fn
|
return fn
|
||||||
|
|
||||||
|
|
||||||
|
def ttcpflow(client_conn=True, server_conn=True, messages=True, err=None):
|
||||||
|
if client_conn is True:
|
||||||
|
client_conn = tclient_conn()
|
||||||
|
if server_conn is True:
|
||||||
|
server_conn = tserver_conn()
|
||||||
|
if messages is True:
|
||||||
|
messages = [
|
||||||
|
TCPMessage(True, b"hello"),
|
||||||
|
TCPMessage(False, b"it's me"),
|
||||||
|
]
|
||||||
|
if err is True:
|
||||||
|
err = terr()
|
||||||
|
|
||||||
|
f = TCPFlow(client_conn, server_conn)
|
||||||
|
f.messages = messages
|
||||||
|
f.error = err
|
||||||
|
f.reply = controller.DummyReply()
|
||||||
|
return f
|
||||||
|
|
||||||
|
|
||||||
def tflow(client_conn=True, server_conn=True, req=True, resp=None, err=None):
|
def tflow(client_conn=True, server_conn=True, req=True, resp=None, err=None):
|
||||||
"""
|
"""
|
||||||
@type client_conn: bool | None | mitmproxy.proxy.connection.ClientConnection
|
@type client_conn: bool | None | mitmproxy.proxy.connection.ClientConnection
|
||||||
@ -52,7 +74,7 @@ def tflow(client_conn=True, server_conn=True, req=True, resp=None, err=None):
|
|||||||
@type req: bool | None | mitmproxy.protocol.http.HTTPRequest
|
@type req: bool | None | mitmproxy.protocol.http.HTTPRequest
|
||||||
@type resp: bool | None | mitmproxy.protocol.http.HTTPResponse
|
@type resp: bool | None | mitmproxy.protocol.http.HTTPResponse
|
||||||
@type err: bool | None | mitmproxy.protocol.primitives.Error
|
@type err: bool | None | mitmproxy.protocol.primitives.Error
|
||||||
@return: bool | None | mitmproxy.protocol.http.HTTPFlow
|
@return: mitmproxy.protocol.http.HTTPFlow
|
||||||
"""
|
"""
|
||||||
if client_conn is True:
|
if client_conn is True:
|
||||||
client_conn = tclient_conn()
|
client_conn = tclient_conn()
|
||||||
|
Loading…
Reference in New Issue
Block a user