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.
@ -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
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import random
|
import random
|
||||||
import sys
|
import sys
|
||||||
from mimtproxy import io
|
from mitmproxy import io
|
||||||
|
|
||||||
|
|
||||||
class Writer:
|
class Writer:
|
||||||
|
@ -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"):
|
||||||
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
from mitmproxy.console import master
|
|
||||||
|
|
||||||
|
|
||||||
__all__ = ["master"]
|
|
@ -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()
|
||||||
|
@ -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,
|
@ -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:
|
||||||
|
@ -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
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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",
|
|
||||||
]
|
|
@ -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
|
||||||
|
@ -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)
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
@ -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()
|
||||||
|
@ -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(
|
||||||
server.rfile,
|
http1.read_response(
|
||||||
r,
|
server.rfile,
|
||||||
body_size_limit=self.config.options.body_size_limit
|
r,
|
||||||
))
|
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()
|
||||||
|
@ -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)
|
||||||
|
@ -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>`.
|
||||||
"""
|
"""
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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]
|
||||||
)
|
)
|
0
mitmproxy/tools/__init__.py
Normal 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
|
||||||
|
|
4
mitmproxy/tools/console/__init__.py
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
from mitmproxy.tools.console import master
|
||||||
|
|
||||||
|
|
||||||
|
__all__ = ["master"]
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
@ -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:
|
@ -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 ",
|
@ -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
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
||||||
|
|
@ -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):
|
@ -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
|
||||||
|
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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
|
||||||
|
|
@ -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 ",
|
@ -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",
|
@ -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):
|
@ -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):
|
@ -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
|
||||||
|
|
||||||
|
|
@ -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):
|
@ -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()
|
||||||
|
|
2
mitmproxy/tools/web/__init__.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
from mitmproxy.tools.web import master
|
||||||
|
__all__ = ["master"]
|
@ -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
|
@ -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
|
||||||
|
|
||||||
|
|
Before Width: | Height: | Size: 280 KiB After Width: | Height: | Size: 280 KiB |
Before Width: | Height: | Size: 1005 B After Width: | Height: | Size: 1005 B |
Before Width: | Height: | Size: 951 B After Width: | Height: | Size: 951 B |
Before Width: | Height: | Size: 787 B After Width: | Height: | Size: 787 B |
Before Width: | Height: | Size: 295 B After Width: | Height: | Size: 295 B |
Before Width: | Height: | Size: 357 KiB After Width: | Height: | Size: 357 KiB |
Before Width: | Height: | Size: 853 B After Width: | Height: | Size: 853 B |
Before Width: | Height: | Size: 921 B After Width: | Height: | Size: 921 B |
Before Width: | Height: | Size: 976 B After Width: | Height: | Size: 976 B |
Before Width: | Height: | Size: 861 B After Width: | Height: | Size: 861 B |
Before Width: | Height: | Size: 1.0 KiB After Width: | Height: | Size: 1.0 KiB |
Before Width: | Height: | Size: 1.1 KiB After Width: | Height: | Size: 1.1 KiB |
@ -1,2 +0,0 @@
|
|||||||
from mitmproxy.web import master
|
|
||||||
__all__ = ["master"]
|
|
6
setup.py
@ -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"
|
||||||
]
|
]
|
||||||
|
@ -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()
|
||||||
|
@ -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):
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import mitmproxy.console.common as common
|
from mitmproxy.tools.console import common
|
||||||
from .. import tutils
|
from .. import tutils
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import mitmproxy.console.help as help
|
import mitmproxy.tools.console.help as help
|
||||||
from .. import tutils
|
from .. import tutils
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import mitmproxy.console.palettes as palettes
|
import mitmproxy.tools.console.palettes as palettes
|
||||||
from .. import tutils
|
from .. import tutils
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import argparse
|
import argparse
|
||||||
from mitmproxy import cmdline
|
from mitmproxy.tools import cmdline
|
||||||
from . import tutils
|
from . import tutils
|
||||||
|
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|
@ -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()
|
||||||
|
@ -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)
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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")
|
||||||
|
|
||||||
|
|
||||||
|
@ -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):
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
|
||||||
|
|
||||||
|