Move all tools into mitmproxy.tools, move models/* to top level

The primary motivation here (and for all the other moving around) is to present
a clean "front of house" to library users, and to migrate primary objects to
the top of the module hierarchy.
This commit is contained in:
Aldo Cortesi 2016-10-19 15:25:39 +13:00
parent 5a68d21e8c
commit 24cf8da27e
95 changed files with 381 additions and 378 deletions

View File

@ -5,11 +5,11 @@ API
=== ===
- Errors - Errors
- `mitmproxy.models.flow.Error <#mitmproxy.models.flow.Error>`_ - `mitmproxy.flow.Error <#mitmproxy.flow.Error>`_
- HTTP - HTTP
- `mitmproxy.models.http.HTTPRequest <#mitmproxy.models.http.HTTPRequest>`_ - `mitmproxy.http.HTTPRequest <#mitmproxy.http.HTTPRequest>`_
- `mitmproxy.models.http.HTTPResponse <#mitmproxy.models.http.HTTPResponse>`_ - `mitmproxy.http.HTTPResponse <#mitmproxy.http.HTTPResponse>`_
- `mitmproxy.models.http.HTTPFlow <#mitmproxy.models.http.HTTPFlow>`_ - `mitmproxy.http.HTTPFlow <#mitmproxy.http.HTTPFlow>`_
- Logging - Logging
- `mitmproxy.log.Log <#mitmproxy.controller.Log>`_ - `mitmproxy.log.Log <#mitmproxy.controller.Log>`_
- `mitmproxy.log.LogEntry <#mitmproxy.controller.LogEntry>`_ - `mitmproxy.log.LogEntry <#mitmproxy.controller.LogEntry>`_
@ -18,19 +18,19 @@ API
Errors Errors
------ ------
.. autoclass:: mitmproxy.models.flow.Error .. autoclass:: mitmproxy.flow.Error
:inherited-members: :inherited-members:
HTTP HTTP
---- ----
.. autoclass:: mitmproxy.models.http.HTTPRequest .. autoclass:: mitmproxy.http.HTTPRequest
:inherited-members: :inherited-members:
.. autoclass:: mitmproxy.models.http.HTTPResponse .. autoclass:: mitmproxy.http.HTTPResponse
:inherited-members: :inherited-members:
.. autoclass:: mitmproxy.models.http.HTTPFlow .. autoclass:: mitmproxy.http.HTTPFlow
:inherited-members: :inherited-members:
Logging Logging

View File

@ -1,6 +1,6 @@
import random import random
import sys import sys
from mimtproxy import io from mitmproxy import io
class Writer: class Writer:

View File

@ -1,7 +1,7 @@
""" """
This example shows two ways to redirect flows to other destinations. This example shows two ways to redirect flows to other destinations.
""" """
from mitmproxy.models import HTTPResponse from mitmproxy import http
def request(flow): def request(flow):
@ -11,7 +11,7 @@ def request(flow):
# Method 1: Answer with a locally generated response # Method 1: Answer with a locally generated response
if flow.request.pretty_host.endswith("example.com"): if flow.request.pretty_host.endswith("example.com"):
flow.response = HTTPResponse.make(200, b"Hello World", {"Content-Type": "text/html"}) flow.response = http.HTTPResponse.make(200, b"Hello World", {"Content-Type": "text/html"})
# Method 2: Redirect the request to a different server # Method 2: Redirect the request to a different server
if flow.request.pretty_host.endswith("example.org"): if flow.request.pretty_host.endswith("example.org"):

View File

@ -3,7 +3,6 @@ from mitmproxy import ctx
from mitmproxy import io from mitmproxy import io
class ClientPlayback: class ClientPlayback:
def __init__(self): def __init__(self):
self.flows = None self.flows = None

View File

@ -8,7 +8,7 @@ from mitmproxy import io
class FileStreamer: class FileStreamer:
def __init__(self): def __init__(self):
self.stream = None self.stream = None
self.active_flows = set() # type: Set[models.Flow] self.active_flows = set() # type: Set[flow.Flow]
def start_stream_to_path(self, path, mode, flt): def start_stream_to_path(self, path, mode, flt):
path = os.path.expanduser(path) path = os.path.expanduser(path)

View File

@ -3,12 +3,12 @@ from abc import abstractmethod, ABCMeta
from typing import List # noqa from typing import List # noqa
from mitmproxy import flowfilter from mitmproxy import flowfilter
from mitmproxy import models # noqa from mitmproxy import flow # noqa
class FlowList(metaclass=ABCMeta): class FlowList(metaclass=ABCMeta):
def __init__(self): def __init__(self):
self._list = [] # type: List[models.Flow] self._list = [] # type: List[flow.Flow]
def __iter__(self): def __iter__(self):
return iter(self._list) return iter(self._list)

View File

@ -1,4 +0,0 @@
from mitmproxy.console import master
__all__ = ["master"]

View File

@ -1,5 +1,6 @@
from mitmproxy import controller from mitmproxy import controller
from mitmproxy import models from mitmproxy import http
from mitmproxy import tcp
Events = frozenset([ Events = frozenset([
"clientconnect", "clientconnect",
@ -34,7 +35,7 @@ Events = frozenset([
def event_sequence(f): def event_sequence(f):
if isinstance(f, models.HTTPFlow): if isinstance(f, http.HTTPFlow):
if f.request: if f.request:
yield "requestheaders", f yield "requestheaders", f
yield "request", f yield "request", f
@ -43,7 +44,7 @@ def event_sequence(f):
yield "response", f yield "response", f
if f.error: if f.error:
yield "error", f yield "error", f
elif isinstance(f, models.TCPFlow): elif isinstance(f, tcp.TCPFlow):
messages = f.messages messages = f.messages
f.messages = [] f.messages = []
f.reply = controller.DummyReply() f.reply = controller.DummyReply()

View File

@ -3,8 +3,7 @@ import copy
import uuid import uuid
from mitmproxy import stateobject from mitmproxy import stateobject
from mitmproxy.models.connections import ClientConnection from mitmproxy import connections
from mitmproxy.models.connections import ServerConnection
from netlib import version from netlib import version
from typing import Optional # noqa from typing import Optional # noqa
@ -68,8 +67,8 @@ class Flow(stateobject.StateObject):
def __init__( def __init__(
self, self,
type: str, type: str,
client_conn: ClientConnection, client_conn: connections.ClientConnection,
server_conn: ServerConnection, server_conn: connections.ServerConnection,
live=None live=None
): ):
self.type = type self.type = type
@ -87,8 +86,8 @@ class Flow(stateobject.StateObject):
_stateobject_attributes = dict( _stateobject_attributes = dict(
id=str, id=str,
error=Error, error=Error,
client_conn=ClientConnection, client_conn=connections.ClientConnection,
server_conn=ServerConnection, server_conn=connections.ServerConnection,
type=str, type=str,
intercepted=bool, intercepted=bool,
marked=bool, marked=bool,

View File

@ -36,9 +36,9 @@ import re
import sys import sys
import functools import functools
from mitmproxy.models.http import HTTPFlow from mitmproxy import http
from mitmproxy.models.tcp import TCPFlow from mitmproxy import tcp
from mitmproxy.models.flow import Flow from mitmproxy import flow
from netlib import strutils from netlib import strutils
@ -94,7 +94,7 @@ class FHTTP(_Action):
code = "http" code = "http"
help = "Match HTTP flows" help = "Match HTTP flows"
@only(HTTPFlow) @only(http.HTTPFlow)
def __call__(self, f): def __call__(self, f):
return True return True
@ -103,7 +103,7 @@ class FTCP(_Action):
code = "tcp" code = "tcp"
help = "Match TCP flows" help = "Match TCP flows"
@only(TCPFlow) @only(tcp.TCPFlow)
def __call__(self, f): def __call__(self, f):
return True return True
@ -112,7 +112,7 @@ class FReq(_Action):
code = "q" code = "q"
help = "Match request with no response" help = "Match request with no response"
@only(HTTPFlow) @only(http.HTTPFlow)
def __call__(self, f): def __call__(self, f):
if not f.response: if not f.response:
return True return True
@ -122,7 +122,7 @@ class FResp(_Action):
code = "s" code = "s"
help = "Match response" help = "Match response"
@only(HTTPFlow) @only(http.HTTPFlow)
def __call__(self, f): def __call__(self, f):
return bool(f.response) return bool(f.response)
@ -162,7 +162,7 @@ class FAsset(_Action):
] ]
ASSET_TYPES = [re.compile(x) for x in ASSET_TYPES] ASSET_TYPES = [re.compile(x) for x in ASSET_TYPES]
@only(HTTPFlow) @only(http.HTTPFlow)
def __call__(self, f): def __call__(self, f):
if f.response: if f.response:
for i in self.ASSET_TYPES: for i in self.ASSET_TYPES:
@ -175,7 +175,7 @@ class FContentType(_Rex):
code = "t" code = "t"
help = "Content-type header" help = "Content-type header"
@only(HTTPFlow) @only(http.HTTPFlow)
def __call__(self, f): def __call__(self, f):
if _check_content_type(self.re, f.request): if _check_content_type(self.re, f.request):
return True return True
@ -188,7 +188,7 @@ class FContentTypeRequest(_Rex):
code = "tq" code = "tq"
help = "Request Content-Type header" help = "Request Content-Type header"
@only(HTTPFlow) @only(http.HTTPFlow)
def __call__(self, f): def __call__(self, f):
return _check_content_type(self.re, f.request) return _check_content_type(self.re, f.request)
@ -197,7 +197,7 @@ class FContentTypeResponse(_Rex):
code = "ts" code = "ts"
help = "Response Content-Type header" help = "Response Content-Type header"
@only(HTTPFlow) @only(http.HTTPFlow)
def __call__(self, f): def __call__(self, f):
if f.response: if f.response:
return _check_content_type(self.re, f.response) return _check_content_type(self.re, f.response)
@ -209,7 +209,7 @@ class FHead(_Rex):
help = "Header" help = "Header"
flags = re.MULTILINE flags = re.MULTILINE
@only(HTTPFlow) @only(http.HTTPFlow)
def __call__(self, f): def __call__(self, f):
if f.request and self.re.search(bytes(f.request.headers)): if f.request and self.re.search(bytes(f.request.headers)):
return True return True
@ -223,7 +223,7 @@ class FHeadRequest(_Rex):
help = "Request header" help = "Request header"
flags = re.MULTILINE flags = re.MULTILINE
@only(HTTPFlow) @only(http.HTTPFlow)
def __call__(self, f): def __call__(self, f):
if f.request and self.re.search(bytes(f.request.headers)): if f.request and self.re.search(bytes(f.request.headers)):
return True return True
@ -234,7 +234,7 @@ class FHeadResponse(_Rex):
help = "Response header" help = "Response header"
flags = re.MULTILINE flags = re.MULTILINE
@only(HTTPFlow) @only(http.HTTPFlow)
def __call__(self, f): def __call__(self, f):
if f.response and self.re.search(bytes(f.response.headers)): if f.response and self.re.search(bytes(f.response.headers)):
return True return True
@ -245,16 +245,16 @@ class FBod(_Rex):
help = "Body" help = "Body"
flags = re.DOTALL flags = re.DOTALL
@only(HTTPFlow, TCPFlow) @only(http.HTTPFlow, tcp.TCPFlow)
def __call__(self, f): def __call__(self, f):
if isinstance(f, HTTPFlow): if isinstance(f, http.HTTPFlow):
if f.request and f.request.raw_content: if f.request and f.request.raw_content:
if self.re.search(f.request.get_content(strict=False)): if self.re.search(f.request.get_content(strict=False)):
return True return True
if f.response and f.response.raw_content: if f.response and f.response.raw_content:
if self.re.search(f.response.get_content(strict=False)): if self.re.search(f.response.get_content(strict=False)):
return True return True
elif isinstance(f, TCPFlow): elif isinstance(f, tcp.TCPFlow):
for msg in f.messages: for msg in f.messages:
if self.re.search(msg.content): if self.re.search(msg.content):
return True return True
@ -266,13 +266,13 @@ class FBodRequest(_Rex):
help = "Request body" help = "Request body"
flags = re.DOTALL flags = re.DOTALL
@only(HTTPFlow, TCPFlow) @only(http.HTTPFlow, tcp.TCPFlow)
def __call__(self, f): def __call__(self, f):
if isinstance(f, HTTPFlow): if isinstance(f, http.HTTPFlow):
if f.request and f.request.raw_content: if f.request and f.request.raw_content:
if self.re.search(f.request.get_content(strict=False)): if self.re.search(f.request.get_content(strict=False)):
return True return True
elif isinstance(f, TCPFlow): elif isinstance(f, tcp.TCPFlow):
for msg in f.messages: for msg in f.messages:
if msg.from_client and self.re.search(msg.content): if msg.from_client and self.re.search(msg.content):
return True return True
@ -283,13 +283,13 @@ class FBodResponse(_Rex):
help = "Response body" help = "Response body"
flags = re.DOTALL flags = re.DOTALL
@only(HTTPFlow, TCPFlow) @only(http.HTTPFlow, tcp.TCPFlow)
def __call__(self, f): def __call__(self, f):
if isinstance(f, HTTPFlow): if isinstance(f, http.HTTPFlow):
if f.response and f.response.raw_content: if f.response and f.response.raw_content:
if self.re.search(f.response.get_content(strict=False)): if self.re.search(f.response.get_content(strict=False)):
return True return True
elif isinstance(f, TCPFlow): elif isinstance(f, tcp.TCPFlow):
for msg in f.messages: for msg in f.messages:
if not msg.from_client and self.re.search(msg.content): if not msg.from_client and self.re.search(msg.content):
return True return True
@ -300,7 +300,7 @@ class FMethod(_Rex):
help = "Method" help = "Method"
flags = re.IGNORECASE flags = re.IGNORECASE
@only(HTTPFlow) @only(http.HTTPFlow)
def __call__(self, f): def __call__(self, f):
return bool(self.re.search(f.request.data.method)) return bool(self.re.search(f.request.data.method))
@ -310,7 +310,7 @@ class FDomain(_Rex):
help = "Domain" help = "Domain"
flags = re.IGNORECASE flags = re.IGNORECASE
@only(HTTPFlow) @only(http.HTTPFlow)
def __call__(self, f): def __call__(self, f):
return bool(self.re.search(f.request.data.host)) return bool(self.re.search(f.request.data.host))
@ -327,7 +327,7 @@ class FUrl(_Rex):
toks = toks[1:] toks = toks[1:]
return klass(*toks) return klass(*toks)
@only(HTTPFlow) @only(http.HTTPFlow)
def __call__(self, f): def __call__(self, f):
return self.re.search(f.request.url) return self.re.search(f.request.url)
@ -360,7 +360,7 @@ class FCode(_Int):
code = "c" code = "c"
help = "HTTP response code" help = "HTTP response code"
@only(HTTPFlow) @only(http.HTTPFlow)
def __call__(self, f): def __call__(self, f):
if f.response and f.response.status_code == self.num: if f.response and f.response.status_code == self.num:
return True return True
@ -485,7 +485,7 @@ def _make():
bnf = _make() bnf = _make()
TFilter = Callable[[Flow], bool] TFilter = Callable[[flow.Flow], bool]
def parse(s: str) -> TFilter: def parse(s: str) -> TFilter:

View File

@ -1,6 +1,6 @@
import cgi import cgi
from mitmproxy.models import flow from mitmproxy import flow
from netlib import http from netlib import http
from netlib import version from netlib import version
from netlib import tcp from netlib import tcp

View File

@ -2,11 +2,18 @@ import os
from mitmproxy import exceptions from mitmproxy import exceptions
from mitmproxy import flowfilter from mitmproxy import flowfilter
from mitmproxy import models from mitmproxy import http
from mitmproxy import tcp
from mitmproxy.contrib import tnetstring from mitmproxy.contrib import tnetstring
from mitmproxy import io_compat from mitmproxy import io_compat
FLOW_TYPES = dict(
http=http.HTTPFlow,
tcp=tcp.TCPFlow,
)
class FlowWriter: class FlowWriter:
def __init__(self, fo): def __init__(self, fo):
self.fo = fo self.fo = fo
@ -31,9 +38,9 @@ class FlowReader:
data = io_compat.migrate_flow(data) data = io_compat.migrate_flow(data)
except ValueError as e: except ValueError as e:
raise exceptions.FlowReadException(str(e)) raise exceptions.FlowReadException(str(e))
if data["type"] not in models.FLOW_TYPES: if data["type"] not in FLOW_TYPES:
raise exceptions.FlowReadException("Unknown flow type: {}".format(data["type"])) raise exceptions.FlowReadException("Unknown flow type: {}".format(data["type"]))
yield models.FLOW_TYPES[data["type"]].from_state(data) yield FLOW_TYPES[data["type"]].from_state(data)
except ValueError as e: except ValueError as e:
if str(e) == "not a tnetstring: empty file": if str(e) == "not a tnetstring: empty file":
return # Error is due to EOF return # Error is due to EOF

View File

@ -9,12 +9,13 @@ from mitmproxy import options
from mitmproxy import controller from mitmproxy import controller
from mitmproxy import events from mitmproxy import events
from mitmproxy import exceptions from mitmproxy import exceptions
from mitmproxy import models from mitmproxy import connections
from mitmproxy import http
from mitmproxy import log from mitmproxy import log
from mitmproxy import io from mitmproxy import io
from mitmproxy.protocol import http_replay from mitmproxy.protocol import http_replay
from netlib import basethread from netlib import basethread
from netlib import http import netlib.http
from . import ctx as mitmproxy_ctx from . import ctx as mitmproxy_ctx
@ -117,13 +118,13 @@ class Master:
""" """
this method creates a new artificial and minimalist request also adds it to flowlist this method creates a new artificial and minimalist request also adds it to flowlist
""" """
c = models.ClientConnection.make_dummy(("", 0)) c = connections.ClientConnection.make_dummy(("", 0))
s = models.ServerConnection.make_dummy((host, port)) s = connections.ServerConnection.make_dummy((host, port))
f = models.HTTPFlow(c, s) f = http.HTTPFlow(c, s)
headers = http.Headers() headers = netlib.http.Headers()
req = models.HTTPRequest( req = http.HTTPRequest(
"absolute", "absolute",
method, method,
scheme, scheme,
@ -142,7 +143,7 @@ class Master:
""" """
Loads a flow Loads a flow
""" """
if isinstance(f, models.HTTPFlow): if isinstance(f, http.HTTPFlow):
if self.server and self.options.mode == "reverse": if self.server and self.options.mode == "reverse":
f.request.host = self.server.config.upstream_server.address.host f.request.host = self.server.config.upstream_server.address.host
f.request.port = self.server.config.upstream_server.address.port f.request.port = self.server.config.upstream_server.address.port

View File

@ -1,23 +0,0 @@
from netlib.http import decoded
from .connections import ClientConnection, ServerConnection
from .flow import Flow, Error
from .http import (
HTTPFlow, HTTPRequest, HTTPResponse,
make_error_response, make_connect_request, make_connect_response, expect_continue_response
)
from .tcp import TCPFlow
FLOW_TYPES = dict(
http=HTTPFlow,
tcp=TCPFlow,
)
__all__ = [
"HTTPFlow", "HTTPRequest", "HTTPResponse", "decoded",
"make_error_response", "make_connect_request",
"make_connect_response", "expect_continue_response",
"ClientConnection", "ServerConnection",
"Flow", "Error",
"TCPFlow",
"FLOW_TYPES",
]

View File

@ -1,6 +1,6 @@
import netlib.exceptions import netlib.exceptions
from mitmproxy import exceptions from mitmproxy import exceptions
from mitmproxy import models from mitmproxy import connections
class _LayerCodeCompletion: class _LayerCodeCompletion:
@ -16,9 +16,9 @@ class _LayerCodeCompletion:
self.config = None self.config = None
"""@type: mitmproxy.proxy.ProxyConfig""" """@type: mitmproxy.proxy.ProxyConfig"""
self.client_conn = None self.client_conn = None
"""@type: mitmproxy.models.ClientConnection""" """@type: mitmproxy.connections.ClientConnection"""
self.server_conn = None self.server_conn = None
"""@type: mitmproxy.models.ServerConnection""" """@type: mitmproxy.connections.ServerConnection"""
self.channel = None self.channel = None
"""@type: mitmproxy.controller.Channel""" """@type: mitmproxy.controller.Channel"""
self.ctx = None self.ctx = None
@ -111,10 +111,10 @@ class ServerConnectionMixin:
self.server_conn = None self.server_conn = None
if self.config.options.spoof_source_address: if self.config.options.spoof_source_address:
self.server_conn = models.ServerConnection( self.server_conn = connections.ServerConnection(
server_address, (self.ctx.client_conn.address.host, 0), True) server_address, (self.ctx.client_conn.address.host, 0), True)
else: else:
self.server_conn = models.ServerConnection( self.server_conn = connections.ServerConnection(
server_address, (self.config.options.listen_host, 0)) server_address, (self.config.options.listen_host, 0))
self.__check_self_connect() self.__check_self_connect()
@ -157,7 +157,7 @@ class ServerConnectionMixin:
self.server_conn.close() self.server_conn.close()
self.channel.tell("serverdisconnect", self.server_conn) self.channel.tell("serverdisconnect", self.server_conn)
self.server_conn = models.ServerConnection( self.server_conn = connections.ServerConnection(
address, address,
(self.server_conn.source_address.host, 0), (self.server_conn.source_address.host, 0),
self.config.options.spoof_source_address self.config.options.spoof_source_address

View File

@ -3,10 +3,11 @@ import netlib.exceptions
import time import time
import traceback import traceback
from mitmproxy import exceptions from mitmproxy import exceptions
from mitmproxy import models from mitmproxy import http
from mitmproxy import flow
from mitmproxy.protocol import base from mitmproxy.protocol import base
from mitmproxy.protocol import websockets as pwebsockets from mitmproxy.protocol import websockets as pwebsockets
from netlib import http import netlib.http
from netlib import tcp from netlib import tcp
from netlib import websockets from netlib import websockets
@ -55,7 +56,7 @@ class _HttpTransmissionLayer(base.Layer):
def send_response_body(self, response, chunks): def send_response_body(self, response, chunks):
raise NotImplementedError() raise NotImplementedError()
def check_close_connection(self, flow): def check_close_connection(self, f):
raise NotImplementedError() raise NotImplementedError()
@ -140,9 +141,9 @@ class HttpLayer(base.Layer):
self.__initial_server_tls = self.server_tls self.__initial_server_tls = self.server_tls
self.__initial_server_conn = self.server_conn self.__initial_server_conn = self.server_conn
while True: while True:
flow = models.HTTPFlow(self.client_conn, self.server_conn, live=self) f = http.HTTPFlow(self.client_conn, self.server_conn, live=self)
try: try:
request = self.get_request_from_client(flow) request = self.get_request_from_client(f)
# Make sure that the incoming request matches our expectations # Make sure that the incoming request matches our expectations
self.validate_request(request) self.validate_request(request)
except netlib.exceptions.HttpReadDisconnect: except netlib.exceptions.HttpReadDisconnect:
@ -165,7 +166,7 @@ class HttpLayer(base.Layer):
if not (self.http_authenticated or self.authenticate(request)): if not (self.http_authenticated or self.authenticate(request)):
return return
flow.request = request f.request = request
try: try:
# Regular Proxy Mode: Handle CONNECT # Regular Proxy Mode: Handle CONNECT
@ -176,74 +177,74 @@ class HttpLayer(base.Layer):
# HTTPS tasting means that ordinary errors like resolution and # HTTPS tasting means that ordinary errors like resolution and
# connection errors can happen here. # connection errors can happen here.
self.send_error_response(502, repr(e)) self.send_error_response(502, repr(e))
flow.error = models.Error(str(e)) f.error = flow.Error(str(e))
self.channel.ask("error", flow) self.channel.ask("error", f)
return return
# update host header in reverse proxy mode # update host header in reverse proxy mode
if self.config.options.mode == "reverse": if self.config.options.mode == "reverse":
flow.request.headers["Host"] = self.config.upstream_server.address.host f.request.headers["Host"] = self.config.upstream_server.address.host
# set upstream auth # set upstream auth
if self.mode == "upstream" and self.config.upstream_auth is not None: if self.mode == "upstream" and self.config.upstream_auth is not None:
flow.request.headers["Proxy-Authorization"] = self.config.upstream_auth f.request.headers["Proxy-Authorization"] = self.config.upstream_auth
self.process_request_hook(flow) self.process_request_hook(f)
try: try:
if websockets.check_handshake(request.headers) and websockets.check_client_version(request.headers): if websockets.check_handshake(request.headers) and websockets.check_client_version(request.headers):
# We only support RFC6455 with WebSockets version 13 # We only support RFC6455 with WebSockets version 13
# allow inline scripts to manipulate the client handshake # allow inline scripts to manipulate the client handshake
self.channel.ask("websocket_handshake", flow) self.channel.ask("websocket_handshake", f)
if not flow.response: if not f.response:
self.establish_server_connection( self.establish_server_connection(
flow.request.host, f.request.host,
flow.request.port, f.request.port,
flow.request.scheme f.request.scheme
) )
self.get_response_from_server(flow) self.get_response_from_server(f)
else: else:
# response was set by an inline script. # response was set by an inline script.
# we now need to emulate the responseheaders hook. # we now need to emulate the responseheaders hook.
self.channel.ask("responseheaders", flow) self.channel.ask("responseheaders", f)
self.log("response", "debug", [repr(flow.response)]) self.log("response", "debug", [repr(f.response)])
self.channel.ask("response", flow) self.channel.ask("response", f)
self.send_response_to_client(flow) self.send_response_to_client(f)
if self.check_close_connection(flow): if self.check_close_connection(f):
return return
# Handle 101 Switching Protocols # Handle 101 Switching Protocols
if flow.response.status_code == 101: if f.response.status_code == 101:
return self.handle_101_switching_protocols(flow) return self.handle_101_switching_protocols(f)
# Upstream Proxy Mode: Handle CONNECT # Upstream Proxy Mode: Handle CONNECT
if flow.request.first_line_format == "authority" and flow.response.status_code == 200: if f.request.first_line_format == "authority" and f.response.status_code == 200:
self.handle_upstream_mode_connect(flow.request.copy()) self.handle_upstream_mode_connect(f.request.copy())
return return
except (exceptions.ProtocolException, netlib.exceptions.NetlibException) as e: except (exceptions.ProtocolException, netlib.exceptions.NetlibException) as e:
self.send_error_response(502, repr(e)) self.send_error_response(502, repr(e))
if not flow.response: if not f.response:
flow.error = models.Error(str(e)) f.error = flow.Error(str(e))
self.channel.ask("error", flow) self.channel.ask("error", f)
return return
else: else:
raise exceptions.ProtocolException( raise exceptions.ProtocolException(
"Error in HTTP connection: %s" % repr(e) "Error in HTTP connection: %s" % repr(e)
) )
finally: finally:
if flow: if f:
flow.live = False f.live = False
def get_request_from_client(self, flow): def get_request_from_client(self, f):
request = self.read_request() request = self.read_request()
flow.request = request f.request = request
self.channel.ask("requestheaders", flow) self.channel.ask("requestheaders", f)
if request.headers.get("expect", "").lower() == "100-continue": if request.headers.get("expect", "").lower() == "100-continue":
# TODO: We may have to use send_response_headers for HTTP2 here. # TODO: We may have to use send_response_headers for HTTP2 here.
self.send_response(models.expect_continue_response) self.send_response(http.expect_continue_response)
request.headers.pop("expect") request.headers.pop("expect")
request.body = b"".join(self.read_request_body(request)) request.body = b"".join(self.read_request_body(request))
request.timestamp_end = time.time() request.timestamp_end = time.time()
@ -251,7 +252,7 @@ class HttpLayer(base.Layer):
def send_error_response(self, code, message, headers=None): def send_error_response(self, code, message, headers=None):
try: try:
response = models.make_error_response(code, message, headers) response = http.make_error_response(code, message, headers)
self.send_response(response) self.send_response(response)
except (netlib.exceptions.NetlibException, h2.exceptions.H2Error, exceptions.Http2ProtocolException): except (netlib.exceptions.NetlibException, h2.exceptions.H2Error, exceptions.Http2ProtocolException):
self.log(traceback.format_exc(), "debug") self.log(traceback.format_exc(), "debug")
@ -265,7 +266,7 @@ class HttpLayer(base.Layer):
def handle_regular_mode_connect(self, request): def handle_regular_mode_connect(self, request):
self.http_authenticated = True self.http_authenticated = True
self.set_server((request.host, request.port)) self.set_server((request.host, request.port))
self.send_response(models.make_connect_response(request.data.http_version)) self.send_response(http.make_connect_response(request.data.http_version))
layer = self.ctx.next_layer(self) layer = self.ctx.next_layer(self)
layer() layer()
@ -273,29 +274,29 @@ class HttpLayer(base.Layer):
layer = UpstreamConnectLayer(self, connect_request) layer = UpstreamConnectLayer(self, connect_request)
layer() layer()
def send_response_to_client(self, flow): def send_response_to_client(self, f):
if not flow.response.stream: if not f.response.stream:
# no streaming: # no streaming:
# we already received the full response from the server and can # we already received the full response from the server and can
# send it to the client straight away. # send it to the client straight away.
self.send_response(flow.response) self.send_response(f.response)
else: else:
# streaming: # streaming:
# First send the headers and then transfer the response incrementally # First send the headers and then transfer the response incrementally
self.send_response_headers(flow.response) self.send_response_headers(f.response)
chunks = self.read_response_body( chunks = self.read_response_body(
flow.request, f.request,
flow.response f.response
) )
if callable(flow.response.stream): if callable(f.response.stream):
chunks = flow.response.stream(chunks) chunks = f.response.stream(chunks)
self.send_response_body(flow.response, chunks) self.send_response_body(f.response, chunks)
flow.response.timestamp_end = time.time() f.response.timestamp_end = time.time()
def get_response_from_server(self, flow): def get_response_from_server(self, f):
def get_response(): def get_response():
self.send_request(flow.request) self.send_request(f.request)
flow.response = self.read_response_headers() f.response = self.read_response_headers()
try: try:
get_response() get_response()
@ -325,23 +326,23 @@ class HttpLayer(base.Layer):
get_response() get_response()
# call the appropriate script hook - this is an opportunity for an # call the appropriate script hook - this is an opportunity for an
# inline script to set flow.stream = True # inline script to set f.stream = True
self.channel.ask("responseheaders", flow) self.channel.ask("responseheaders", f)
if flow.response.stream: if f.response.stream:
flow.response.data.content = None f.response.data.content = None
else: else:
flow.response.data.content = b"".join(self.read_response_body( f.response.data.content = b"".join(self.read_response_body(
flow.request, f.request,
flow.response f.response
)) ))
flow.response.timestamp_end = time.time() f.response.timestamp_end = time.time()
# no further manipulation of self.server_conn beyond this point # no further manipulation of self.server_conn beyond this point
# we can safely set it as the final attribute value here. # we can safely set it as the final attribute value here.
flow.server_conn = self.server_conn f.server_conn = self.server_conn
def process_request_hook(self, flow): def process_request_hook(self, f):
# Determine .scheme, .host and .port attributes for inline scripts. # Determine .scheme, .host and .port attributes for inline scripts.
# For absolute-form requests, they are directly given in the request. # For absolute-form requests, they are directly given in the request.
# For authority-form requests, we only need to determine the request scheme. # For authority-form requests, we only need to determine the request scheme.
@ -353,13 +354,13 @@ class HttpLayer(base.Layer):
pass pass
else: else:
# Setting request.host also updates the host header, which we want to preserve # Setting request.host also updates the host header, which we want to preserve
host_header = flow.request.headers.get("host", None) host_header = f.request.headers.get("host", None)
flow.request.host = self.__initial_server_conn.address.host f.request.host = self.__initial_server_conn.address.host
flow.request.port = self.__initial_server_conn.address.port f.request.port = self.__initial_server_conn.address.port
if host_header: if host_header:
flow.request.headers["host"] = host_header f.request.headers["host"] = host_header
flow.request.scheme = "https" if self.__initial_server_tls else "http" f.request.scheme = "https" if self.__initial_server_tls else "http"
self.channel.ask("request", flow) self.channel.ask("request", f)
def establish_server_connection(self, host, port, scheme): def establish_server_connection(self, host, port, scheme):
address = tcp.Address((host, port)) address = tcp.Address((host, port))
@ -419,29 +420,29 @@ class HttpLayer(base.Layer):
self.config.authenticator.clean(request.headers) self.config.authenticator.clean(request.headers)
else: else:
if self.mode == "transparent": if self.mode == "transparent":
self.send_response(models.make_error_response( self.send_response(http.make_error_response(
401, 401,
"Authentication Required", "Authentication Required",
http.Headers(**self.config.authenticator.auth_challenge_headers()) netlib.http.Headers(**self.config.authenticator.auth_challenge_headers())
)) ))
else: else:
self.send_response(models.make_error_response( self.send_response(http.make_error_response(
407, 407,
"Proxy Authentication Required", "Proxy Authentication Required",
http.Headers(**self.config.authenticator.auth_challenge_headers()) netlib.http.Headers(**self.config.authenticator.auth_challenge_headers())
)) ))
return False return False
return True return True
def handle_101_switching_protocols(self, flow): def handle_101_switching_protocols(self, f):
""" """
Handle a successful HTTP 101 Switching Protocols Response, received after e.g. a WebSocket upgrade request. Handle a successful HTTP 101 Switching Protocols Response, received after e.g. a WebSocket upgrade request.
""" """
# Check for WebSockets handshake # Check for WebSockets handshake
is_websockets = ( is_websockets = (
flow and f and
websockets.check_handshake(flow.request.headers) and websockets.check_handshake(f.request.headers) and
websockets.check_handshake(flow.response.headers) websockets.check_handshake(f.response.headers)
) )
if is_websockets and not self.config.options.websockets: if is_websockets and not self.config.options.websockets:
self.log( self.log(
@ -450,7 +451,7 @@ class HttpLayer(base.Layer):
) )
if is_websockets and self.config.options.websockets: if is_websockets and self.config.options.websockets:
layer = pwebsockets.WebSocketsLayer(self, flow) layer = pwebsockets.WebSocketsLayer(self, f)
else: else:
layer = self.ctx.next_layer(self) layer = self.ctx.next_layer(self)

View File

@ -1,16 +1,16 @@
from mitmproxy import models from mitmproxy import http
from mitmproxy.protocol import http from mitmproxy.protocol import http as httpbase
from netlib.http import http1 from netlib.http import http1
class Http1Layer(http._HttpTransmissionLayer): class Http1Layer(httpbase._HttpTransmissionLayer):
def __init__(self, ctx, mode): def __init__(self, ctx, mode):
super().__init__(ctx) super().__init__(ctx)
self.mode = mode self.mode = mode
def read_request_headers(self): def read_request_headers(self):
return models.HTTPRequest.wrap( return http.HTTPRequest.wrap(
http1.read_request_head(self.client_conn.rfile) http1.read_request_head(self.client_conn.rfile)
) )
@ -28,7 +28,7 @@ class Http1Layer(http._HttpTransmissionLayer):
def read_response_headers(self): def read_response_headers(self):
resp = http1.read_response_head(self.server_conn.rfile) resp = http1.read_response_head(self.server_conn.rfile)
return models.HTTPResponse.wrap(resp) return http.HTTPResponse.wrap(resp)
def read_response_body(self, request, response): def read_response_body(self, request, response):
expected_size = http1.expected_http_body_size(request, response) expected_size = http1.expected_http_body_size(request, response)
@ -68,5 +68,5 @@ class Http1Layer(http._HttpTransmissionLayer):
return close_connection return close_connection
def __call__(self): def __call__(self):
layer = http.HttpLayer(self, self.mode) layer = httpbase.HttpLayer(self, self.mode)
layer() layer()

View File

@ -10,9 +10,9 @@ import queue
import netlib.exceptions import netlib.exceptions
from mitmproxy import exceptions from mitmproxy import exceptions
from mitmproxy import models from mitmproxy import http
from mitmproxy.protocol import base from mitmproxy.protocol import base
from mitmproxy.protocol import http from mitmproxy.protocol import http as httpbase
import netlib.http import netlib.http
from netlib import tcp from netlib import tcp
from netlib import basethread from netlib import basethread
@ -358,7 +358,7 @@ def detect_zombie_stream(func):
return wrapper return wrapper
class Http2SingleStreamLayer(http._HttpTransmissionLayer, basethread.BaseThread): class Http2SingleStreamLayer(httpbase._HttpTransmissionLayer, basethread.BaseThread):
def __init__(self, ctx, h2_connection, stream_id, request_headers): def __init__(self, ctx, h2_connection, stream_id, request_headers):
super().__init__( super().__init__(
@ -451,7 +451,7 @@ class Http2SingleStreamLayer(http._HttpTransmissionLayer, basethread.BaseThread)
self.request_arrived.wait() self.request_arrived.wait()
self.raise_zombie() self.raise_zombie()
first_line_format, method, scheme, host, port, path = http2.parse_headers(self.request_headers) first_line_format, method, scheme, host, port, path = http2.parse_headers(self.request_headers)
return models.HTTPRequest( return http.HTTPRequest(
first_line_format, first_line_format,
method, method,
scheme, scheme,
@ -547,7 +547,7 @@ class Http2SingleStreamLayer(http._HttpTransmissionLayer, basethread.BaseThread)
headers = self.response_headers.copy() headers = self.response_headers.copy()
headers.pop(":status", None) headers.pop(":status", None)
return models.HTTPResponse( return http.HTTPResponse(
http_version=b"HTTP/2.0", http_version=b"HTTP/2.0",
status_code=status_code, status_code=status_code,
reason=b'', reason=b'',
@ -597,7 +597,7 @@ class Http2SingleStreamLayer(http._HttpTransmissionLayer, basethread.BaseThread)
raise EnvironmentError('Http2SingleStreamLayer must be run as thread') raise EnvironmentError('Http2SingleStreamLayer must be run as thread')
def run(self): def run(self):
layer = http.HttpLayer(self, self.mode) layer = httpbase.HttpLayer(self, self.mode)
try: try:
layer() layer()

View File

@ -1,9 +1,12 @@
import traceback import traceback
import netlib.exceptions import netlib.exceptions
from mitmproxy import log
from mitmproxy import controller from mitmproxy import controller
from mitmproxy import exceptions from mitmproxy import exceptions
from mitmproxy import models from mitmproxy import http
from mitmproxy import flow
from mitmproxy import connections
from netlib.http import http1 from netlib.http import http1
from netlib import basethread from netlib import basethread
@ -14,42 +17,42 @@ from netlib import basethread
class RequestReplayThread(basethread.BaseThread): class RequestReplayThread(basethread.BaseThread):
name = "RequestReplayThread" name = "RequestReplayThread"
def __init__(self, config, flow, event_queue, should_exit): def __init__(self, config, f, event_queue, should_exit):
""" """
event_queue can be a queue or None, if no scripthooks should be event_queue can be a queue or None, if no scripthooks should be
processed. processed.
""" """
self.config, self.flow = config, flow self.config, self.f = config, f
flow.live = True f.live = True
if event_queue: if event_queue:
self.channel = controller.Channel(event_queue, should_exit) self.channel = controller.Channel(event_queue, should_exit)
else: else:
self.channel = None self.channel = None
super().__init__( super().__init__(
"RequestReplay (%s)" % flow.request.url "RequestReplay (%s)" % f.request.url
) )
def run(self): def run(self):
r = self.flow.request r = self.f.request
first_line_format_backup = r.first_line_format first_line_format_backup = r.first_line_format
server = None server = None
try: try:
self.flow.response = None self.f.response = None
# If we have a channel, run script hooks. # If we have a channel, run script hooks.
if self.channel: if self.channel:
request_reply = self.channel.ask("request", self.flow) request_reply = self.channel.ask("request", self.f)
if isinstance(request_reply, models.HTTPResponse): if isinstance(request_reply, http.HTTPResponse):
self.flow.response = request_reply self.f.response = request_reply
if not self.flow.response: if not self.f.response:
# In all modes, we directly connect to the server displayed # In all modes, we directly connect to the server displayed
if self.config.options.mode == "upstream": if self.config.options.mode == "upstream":
server_address = self.config.upstream_server.address server_address = self.config.upstream_server.address
server = models.ServerConnection(server_address, (self.config.options.listen_host, 0)) server = connections.ServerConnection(server_address, (self.config.options.listen_host, 0))
server.connect() server.connect()
if r.scheme == "https": if r.scheme == "https":
connect_request = models.make_connect_request((r.data.host, r.port)) connect_request = http.make_connect_request((r.data.host, r.port))
server.wfile.write(http1.assemble_request(connect_request)) server.wfile.write(http1.assemble_request(connect_request))
server.wfile.flush() server.wfile.flush()
resp = http1.read_response( resp = http1.read_response(
@ -61,46 +64,57 @@ class RequestReplayThread(basethread.BaseThread):
raise exceptions.ReplayException("Upstream server refuses CONNECT request") raise exceptions.ReplayException("Upstream server refuses CONNECT request")
server.establish_ssl( server.establish_ssl(
self.config.clientcerts, self.config.clientcerts,
sni=self.flow.server_conn.sni sni=self.f.server_conn.sni
) )
r.first_line_format = "relative" r.first_line_format = "relative"
else: else:
r.first_line_format = "absolute" r.first_line_format = "absolute"
else: else:
server_address = (r.host, r.port) server_address = (r.host, r.port)
server = models.ServerConnection(server_address, (self.config.options.listen_host, 0)) server = connections.ServerConnection(
server_address,
(self.config.options.listen_host, 0)
)
server.connect() server.connect()
if r.scheme == "https": if r.scheme == "https":
server.establish_ssl( server.establish_ssl(
self.config.clientcerts, self.config.clientcerts,
sni=self.flow.server_conn.sni sni=self.f.server_conn.sni
) )
r.first_line_format = "relative" r.first_line_format = "relative"
server.wfile.write(http1.assemble_request(r)) server.wfile.write(http1.assemble_request(r))
server.wfile.flush() server.wfile.flush()
self.flow.server_conn = server self.f.server_conn = server
self.flow.response = models.HTTPResponse.wrap(http1.read_response( self.f.response = http.HTTPResponse.wrap(
http1.read_response(
server.rfile, server.rfile,
r, r,
body_size_limit=self.config.options.body_size_limit body_size_limit=self.config.options.body_size_limit
)) )
)
if self.channel: if self.channel:
response_reply = self.channel.ask("response", self.flow) response_reply = self.channel.ask("response", self.f)
if response_reply == exceptions.Kill: if response_reply == exceptions.Kill:
raise exceptions.Kill() raise exceptions.Kill()
except (exceptions.ReplayException, netlib.exceptions.NetlibException) as e: except (exceptions.ReplayException, netlib.exceptions.NetlibException) as e:
self.flow.error = models.Error(str(e)) self.f.error = flow.Error(str(e))
if self.channel: if self.channel:
self.channel.ask("error", self.flow) self.channel.ask("error", self.f)
except exceptions.Kill: except exceptions.Kill:
# Kill should only be raised if there's a channel in the # Kill should only be raised if there's a channel in the
# first place. # first place.
self.channel.tell("log", controller.LogEntry("Connection killed", "info")) self.channel.tell(
"log",
log.LogEntry("Connection killed", "info")
)
except Exception: except Exception:
self.channel.tell("log", controller.LogEntry(traceback.format_exc(), "error")) self.channel.tell(
"log",
log.LogEntry(traceback.format_exc(), "error")
)
finally: finally:
r.first_line_format = first_line_format_backup r.first_line_format = first_line_format_backup
self.flow.live = False self.f.live = False
if server: if server:
server.finish() server.finish()

View File

@ -4,8 +4,8 @@ from OpenSSL import SSL
import netlib.exceptions import netlib.exceptions
import netlib.tcp import netlib.tcp
from mitmproxy import models from mitmproxy import tcp
from mitmproxy.models import tcp from mitmproxy import flow
from mitmproxy.protocol import base from mitmproxy.protocol import base
@ -20,8 +20,8 @@ class RawTCPLayer(base.Layer):
self.connect() self.connect()
if not self.ignore: if not self.ignore:
flow = models.TCPFlow(self.client_conn, self.server_conn, self) f = tcp.TCPFlow(self.client_conn, self.server_conn, self)
self.channel.ask("tcp_start", flow) self.channel.ask("tcp_start", f)
buf = memoryview(bytearray(self.chunk_size)) buf = memoryview(bytearray(self.chunk_size))
@ -52,14 +52,14 @@ class RawTCPLayer(base.Layer):
tcp_message = tcp.TCPMessage(dst == server, buf[:size].tobytes()) tcp_message = tcp.TCPMessage(dst == server, buf[:size].tobytes())
if not self.ignore: if not self.ignore:
flow.messages.append(tcp_message) f.messages.append(tcp_message)
self.channel.ask("tcp_message", flow) self.channel.ask("tcp_message", f)
dst.sendall(tcp_message.content) dst.sendall(tcp_message.content)
except (socket.error, netlib.exceptions.TcpException, SSL.Error) as e: except (socket.error, netlib.exceptions.TcpException, SSL.Error) as e:
if not self.ignore: if not self.ignore:
flow.error = models.Error("TCP connection closed unexpectedly: {}".format(repr(e))) f.error = flow.Error("TCP connection closed unexpectedly: {}".format(repr(e)))
self.channel.tell("tcp_error", flow) self.channel.tell("tcp_error", f)
finally: finally:
if not self.ignore: if not self.ignore:
self.channel.tell("tcp_end", flow) self.channel.tell("tcp_end", f)

View File

@ -224,7 +224,7 @@ def get_client_hello(client_conn):
Peek into the socket and read all records that contain the initial client hello message. Peek into the socket and read all records that contain the initial client hello message.
client_conn: client_conn:
The :py:class:`client connection <mitmproxy.models.ClientConnection>`. The :py:class:`client connection <mitmproxy.connections.ClientConnection>`.
Returns: Returns:
The raw handshake packet bytes, without TLS record header(s). The raw handshake packet bytes, without TLS record header(s).
@ -281,7 +281,7 @@ class TlsClientHello:
""" """
Peek into the connection, read the initial client hello and parse it to obtain ALPN values. Peek into the connection, read the initial client hello and parse it to obtain ALPN values.
client_conn: client_conn:
The :py:class:`client connection <mitmproxy.models.ClientConnection>`. The :py:class:`client connection <mitmproxy.connections.ClientConnection>`.
Returns: Returns:
:py:class:`client hello <mitmproxy.protocol.tls.TlsClientHello>`. :py:class:`client hello <mitmproxy.protocol.tls.TlsClientHello>`.
""" """

View File

@ -13,7 +13,7 @@ class RootContext:
Attributes: Attributes:
client_conn: client_conn:
The :py:class:`client connection <mitmproxy.models.ClientConnection>`. The :py:class:`client connection <mitmproxy.connections.ClientConnection>`.
channel: channel:
A :py:class:`~mitmproxy.controller.Channel` to communicate with the FlowMaster. A :py:class:`~mitmproxy.controller.Channel` to communicate with the FlowMaster.
Provides :py:meth:`.ask() <mitmproxy.controller.Channel.ask>` and Provides :py:meth:`.ask() <mitmproxy.controller.Channel.ask>` and

View File

@ -4,7 +4,8 @@ import traceback
import netlib.exceptions import netlib.exceptions
from mitmproxy import exceptions from mitmproxy import exceptions
from mitmproxy import models from mitmproxy import connections
from mitmproxy import http
from mitmproxy import log from mitmproxy import log
from mitmproxy.proxy import modes from mitmproxy.proxy import modes
from mitmproxy.proxy import root_context from mitmproxy.proxy import root_context
@ -66,7 +67,7 @@ class ConnectionHandler:
def __init__(self, client_conn, client_address, config, channel): def __init__(self, client_conn, client_address, config, channel):
self.config = config self.config = config
"""@type: mitmproxy.proxy.config.ProxyConfig""" """@type: mitmproxy.proxy.config.ProxyConfig"""
self.client_conn = models.ClientConnection( self.client_conn = connections.ClientConnection(
client_conn, client_conn,
client_address, client_address,
None) None)
@ -135,7 +136,7 @@ class ConnectionHandler:
# we send an HTTP error response, which is both # we send an HTTP error response, which is both
# understandable by HTTP clients and humans. # understandable by HTTP clients and humans.
try: try:
error_response = models.make_error_response(502, repr(e)) error_response = http.make_error_response(502, repr(e))
self.client_conn.send(http1.assemble_response(error_response)) self.client_conn.send(http1.assemble_response(error_response))
except netlib.exceptions.TcpException: except netlib.exceptions.TcpException:
pass pass

View File

@ -3,7 +3,7 @@ import time
from typing import List from typing import List
import netlib.basetypes import netlib.basetypes
from mitmproxy.models.flow import Flow from mitmproxy import flow
class TCPMessage(netlib.basetypes.Serializable): class TCPMessage(netlib.basetypes.Serializable):
@ -34,7 +34,7 @@ class TCPMessage(netlib.basetypes.Serializable):
) )
class TCPFlow(Flow): class TCPFlow(flow.Flow):
""" """
A TCPFlow is a simplified representation of a TCP session. A TCPFlow is a simplified representation of a TCP session.
@ -44,7 +44,7 @@ class TCPFlow(Flow):
super().__init__("tcp", client_conn, server_conn, live) super().__init__("tcp", client_conn, server_conn, live)
self.messages = [] # type: List[TCPMessage] self.messages = [] # type: List[TCPMessage]
_stateobject_attributes = Flow._stateobject_attributes.copy() _stateobject_attributes = flow.Flow._stateobject_attributes.copy()
_stateobject_attributes.update( _stateobject_attributes.update(
messages=List[TCPMessage] messages=List[TCPMessage]
) )

View File

View File

@ -750,7 +750,7 @@ def common_options(parser):
def mitmproxy(): def mitmproxy():
# Don't import mitmproxy.console for mitmdump, urwid is not available on all # Don't import mitmproxy.tools.console for mitmdump, urwid is not available on all
# platforms. # platforms.
from .console import palettes from .console import palettes

View File

@ -0,0 +1,4 @@
from mitmproxy.tools.console import master
__all__ = ["master"]

View File

@ -8,7 +8,7 @@ import urwid.util
import netlib import netlib
from mitmproxy import utils from mitmproxy import utils
from mitmproxy.console import signals from mitmproxy.tools.console import signals
from mitmproxy import export from mitmproxy import export
from netlib import human from netlib import human

View File

@ -1,6 +1,6 @@
import urwid import urwid
from mitmproxy.console import common, searchable from mitmproxy.tools.console import common, searchable
from netlib import human from netlib import human

View File

@ -2,8 +2,8 @@ import urwid
import netlib.http.url import netlib.http.url
from mitmproxy import exceptions from mitmproxy import exceptions
from mitmproxy.console import common from mitmproxy.tools.console import common
from mitmproxy.console import signals from mitmproxy.tools.console import signals
from mitmproxy import export from mitmproxy import export

View File

@ -7,14 +7,14 @@ from mitmproxy import exceptions
from typing import Optional, Union # noqa from typing import Optional, Union # noqa
from mitmproxy import contentviews from mitmproxy import contentviews
from mitmproxy import models from mitmproxy import http
from mitmproxy import utils from mitmproxy import utils
from mitmproxy.console import common from mitmproxy.tools.console import common
from mitmproxy.console import flowdetailview from mitmproxy.tools.console import flowdetailview
from mitmproxy.console import grideditor from mitmproxy.tools.console import grideditor
from mitmproxy.console import searchable from mitmproxy.tools.console import searchable
from mitmproxy.console import signals from mitmproxy.tools.console import signals
from mitmproxy.console import tabs from mitmproxy.tools.console import tabs
from mitmproxy import export from mitmproxy import export
from netlib.http import Headers from netlib.http import Headers
from netlib.http import status_codes from netlib.http import status_codes
@ -100,7 +100,7 @@ footer = [
class FlowViewHeader(urwid.WidgetWrap): class FlowViewHeader(urwid.WidgetWrap):
def __init__(self, master: "mitmproxy.console.master.ConsoleMaster", f: models.HTTPFlow): def __init__(self, master: "mitmproxy.console.master.ConsoleMaster", f: http.HTTPFlow):
self.master = master self.master = master
self.flow = f self.flow = f
self._w = common.format_flow( self._w = common.format_flow(
@ -208,7 +208,7 @@ class FlowView(tabs.Tabs):
if error: if error:
signals.add_log(error, "error") signals.add_log(error, "error")
# Give hint that you have to tab for the response. # Give hint that you have to tab for the response.
if description == "No content" and isinstance(message, models.HTTPRequest): if description == "No content" and isinstance(message, http.HTTPRequest):
description = "No request content (press tab to view response)" description = "No request content (press tab to view response)"
# If the users has a wide terminal, he gets fewer lines; this should not be an issue. # If the users has a wide terminal, he gets fewer lines; this should not be an issue.
@ -373,7 +373,7 @@ class FlowView(tabs.Tabs):
message = self.flow.request message = self.flow.request
else: else:
if not self.flow.response: if not self.flow.response:
self.flow.response = models.HTTPResponse.make(200, b"") self.flow.response = http.HTTPResponse.make(200, b"")
message = self.flow.response message = self.flow.response
self.flow.backup() self.flow.backup()
@ -500,7 +500,7 @@ class FlowView(tabs.Tabs):
signals.flow_change.send(self, flow = self.flow) signals.flow_change.send(self, flow = self.flow)
def keypress(self, size, key): def keypress(self, size, key):
conn = None # type: Optional[Union[models.HTTPRequest, models.HTTPResponse]] conn = None # type: Optional[Union[http.HTTPRequest, http.HTTPResponse]]
if self.tab_offset == TAB_REQ: if self.tab_offset == TAB_REQ:
conn = self.flow.request conn = self.flow.request
elif self.tab_offset == TAB_RESP: elif self.tab_offset == TAB_RESP:

View File

@ -9,8 +9,8 @@ from typing import Sequence
from typing import Tuple from typing import Tuple
import urwid import urwid
from mitmproxy.console import common from mitmproxy.tools.console import common
from mitmproxy.console import signals from mitmproxy.tools.console import signals
FOOTER = [ FOOTER = [
('heading_key', "enter"), ":edit ", ('heading_key', "enter"), ":edit ",

View File

@ -2,8 +2,8 @@ import os
from typing import Callable, Optional from typing import Callable, Optional
import urwid import urwid
from mitmproxy.console import signals from mitmproxy.tools.console import signals
from mitmproxy.console.grideditor import base from mitmproxy.tools.console.grideditor import base
from netlib import strutils from netlib import strutils

View File

@ -1,6 +1,6 @@
import urwid import urwid
from mitmproxy.console.grideditor import base from mitmproxy.tools.console.grideditor import base
from mitmproxy.console import signals from mitmproxy.tools.console import signals
from netlib.http import cookies from netlib.http import cookies

View File

@ -5,8 +5,8 @@ In a nutshell, text columns are actually a proxy class for byte columns,
which just encode/decodes contents. which just encode/decodes contents.
""" """
from mitmproxy.console import signals from mitmproxy.tools.console import signals
from mitmproxy.console.grideditor import col_bytes from mitmproxy.tools.console.grideditor import col_bytes
class Column(col_bytes.Column): class Column(col_bytes.Column):

View File

@ -3,12 +3,12 @@ import urwid
from mitmproxy import exceptions from mitmproxy import exceptions
from mitmproxy import flowfilter from mitmproxy import flowfilter
from mitmproxy.addons import script from mitmproxy.addons import script
from mitmproxy.console import common from mitmproxy.tools.console import common
from mitmproxy.console.grideditor import base from mitmproxy.tools.console.grideditor import base
from mitmproxy.console.grideditor import col_bytes from mitmproxy.tools.console.grideditor import col_bytes
from mitmproxy.console.grideditor import col_text from mitmproxy.tools.console.grideditor import col_text
from mitmproxy.console.grideditor import col_subgrid from mitmproxy.tools.console.grideditor import col_subgrid
from mitmproxy.console import signals from mitmproxy.tools.console import signals
from netlib.http import user_agents from netlib.http import user_agents

View File

@ -3,8 +3,8 @@ import platform
import urwid import urwid
from mitmproxy import flowfilter from mitmproxy import flowfilter
from mitmproxy.console import common from mitmproxy.tools.console import common
from mitmproxy.console import signals from mitmproxy.tools.console import signals
from netlib import version from netlib import version

View File

@ -24,16 +24,16 @@ from mitmproxy import flowfilter
from mitmproxy import utils from mitmproxy import utils
from mitmproxy.addons import state from mitmproxy.addons import state
import mitmproxy.options import mitmproxy.options
from mitmproxy.console import flowlist from mitmproxy.tools.console import flowlist
from mitmproxy.console import flowview from mitmproxy.tools.console import flowview
from mitmproxy.console import grideditor from mitmproxy.tools.console import grideditor
from mitmproxy.console import help from mitmproxy.tools.console import help
from mitmproxy.console import options from mitmproxy.tools.console import options
from mitmproxy.console import palettepicker from mitmproxy.tools.console import palettepicker
from mitmproxy.console import palettes from mitmproxy.tools.console import palettes
from mitmproxy.console import signals from mitmproxy.tools.console import signals
from mitmproxy.console import statusbar from mitmproxy.tools.console import statusbar
from mitmproxy.console import window from mitmproxy.tools.console import window
from mitmproxy.flowfilter import FMarked from mitmproxy.flowfilter import FMarked
from netlib import tcp, strutils from netlib import tcp, strutils

View File

@ -1,11 +1,11 @@
import urwid import urwid
from mitmproxy import contentviews from mitmproxy import contentviews
from mitmproxy.console import common from mitmproxy.tools.console import common
from mitmproxy.console import grideditor from mitmproxy.tools.console import grideditor
from mitmproxy.console import palettes from mitmproxy.tools.console import palettes
from mitmproxy.console import select from mitmproxy.tools.console import select
from mitmproxy.console import signals from mitmproxy.tools.console import signals
footer = [ footer = [
('heading_key', "enter/space"), ":toggle ", ('heading_key', "enter/space"), ":toggle ",

View File

@ -1,9 +1,9 @@
import urwid import urwid
from mitmproxy.console import common from mitmproxy.tools.console import common
from mitmproxy.console import palettes from mitmproxy.tools.console import palettes
from mitmproxy.console import select from mitmproxy.tools.console import select
from mitmproxy.console import signals from mitmproxy.tools.console import signals
footer = [ footer = [
('heading_key', "enter/space"), ":select", ('heading_key', "enter/space"), ":select",

View File

@ -1,6 +1,6 @@
import urwid import urwid
from mitmproxy.console import signals from mitmproxy.tools.console import signals
class Highlight(urwid.AttrMap): class Highlight(urwid.AttrMap):

View File

@ -1,6 +1,6 @@
import urwid import urwid
from mitmproxy.console import common from mitmproxy.tools.console import common
class _OptionWidget(urwid.WidgetWrap): class _OptionWidget(urwid.WidgetWrap):

View File

@ -3,9 +3,9 @@ import os.path
import urwid import urwid
import netlib.http.url import netlib.http.url
from mitmproxy.console import common from mitmproxy.tools.console import common
from mitmproxy.console import pathedit from mitmproxy.tools.console import pathedit
from mitmproxy.console import signals from mitmproxy.tools.console import signals
from netlib import human from netlib import human

View File

@ -1,6 +1,6 @@
import urwid import urwid
from mitmproxy.console import signals from mitmproxy.tools.console import signals
class Window(urwid.Frame): class Window(urwid.Frame):

View File

@ -2,7 +2,7 @@ import os
import signal import signal
import sys import sys
from mitmproxy import cmdline from mitmproxy.tools import cmdline
from mitmproxy import exceptions from mitmproxy import exceptions
from mitmproxy.proxy import config from mitmproxy.proxy import config
from mitmproxy.proxy import server from mitmproxy.proxy import server
@ -47,7 +47,7 @@ def mitmproxy(args=None): # pragma: no cover
print("Error: mitmproxy's console interface is not supported on Windows. " print("Error: mitmproxy's console interface is not supported on Windows. "
"You can run mitmdump or mitmweb instead.", file=sys.stderr) "You can run mitmdump or mitmweb instead.", file=sys.stderr)
sys.exit(1) sys.exit(1)
from . import console from mitmproxy.tools import console
version_check.check_pyopenssl_version() version_check.check_pyopenssl_version()
assert_utf8_env() assert_utf8_env()
@ -79,7 +79,7 @@ def mitmproxy(args=None): # pragma: no cover
def mitmdump(args=None): # pragma: no cover def mitmdump(args=None): # pragma: no cover
from . import dump from mitmproxy.tools import dump
version_check.check_pyopenssl_version() version_check.check_pyopenssl_version()
@ -113,7 +113,7 @@ def mitmdump(args=None): # pragma: no cover
def mitmweb(args=None): # pragma: no cover def mitmweb(args=None): # pragma: no cover
from . import web from mitmproxy.tools import web
version_check.check_pyopenssl_version() version_check.check_pyopenssl_version()

View File

@ -0,0 +1,2 @@
from mitmproxy.tools.web import master
__all__ = ["master"]

View File

@ -11,13 +11,14 @@ import tornado.web
from io import BytesIO from io import BytesIO
from mitmproxy import flowfilter from mitmproxy import flowfilter
from mitmproxy import models from mitmproxy import flow
from mitmproxy import http
from mitmproxy import contentviews from mitmproxy import contentviews
from mitmproxy import io from mitmproxy import io
from netlib import version from netlib import version
def convert_flow_to_json_dict(flow: models.Flow) -> dict: def convert_flow_to_json_dict(flow: flow.Flow) -> dict:
""" """
Remove flow message content and cert to save transmission space. Remove flow message content and cert to save transmission space.
@ -34,7 +35,7 @@ def convert_flow_to_json_dict(flow: models.Flow) -> dict:
if flow.error: if flow.error:
f["error"] = flow.error.get_state() f["error"] = flow.error.get_state()
if isinstance(flow, models.HTTPFlow): if isinstance(flow, http.HTTPFlow):
if flow.request: if flow.request:
f["request"] = { f["request"] = {
"method": flow.request.method, "method": flow.request.method,
@ -119,7 +120,7 @@ class RequestHandler(BasicAuth, tornado.web.RequestHandler):
return self.application.master.state return self.application.master.state
@property @property
def master(self) -> "mitmproxy.web.master.WebMaster": def master(self) -> "mitmproxy.tools.web.master.WebMaster":
return self.application.master return self.application.master
@property @property

View File

@ -12,7 +12,7 @@ from mitmproxy import exceptions
from mitmproxy.addons import state from mitmproxy.addons import state
from mitmproxy import options from mitmproxy import options
from mitmproxy import master from mitmproxy import master
from mitmproxy.web import app from mitmproxy.tools.web import app
from netlib.http import authentication from netlib.http import authentication

View File

Before

Width:  |  Height:  |  Size: 280 KiB

After

Width:  |  Height:  |  Size: 280 KiB

View File

Before

Width:  |  Height:  |  Size: 1005 B

After

Width:  |  Height:  |  Size: 1005 B

View File

Before

Width:  |  Height:  |  Size: 787 B

After

Width:  |  Height:  |  Size: 787 B

View File

Before

Width:  |  Height:  |  Size: 357 KiB

After

Width:  |  Height:  |  Size: 357 KiB

View File

Before

Width:  |  Height:  |  Size: 853 B

After

Width:  |  Height:  |  Size: 853 B

View File

Before

Width:  |  Height:  |  Size: 921 B

After

Width:  |  Height:  |  Size: 921 B

View File

Before

Width:  |  Height:  |  Size: 976 B

After

Width:  |  Height:  |  Size: 976 B

View File

Before

Width:  |  Height:  |  Size: 861 B

After

Width:  |  Height:  |  Size: 861 B

View File

Before

Width:  |  Height:  |  Size: 1.0 KiB

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -1,2 +0,0 @@
from mitmproxy.web import master
__all__ = ["master"]

View File

@ -49,9 +49,9 @@ setup(
include_package_data=True, include_package_data=True,
entry_points={ entry_points={
'console_scripts': [ 'console_scripts': [
"mitmproxy = mitmproxy.main:mitmproxy", "mitmproxy = mitmproxy.tools.main:mitmproxy",
"mitmdump = mitmproxy.main:mitmdump", "mitmdump = mitmproxy.tools.main:mitmdump",
"mitmweb = mitmproxy.main:mitmweb", "mitmweb = mitmproxy.tools.main:mitmweb",
"pathod = pathod.pathod_cmdline:go_pathod", "pathod = pathod.pathod_cmdline:go_pathod",
"pathoc = pathod.pathoc_cmdline:go_pathoc" "pathoc = pathod.pathoc_cmdline:go_pathoc"
] ]

View File

@ -4,8 +4,8 @@ from .. import tutils, mastertest
from mitmproxy.addons import dumper from mitmproxy.addons import dumper
from mitmproxy import exceptions from mitmproxy import exceptions
from mitmproxy import dump from mitmproxy.tools import dump
from mitmproxy import models from mitmproxy import http
from mitmproxy import proxy from mitmproxy import proxy
import netlib.tutils import netlib.tutils
import mock import mock
@ -60,7 +60,7 @@ class TestDumper(mastertest.MasterTest):
d.configure(dump.Options(tfile = sio), updated) d.configure(dump.Options(tfile = sio), updated)
flow = tutils.tflow() flow = tutils.tflow()
flow.request.content = None flow.request.content = None
flow.response = models.HTTPResponse.wrap(netlib.tutils.tresp()) flow.response = http.HTTPResponse.wrap(netlib.tutils.tresp())
flow.response.content = None flow.response.content = None
d.response(flow) d.response(flow)
assert "content missing" in sio.getvalue() assert "content missing" in sio.getvalue()

View File

@ -3,7 +3,7 @@ import io
from mitmproxy.addons import termlog from mitmproxy.addons import termlog
from mitmproxy import log from mitmproxy import log
from mitmproxy import dump from mitmproxy.tools import dump
class TestTermLog(mastertest.MasterTest): class TestTermLog(mastertest.MasterTest):

View File

@ -1,4 +1,4 @@
import mitmproxy.console.common as common from mitmproxy.tools.console import common
from .. import tutils from .. import tutils

View File

@ -1,4 +1,4 @@
import mitmproxy.console.help as help import mitmproxy.tools.console.help as help
from .. import tutils from .. import tutils

View File

@ -1,9 +1,9 @@
import gc import gc
import netlib.tutils import netlib.tutils
from mitmproxy import console from mitmproxy.tools import console
from mitmproxy import proxy from mitmproxy import proxy
from mitmproxy.console import common from mitmproxy.tools.console import common
from .. import tutils, mastertest from .. import tutils, mastertest

View File

@ -1,4 +1,4 @@
import mitmproxy.console.palettes as palettes import mitmproxy.tools.console.palettes as palettes
from .. import tutils from .. import tutils

View File

@ -1,6 +1,6 @@
import os import os
from os.path import normpath from os.path import normpath
from mitmproxy.console import pathedit from mitmproxy.tools.console import pathedit
from mock import patch from mock import patch

View File

@ -4,7 +4,10 @@ from . import tutils
import netlib.tutils import netlib.tutils
from mitmproxy import master from mitmproxy import master
from mitmproxy import io, proxy, models, options from mitmproxy import io
from mitmproxy import proxy
from mitmproxy import http
from mitmproxy import options
class TestMaster: class TestMaster:
@ -19,7 +22,7 @@ class MasterTest:
master.serverconnect(f.server_conn) master.serverconnect(f.server_conn)
master.request(f) master.request(f)
if not f.error: if not f.error:
f.response = models.HTTPResponse.wrap( f.response = http.HTTPResponse.wrap(
netlib.tutils.tresp(content=content) netlib.tutils.tresp(content=content)
) )
master.response(f) master.response(f)

View File

@ -1,5 +1,5 @@
import argparse import argparse
from mitmproxy import cmdline from mitmproxy.tools import cmdline
from . import tutils from . import tutils

View File

@ -2,7 +2,9 @@ import os
import io import io
import mitmproxy.io import mitmproxy.io
from mitmproxy import dump, exceptions, proxy from mitmproxy.tools import dump
from mitmproxy import exceptions
from mitmproxy import proxy
from . import tutils, mastertest from . import tutils, mastertest

View File

@ -8,14 +8,11 @@ from mitmproxy import flowfilter, options
from mitmproxy.addons import state from mitmproxy.addons import state
from mitmproxy.contrib import tnetstring from mitmproxy.contrib import tnetstring
from mitmproxy.exceptions import FlowReadException, Kill from mitmproxy.exceptions import FlowReadException, Kill
from mitmproxy.models import Error from mitmproxy import flow
from mitmproxy.models import Flow from mitmproxy import http
from mitmproxy.models import HTTPFlow from mitmproxy import connections
from mitmproxy.models import HTTPRequest
from mitmproxy.models import HTTPResponse
from mitmproxy.proxy import ProxyConfig from mitmproxy.proxy import ProxyConfig
from mitmproxy.proxy.server import DummyServer from mitmproxy.proxy.server import DummyServer
from mitmproxy.models.connections import ClientConnection
from mitmproxy import master from mitmproxy import master
from . import tutils from . import tutils
@ -62,7 +59,7 @@ class TestHTTPFlow:
def test_backup(self): def test_backup(self):
f = tutils.tflow() f = tutils.tflow()
f.response = HTTPResponse.wrap(netlib.tutils.tresp()) f.response = http.HTTPResponse.wrap(netlib.tutils.tresp())
f.request.content = b"foo" f.request.content = b"foo"
assert not f.modified() assert not f.modified()
f.backup() f.backup()
@ -81,20 +78,20 @@ class TestHTTPFlow:
def test_getset_state(self): def test_getset_state(self):
f = tutils.tflow(resp=True) f = tutils.tflow(resp=True)
state = f.get_state() state = f.get_state()
assert f.get_state() == HTTPFlow.from_state( assert f.get_state() == http.HTTPFlow.from_state(
state).get_state() state).get_state()
f.response = None f.response = None
f.error = Error("error") f.error = flow.Error("error")
state = f.get_state() state = f.get_state()
assert f.get_state() == HTTPFlow.from_state( assert f.get_state() == http.HTTPFlow.from_state(
state).get_state() state).get_state()
f2 = f.copy() f2 = f.copy()
f2.id = f.id # copy creates a different uuid f2.id = f.id # copy creates a different uuid
assert f.get_state() == f2.get_state() assert f.get_state() == f2.get_state()
assert not f == f2 assert not f == f2
f2.error = Error("e2") f2.error = flow.Error("e2")
assert not f == f2 assert not f == f2
f.set_state(f2.get_state()) f.set_state(f2.get_state())
assert f.get_state() == f2.get_state() assert f.get_state() == f2.get_state()
@ -215,7 +212,7 @@ class TestState:
assert c.add_flow(newf) assert c.add_flow(newf)
assert c.active_flow_count() == 2 assert c.active_flow_count() == 2
f.response = HTTPResponse.wrap(netlib.tutils.tresp()) f.response = http.HTTPResponse.wrap(netlib.tutils.tresp())
assert c.update_flow(f) assert c.update_flow(f)
assert c.flow_count() == 2 assert c.flow_count() == 2
assert c.active_flow_count() == 1 assert c.active_flow_count() == 1
@ -223,7 +220,7 @@ class TestState:
assert not c.update_flow(None) assert not c.update_flow(None)
assert c.active_flow_count() == 1 assert c.active_flow_count() == 1
newf.response = HTTPResponse.wrap(netlib.tutils.tresp()) newf.response = http.HTTPResponse.wrap(netlib.tutils.tresp())
assert c.update_flow(newf) assert c.update_flow(newf)
assert c.active_flow_count() == 0 assert c.active_flow_count() == 0
@ -231,7 +228,7 @@ class TestState:
c = state.State() c = state.State()
f = tutils.tflow() f = tutils.tflow()
c.add_flow(f) c.add_flow(f)
f.error = Error("message") f.error = flow.Error("message")
assert c.update_flow(f) assert c.update_flow(f)
c = state.State() c = state.State()
@ -255,7 +252,7 @@ class TestState:
c.set_view_filter("~s") c.set_view_filter("~s")
assert c.filter_txt == "~s" assert c.filter_txt == "~s"
assert len(c.view) == 0 assert len(c.view) == 0
f.response = HTTPResponse.wrap(netlib.tutils.tresp()) f.response = http.HTTPResponse.wrap(netlib.tutils.tresp())
c.update_flow(f) c.update_flow(f)
assert len(c.view) == 1 assert len(c.view) == 1
c.set_view_filter(None) c.set_view_filter(None)
@ -287,7 +284,7 @@ class TestState:
def _add_response(self, state): def _add_response(self, state):
f = tutils.tflow() f = tutils.tflow()
state.add_flow(f) state.add_flow(f)
f.response = HTTPResponse.wrap(netlib.tutils.tresp()) f.response = http.HTTPResponse.wrap(netlib.tutils.tresp())
state.update_flow(f) state.update_flow(f)
def _add_error(self, state): def _add_error(self, state):
@ -316,7 +313,7 @@ class TestState:
c.clear() c.clear()
c.load_flows(flows) c.load_flows(flows)
assert isinstance(c.flows[0], Flow) assert isinstance(c.flows[0], flow.Flow)
def test_accept_all(self): def test_accept_all(self):
c = state.State() c = state.State()
@ -447,17 +444,17 @@ class TestFlowMaster:
fm.addons.add(s) fm.addons.add(s)
f = tutils.tflow(req=None) f = tutils.tflow(req=None)
fm.clientconnect(f.client_conn) fm.clientconnect(f.client_conn)
f.request = HTTPRequest.wrap(netlib.tutils.treq()) f.request = http.HTTPRequest.wrap(netlib.tutils.treq())
fm.request(f) fm.request(f)
assert s.flow_count() == 1 assert s.flow_count() == 1
f.response = HTTPResponse.wrap(netlib.tutils.tresp()) f.response = http.HTTPResponse.wrap(netlib.tutils.tresp())
fm.response(f) fm.response(f)
assert s.flow_count() == 1 assert s.flow_count() == 1
fm.clientdisconnect(f.client_conn) fm.clientdisconnect(f.client_conn)
f.error = Error("msg") f.error = flow.Error("msg")
fm.error(f) fm.error(f)
fm.shutdown() fm.shutdown()
@ -476,7 +473,7 @@ class TestRequest:
assert r.get_state() == r2.get_state() assert r.get_state() == r2.get_state()
def test_get_url(self): def test_get_url(self):
r = HTTPRequest.wrap(netlib.tutils.treq()) r = http.HTTPRequest.wrap(netlib.tutils.treq())
assert r.url == "http://address:22/path" assert r.url == "http://address:22/path"
@ -497,7 +494,7 @@ class TestRequest:
assert r.pretty_url == "https://foo.com:22/path" assert r.pretty_url == "https://foo.com:22/path"
def test_replace(self): def test_replace(self):
r = HTTPRequest.wrap(netlib.tutils.treq()) r = http.HTTPRequest.wrap(netlib.tutils.treq())
r.path = "path/foo" r.path = "path/foo"
r.headers["Foo"] = "fOo" r.headers["Foo"] = "fOo"
r.content = b"afoob" r.content = b"afoob"
@ -507,7 +504,7 @@ class TestRequest:
assert r.headers["boo"] == "boo" assert r.headers["boo"] == "boo"
def test_constrain_encoding(self): def test_constrain_encoding(self):
r = HTTPRequest.wrap(netlib.tutils.treq()) r = http.HTTPRequest.wrap(netlib.tutils.treq())
r.headers["accept-encoding"] = "gzip, oink" r.headers["accept-encoding"] = "gzip, oink"
r.constrain_encoding() r.constrain_encoding()
assert "oink" not in r.headers["accept-encoding"] assert "oink" not in r.headers["accept-encoding"]
@ -517,7 +514,7 @@ class TestRequest:
assert "oink" not in r.headers["accept-encoding"] assert "oink" not in r.headers["accept-encoding"]
def test_get_content_type(self): def test_get_content_type(self):
resp = HTTPResponse.wrap(netlib.tutils.tresp()) resp = http.HTTPResponse.wrap(netlib.tutils.tresp())
resp.headers = Headers(content_type="text/plain") resp.headers = Headers(content_type="text/plain")
assert resp.headers["content-type"] == "text/plain" assert resp.headers["content-type"] == "text/plain"
@ -531,7 +528,7 @@ class TestResponse:
assert resp2.get_state() == resp.get_state() assert resp2.get_state() == resp.get_state()
def test_replace(self): def test_replace(self):
r = HTTPResponse.wrap(netlib.tutils.tresp()) r = http.HTTPResponse.wrap(netlib.tutils.tresp())
r.headers["Foo"] = "fOo" r.headers["Foo"] = "fOo"
r.content = b"afoob" r.content = b"afoob"
assert r.replace("foo(?i)", "boo") == 3 assert r.replace("foo(?i)", "boo") == 3
@ -539,7 +536,7 @@ class TestResponse:
assert r.headers["boo"] == "boo" assert r.headers["boo"] == "boo"
def test_get_content_type(self): def test_get_content_type(self):
resp = HTTPResponse.wrap(netlib.tutils.tresp()) resp = http.HTTPResponse.wrap(netlib.tutils.tresp())
resp.headers = Headers(content_type="text/plain") resp.headers = Headers(content_type="text/plain")
assert resp.headers["content-type"] == "text/plain" assert resp.headers["content-type"] == "text/plain"
@ -547,13 +544,13 @@ class TestResponse:
class TestError: class TestError:
def test_getset_state(self): def test_getset_state(self):
e = Error("Error") e = flow.Error("Error")
state = e.get_state() state = e.get_state()
assert Error.from_state(state).get_state() == e.get_state() assert flow.Error.from_state(state).get_state() == e.get_state()
assert e.copy() assert e.copy()
e2 = Error("bar") e2 = flow.Error("bar")
assert not e == e2 assert not e == e2
e.set_state(e2.get_state()) e.set_state(e2.get_state())
assert e.get_state() == e2.get_state() assert e.get_state() == e2.get_state()
@ -562,14 +559,14 @@ class TestError:
assert e3.get_state() == e.get_state() assert e3.get_state() == e.get_state()
def test_repr(self): def test_repr(self):
e = Error("yay") e = flow.Error("yay")
assert repr(e) assert repr(e)
class TestClientConnection: class TestClientConnection:
def test_state(self): def test_state(self):
c = tutils.tclient_conn() c = tutils.tclient_conn()
assert ClientConnection.from_state(c.get_state()).get_state() == \ assert connections.ClientConnection.from_state(c.get_state()).get_state() == \
c.get_state() c.get_state()
c2 = tutils.tclient_conn() c2 = tutils.tclient_conn()

View File

@ -2,10 +2,10 @@ import os
import mock import mock
from OpenSSL import SSL from OpenSSL import SSL
from mitmproxy import cmdline from mitmproxy.tools import cmdline
from mitmproxy import options from mitmproxy import options
from mitmproxy.proxy import ProxyConfig from mitmproxy.proxy import ProxyConfig
from mitmproxy.models.connections import ServerConnection from mitmproxy import connections
from mitmproxy.proxy.server import DummyServer, ProxyServer, ConnectionHandler from mitmproxy.proxy.server import DummyServer, ProxyServer, ConnectionHandler
from mitmproxy.proxy import config from mitmproxy.proxy import config
from netlib.exceptions import TcpDisconnect from netlib.exceptions import TcpDisconnect
@ -18,7 +18,7 @@ class TestServerConnection:
def test_simple(self): def test_simple(self):
self.d = test.Daemon() self.d = test.Daemon()
sc = ServerConnection((self.d.IFACE, self.d.port)) sc = connections.ServerConnection((self.d.IFACE, self.d.port))
sc.connect() sc.connect()
f = tutils.tflow() f = tutils.tflow()
f.server_conn = sc f.server_conn = sc
@ -36,7 +36,7 @@ class TestServerConnection:
def test_terminate_error(self): def test_terminate_error(self):
self.d = test.Daemon() self.d = test.Daemon()
sc = ServerConnection((self.d.IFACE, self.d.port)) sc = connections.ServerConnection((self.d.IFACE, self.d.port))
sc.connect() sc.connect()
sc.connection = mock.Mock() sc.connection = mock.Mock()
sc.connection.recv = mock.Mock(return_value=False) sc.connection.recv = mock.Mock(return_value=False)

View File

@ -6,9 +6,10 @@ import netlib.tutils
from mitmproxy import controller from mitmproxy import controller
from mitmproxy import options from mitmproxy import options
from mitmproxy.addons import script from mitmproxy.addons import script
from mitmproxy.models import HTTPResponse, HTTPFlow from mitmproxy import http
from mitmproxy.proxy.config import HostMatcher, parse_server_spec from mitmproxy.proxy.config import HostMatcher, parse_server_spec
from netlib import tcp, http, socks import netlib.http
from netlib import tcp, socks
from netlib.certutils import SSLCert from netlib.certutils import SSLCert
from netlib.exceptions import HttpReadDisconnect, HttpException from netlib.exceptions import HttpReadDisconnect, HttpException
from netlib.http import authentication, http1 from netlib.http import authentication, http1
@ -183,9 +184,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 if isinstance(f, HTTPFlow)) assert any(f.response.status_code == 304 for f in self.master.state.flows if isinstance(f, http.HTTPFlow))
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 == 305 for f in self.master.state.flows if isinstance(f, http.HTTPFlow))
assert not any(f.response.status_code == 306 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 if isinstance(f, http.HTTPFlow))
# Test that we get the original SSL cert # Test that we get the original SSL cert
if self.ssl: if self.ssl:
@ -293,7 +294,7 @@ class TestHTTPAuth(tservers.HTTPProxyTest):
h'%s'='%s' h'%s'='%s'
""" % ( """ % (
self.server.port, self.server.port,
http.authentication.BasicProxyAuth.AUTH_HEADER, netlib.http.authentication.BasicProxyAuth.AUTH_HEADER,
authentication.assemble_http_basic_auth("basic", "test", "test") authentication.assemble_http_basic_auth("basic", "test", "test")
)) ))
assert ret.status_code == 202 assert ret.status_code == 202
@ -310,7 +311,7 @@ class TestHTTPReverseAuth(tservers.ReverseProxyTest):
'/p/202' '/p/202'
h'%s'='%s' h'%s'='%s'
""" % ( """ % (
http.authentication.BasicWebsiteAuth.AUTH_HEADER, netlib.http.authentication.BasicWebsiteAuth.AUTH_HEADER,
authentication.assemble_http_basic_auth("basic", "test", "test") authentication.assemble_http_basic_auth("basic", "test", "test")
)) ))
assert ret.status_code == 202 assert ret.status_code == 202
@ -790,7 +791,7 @@ class TestStreamRequest(tservers.HTTPProxyTest):
class MasterFakeResponse(tservers.TestMaster): class MasterFakeResponse(tservers.TestMaster):
@controller.handler @controller.handler
def request(self, f): def request(self, f):
f.response = HTTPResponse.wrap(netlib.tutils.tresp()) f.response = http.HTTPResponse.wrap(netlib.tutils.tresp())
class TestFakeResponse(tservers.HTTPProxyTest): class TestFakeResponse(tservers.HTTPProxyTest):
@ -869,7 +870,7 @@ class MasterIncomplete(tservers.TestMaster):
@controller.handler @controller.handler
def request(self, f): def request(self, f):
resp = HTTPResponse.wrap(netlib.tutils.tresp()) resp = http.HTTPResponse.wrap(netlib.tutils.tresp())
resp.content = None resp.content = None
f.response = resp f.response = resp

View File

@ -5,7 +5,7 @@ utils.CERT_SLEEP_TIME = 0
def test_pkg_data(): def test_pkg_data():
assert utils.pkg_data.path("console") assert utils.pkg_data.path("tools/console")
tutils.raises("does not exist", utils.pkg_data.path, "nonexistent") tutils.raises("does not exist", utils.pkg_data.path, "nonexistent")

View File

@ -1,8 +1,8 @@
import tornado.testing import tornado.testing
from mitmproxy import proxy from mitmproxy import proxy
from mitmproxy.web import app from mitmproxy.tools.web import app
from mitmproxy.web import master as webmaster from mitmproxy.tools.web import master as webmaster
class TestApp(tornado.testing.AsyncHTTPTestCase): class TestApp(tornado.testing.AsyncHTTPTestCase):

View File

@ -1,4 +1,4 @@
from mitmproxy.web import master from mitmproxy.tools.web import master
from mitmproxy import proxy from mitmproxy import proxy
from . import mastertest from . import mastertest

View File

@ -12,11 +12,10 @@ import io
import netlib.utils import netlib.utils
import netlib.tutils import netlib.tutils
from mitmproxy import controller from mitmproxy import controller
from mitmproxy.models import ( from mitmproxy import connections
ClientConnection, ServerConnection, Error, HTTPRequest, HTTPResponse, HTTPFlow, TCPFlow from mitmproxy import flow
) from mitmproxy import http
from mitmproxy.models.tcp import TCPMessage from mitmproxy import tcp
from mitmproxy.models.flow import Flow
def _skip_windows(*args): def _skip_windows(*args):
@ -48,7 +47,7 @@ def skip_appveyor(fn):
return fn return fn
class DummyFlow(Flow): class DummyFlow(flow.Flow):
"""A flow that is neither HTTP nor TCP.""" """A flow that is neither HTTP nor TCP."""
def __init__(self, client_conn, server_conn, live=None): def __init__(self, client_conn, server_conn, live=None):
@ -76,13 +75,13 @@ def ttcpflow(client_conn=True, server_conn=True, messages=True, err=None):
server_conn = tserver_conn() server_conn = tserver_conn()
if messages is True: if messages is True:
messages = [ messages = [
TCPMessage(True, b"hello"), tcp.TCPMessage(True, b"hello"),
TCPMessage(False, b"it's me"), tcp.TCPMessage(False, b"it's me"),
] ]
if err is True: if err is True:
err = terr() err = terr()
f = TCPFlow(client_conn, server_conn) f = tcp.TCPFlow(client_conn, server_conn)
f.messages = messages f.messages = messages
f.error = err f.error = err
f.reply = controller.DummyReply() f.reply = controller.DummyReply()
@ -110,11 +109,11 @@ def tflow(client_conn=True, server_conn=True, req=True, resp=None, err=None):
err = terr() err = terr()
if req: if req:
req = HTTPRequest.wrap(req) req = http.HTTPRequest.wrap(req)
if resp: if resp:
resp = HTTPResponse.wrap(resp) resp = http.HTTPResponse.wrap(resp)
f = HTTPFlow(client_conn, server_conn) f = http.HTTPFlow(client_conn, server_conn)
f.request = req f.request = req
f.response = resp f.response = resp
f.error = err f.error = err
@ -126,7 +125,7 @@ def tclient_conn():
""" """
@return: mitmproxy.proxy.connection.ClientConnection @return: mitmproxy.proxy.connection.ClientConnection
""" """
c = ClientConnection.from_state(dict( c = connections.ClientConnection.from_state(dict(
address=dict(address=("address", 22), use_ipv6=True), address=dict(address=("address", 22), use_ipv6=True),
clientcert=None, clientcert=None,
ssl_established=False, ssl_established=False,
@ -142,7 +141,7 @@ def tserver_conn():
""" """
@return: mitmproxy.proxy.connection.ServerConnection @return: mitmproxy.proxy.connection.ServerConnection
""" """
c = ServerConnection.from_state(dict( c = connections.ServerConnection.from_state(dict(
address=dict(address=("address", 22), use_ipv6=True), address=dict(address=("address", 22), use_ipv6=True),
source_address=dict(address=("address", 22), use_ipv6=True), source_address=dict(address=("address", 22), use_ipv6=True),
ip_address=None, ip_address=None,
@ -163,7 +162,7 @@ def terr(content="error"):
""" """
@return: mitmproxy.protocol.primitives.Error @return: mitmproxy.protocol.primitives.Error
""" """
err = Error(content) err = flow.Error(content)
return err return err