aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--mitmproxy/addons/state.py272
-rw-r--r--mitmproxy/addons/view.py32
-rw-r--r--mitmproxy/tools/web/app.py35
-rw-r--r--mitmproxy/tools/web/master.py93
-rw-r--r--test/mitmproxy/addons/test_state.py19
-rw-r--r--test/mitmproxy/test_flow.py152
-rw-r--r--test/mitmproxy/test_server.py24
-rw-r--r--test/mitmproxy/test_web_master.py2
-rw-r--r--test/mitmproxy/tservers.py20
-rw-r--r--tox.ini2
10 files changed, 109 insertions, 542 deletions
diff --git a/mitmproxy/addons/state.py b/mitmproxy/addons/state.py
deleted file mode 100644
index b6f575d1..00000000
--- a/mitmproxy/addons/state.py
+++ /dev/null
@@ -1,272 +0,0 @@
-from abc import abstractmethod, ABCMeta
-
-from typing import List # noqa
-
-from mitmproxy import flowfilter
-from mitmproxy import flow # noqa
-
-
-class FlowList(metaclass=ABCMeta):
- def __init__(self):
- self._list = [] # type: List[flow.Flow]
-
- def __iter__(self):
- return iter(self._list)
-
- def __contains__(self, item):
- return item in self._list
-
- def __getitem__(self, item):
- return self._list[item]
-
- def __bool__(self):
- return bool(self._list)
-
- def __len__(self):
- return len(self._list)
-
- def index(self, f):
- return self._list.index(f)
-
- @abstractmethod
- def _add(self, f):
- return
-
- @abstractmethod
- def _update(self, f):
- return
-
- @abstractmethod
- def _remove(self, f):
- return
-
-
-def _pos(*args):
- return True
-
-
-class FlowView(FlowList):
- def __init__(self, store, flt=None):
- super().__init__()
- if not flt:
- flt = _pos
- self._build(store, flt)
-
- self.store = store
- self.store.views.append(self)
-
- def _close(self):
- self.store.views.remove(self)
-
- def _build(self, flows, flt=None):
- if flt:
- self.filter = flt
- self._list = list(filter(self.filter, flows))
-
- def _add(self, f):
- if self.filter(f):
- self._list.append(f)
-
- def _update(self, f):
- if f not in self._list:
- self._add(f)
- elif not self.filter(f):
- self._remove(f)
-
- def _remove(self, f):
- if f in self._list:
- self._list.remove(f)
-
- def _recalculate(self, flows):
- self._build(flows)
-
-
-class FlowStore(FlowList):
- """
- Responsible for handling flows in the state:
- Keeps a list of all flows and provides views on them.
- """
-
- def __init__(self):
- super().__init__()
- self._set = set() # Used for O(1) lookups
- self.views = []
- self._recalculate_views()
-
- def get(self, flow_id):
- for f in self._list:
- if f.id == flow_id:
- return f
-
- def __contains__(self, f):
- return f in self._set
-
- def _add(self, f):
- """
- Adds a flow to the state.
- The flow to add must not be present in the state.
- """
- self._list.append(f)
- self._set.add(f)
- for view in self.views:
- view._add(f)
-
- def _update(self, f):
- """
- Notifies the state that a flow has been updated.
- The flow must be present in the state.
- """
- if f in self:
- for view in self.views:
- view._update(f)
-
- def _remove(self, f):
- """
- Deletes a flow from the state.
- The flow must be present in the state.
- """
- self._list.remove(f)
- self._set.remove(f)
- for view in self.views:
- view._remove(f)
-
- # Expensive bulk operations
-
- def _extend(self, flows):
- """
- Adds a list of flows to the state.
- The list of flows to add must not contain flows that are already in the state.
- """
- self._list.extend(flows)
- self._set.update(flows)
- self._recalculate_views()
-
- def _clear(self):
- self._list = []
- self._set = set()
- self._recalculate_views()
-
- def _recalculate_views(self):
- """
- Expensive operation: Recalculate all the views after a bulk change.
- """
- for view in self.views:
- view._recalculate(self)
-
- # Utility functions.
- # There are some common cases where we need to argue about all flows
- # irrespective of filters on the view etc (i.e. on shutdown).
-
- def active_count(self):
- c = 0
- for i in self._list:
- if not i.response and not i.error:
- c += 1
- return c
-
- # TODO: Should accept_all operate on views or on all flows?
- def accept_all(self, master):
- for f in self._list:
- f.resume(master)
-
- def kill_all(self, master):
- for f in self._list:
- if f.killable:
- f.kill(master)
-
-
-class State:
- def __init__(self):
- self.flows = FlowStore()
- self.view = FlowView(self.flows, None)
-
- @property
- def filter_txt(self):
- return getattr(self.view.filter, "pattern", None)
-
- def flow_count(self):
- return len(self.flows)
-
- # TODO: All functions regarding flows that don't cause side-effects should
- # be moved into FlowStore.
- def index(self, f):
- return self.flows.index(f)
-
- def active_flow_count(self):
- return self.flows.active_count()
-
- def add_flow(self, f):
- """
- Add a request to the state.
- """
- self.flows._add(f)
- return f
-
- def update_flow(self, f):
- """
- Add a response to the state.
- """
- self.flows._update(f)
- return f
-
- def delete_flow(self, f):
- self.flows._remove(f)
-
- def load_flows(self, flows):
- self.flows._extend(flows)
-
- def set_view_filter(self, txt):
- if txt == self.filter_txt:
- return
- if txt:
- flt = flowfilter.parse(txt)
- if not flt:
- return "Invalid filter expression."
- self.view._close()
- self.view = FlowView(self.flows, flt)
- else:
- self.view._close()
- self.view = FlowView(self.flows, None)
-
- def clear(self):
- self.flows._clear()
-
- def accept_all(self, master):
- self.flows.accept_all(master)
-
- def backup(self, f):
- f.backup()
- self.update_flow(f)
-
- def revert(self, f):
- f.revert()
- self.update_flow(f)
-
- def killall(self, master):
- self.flows.kill_all(master)
-
- def duplicate_flow(self, f):
- """
- Duplicate flow, and insert it into state without triggering any of
- the normal flow events.
- """
- f2 = f.copy()
- self.add_flow(f2)
- return f2
-
- # Event handlers
- def intercept(self, f):
- self.update_flow(f)
-
- def resume(self, f):
- self.update_flow(f)
-
- def error(self, f):
- self.update_flow(f)
-
- def request(self, f):
- if f not in self.flows: # don't add again on replay
- self.add_flow(f)
-
- def response(self, f):
- self.update_flow(f)
diff --git a/mitmproxy/addons/view.py b/mitmproxy/addons/view.py
index c09ff454..8fa5dc50 100644
--- a/mitmproxy/addons/view.py
+++ b/mitmproxy/addons/view.py
@@ -66,17 +66,17 @@ class OrderRequestStart(_OrderKey):
class OrderRequestMethod(_OrderKey):
- def generate(self, f: mitmproxy.flow.Flow) -> datetime.datetime:
+ def generate(self, f: mitmproxy.flow.Flow) -> str:
return f.request.method
class OrderRequestURL(_OrderKey):
- def generate(self, f: mitmproxy.flow.Flow) -> datetime.datetime:
+ def generate(self, f: mitmproxy.flow.Flow) -> str:
return f.request.url
class OrderKeySize(_OrderKey):
- def generate(self, f: mitmproxy.flow.Flow) -> datetime.datetime:
+ def generate(self, f: mitmproxy.flow.Flow) -> int:
s = 0
if f.request.raw_content:
s += len(f.request.raw_content)
@@ -166,8 +166,8 @@ class View(collections.Sequence):
return v
return self._rev(v - 1) + 1
- def index(self, f: mitmproxy.flow.Flow) -> int:
- return self._rev(self._view.index(f))
+ def index(self, f: mitmproxy.flow.Flow, start: int = 0, stop: typing.Optional[int] = None) -> int:
+ return self._rev(self._view.index(f, start, stop))
def __contains__(self, f: mitmproxy.flow.Flow) -> bool:
return self._view.__contains__(f)
@@ -318,7 +318,7 @@ class Focus:
"""
def __init__(self, v: View) -> None:
self.view = v
- self._flow = None
+ self._flow = None # type: mitmproxy.flow.Flow
self.sig_change = blinker.Signal()
if len(self.view):
self.flow = self.view[0]
@@ -374,29 +374,29 @@ class Focus:
class Settings(collections.Mapping):
def __init__(self, view: View) -> None:
self.view = view
- self.values = {}
+ self._values = {} # type: typing.MutableMapping[str, mitmproxy.flow.Flow]
view.sig_remove.connect(self._sig_remove)
view.sig_refresh.connect(self._sig_refresh)
def clear(self):
- self.values.clear()
+ self._values.clear()
- def __iter__(self) -> typing.Iterable:
- return iter(self.values)
+ def __iter__(self) -> typing.Iterator:
+ return iter(self._values)
def __len__(self) -> int:
- return len(self.values)
+ return len(self._values)
def __getitem__(self, f: mitmproxy.flow.Flow) -> dict:
if f.id not in self.view._store:
raise KeyError
- return self.values.setdefault(f.id, {})
+ return self._values.setdefault(f.id, {})
def _sig_remove(self, view, flow):
- if flow.id in self.values:
- del self.values[flow.id]
+ if flow.id in self._values:
+ del self._values[flow.id]
def _sig_refresh(self, view):
- for fid in list(self.values.keys()):
+ for fid in list(self._values.keys()):
if fid not in view._store:
- del self.values[fid]
+ del self._values[fid]
diff --git a/mitmproxy/tools/web/app.py b/mitmproxy/tools/web/app.py
index 41701d36..bbdc2bf9 100644
--- a/mitmproxy/tools/web/app.py
+++ b/mitmproxy/tools/web/app.py
@@ -116,8 +116,8 @@ class RequestHandler(BasicAuth, tornado.web.RequestHandler):
return json.loads(self.request.body.decode())
@property
- def state(self):
- return self.application.master.state
+ def view(self):
+ return self.application.master.view
@property
def master(self) -> "mitmproxy.tools.web.master.WebMaster":
@@ -126,7 +126,8 @@ class RequestHandler(BasicAuth, tornado.web.RequestHandler):
@property
def flow(self):
flow_id = str(self.path_kwargs["flow_id"])
- flow = self.state.flows.get(flow_id)
+ # FIXME: Add a facility to addon.view to safely access the store
+ flow = self.view._store.get(flow_id)
if flow:
return flow
else:
@@ -184,7 +185,7 @@ class Flows(RequestHandler):
def get(self):
self.write(dict(
- data=[convert_flow_to_json_dict(f) for f in self.state.flows]
+ data=[convert_flow_to_json_dict(f) for f in self.view]
))
@@ -195,31 +196,31 @@ class DumpFlows(RequestHandler):
bio = BytesIO()
fw = io.FlowWriter(bio)
- for f in self.state.flows:
+ for f in self.view:
fw.add(f)
self.write(bio.getvalue())
bio.close()
def post(self):
- self.state.clear()
+ self.view.clear()
content = self.request.files.values()[0][0].body
bio = BytesIO(content)
- self.state.load_flows(io.FlowReader(bio).stream())
+ self.view.load_flows(io.FlowReader(bio).stream())
bio.close()
class ClearAll(RequestHandler):
def post(self):
- self.state.clear()
+ self.view.clear()
class AcceptFlows(RequestHandler):
def post(self):
- self.state.flows.accept_all(self.master)
+ self.view.flows.accept_all(self.master)
class AcceptFlow(RequestHandler):
@@ -233,7 +234,7 @@ class FlowHandler(RequestHandler):
def delete(self, flow_id):
if self.flow.killable:
self.flow.kill(self.master)
- self.state.delete_flow(self.flow)
+ self.view.delete_flow(self.flow)
def put(self, flow_id):
flow = self.flow
@@ -270,19 +271,19 @@ class FlowHandler(RequestHandler):
print("Warning: Unknown update {}.{}: {}".format(a, k, v))
else:
print("Warning: Unknown update {}: {}".format(a, b))
- self.state.update_flow(flow)
+ self.view.update_flow(flow)
class DuplicateFlow(RequestHandler):
def post(self, flow_id):
- self.master.state.duplicate_flow(self.flow)
+ self.master.view.duplicate_flow(self.flow)
class RevertFlow(RequestHandler):
def post(self, flow_id):
- self.state.revert(self.flow)
+ self.flow.revert()
class ReplayFlow(RequestHandler):
@@ -290,7 +291,7 @@ class ReplayFlow(RequestHandler):
def post(self, flow_id):
self.flow.backup()
self.flow.response = None
- self.state.update_flow(self.flow)
+ self.view.update_flow(self.flow)
r = self.master.replay_request(self.flow)
if r:
@@ -303,7 +304,7 @@ class FlowContent(RequestHandler):
self.flow.backup()
message = getattr(self.flow, message)
message.content = self.request.files.values()[0][0].body
- self.state.update_flow(self.flow)
+ self.view.update_flow(self.flow)
def get(self, flow_id, message):
message = getattr(self.flow, message)
@@ -340,7 +341,7 @@ class FlowContentView(RequestHandler):
message = getattr(self.flow, message)
description, lines, error = contentviews.get_message_content_view(
- contentviews.get(content_view.replace('_', ' ')), message
+ contentviews.get(content_view.replace('_', ' ')).name, message
)
# if error:
# add event log
@@ -355,7 +356,7 @@ class Events(RequestHandler):
def get(self):
self.write(dict(
- data=list(self.state.events)
+ data=list([])
))
diff --git a/mitmproxy/tools/web/master.py b/mitmproxy/tools/web/master.py
index cf0bfd73..d283e5d5 100644
--- a/mitmproxy/tools/web/master.py
+++ b/mitmproxy/tools/web/master.py
@@ -1,5 +1,4 @@
import sys
-import collections
import tornado.httpserver
import tornado.ioloop
@@ -8,7 +7,7 @@ from typing import Optional
from mitmproxy import addons
from mitmproxy import exceptions
-from mitmproxy.addons import state
+from mitmproxy.addons import view
from mitmproxy.addons import intercept
from mitmproxy import options
from mitmproxy import master
@@ -20,53 +19,7 @@ class Stop(Exception):
pass
-class WebFlowView(state.FlowView):
-
- def __init__(self, store):
- super().__init__(store, None)
-
- def _add(self, f):
- super()._add(f)
- app.ClientConnection.broadcast(
- type="UPDATE_FLOWS",
- cmd="add",
- data=app.convert_flow_to_json_dict(f)
- )
-
- def _update(self, f):
- super()._update(f)
- app.ClientConnection.broadcast(
- type="UPDATE_FLOWS",
- cmd="update",
- data=app.convert_flow_to_json_dict(f)
- )
-
- def _remove(self, f):
- super()._remove(f)
- app.ClientConnection.broadcast(
- type="UPDATE_FLOWS",
- cmd="remove",
- data=dict(id=f.id)
- )
-
- def _recalculate(self, flows):
- super()._recalculate(flows)
- app.ClientConnection.broadcast(
- type="UPDATE_FLOWS",
- cmd="reset"
- )
-
-
-class WebState(state.State):
-
- def __init__(self):
- super().__init__()
- self.view._close()
- self.view = WebFlowView(self.flows)
-
- self._last_event_id = 0
- self.events = collections.deque(maxlen=1000)
-
+class _WebState():
def add_log(self, e, level):
self._last_event_id += 1
entry = {
@@ -136,9 +89,14 @@ class WebMaster(master.Master):
def __init__(self, options, server):
super().__init__(options, server)
- self.state = WebState()
+ self.view = view.View()
+ self.view.sig_add.connect(self._sig_add)
+ self.view.sig_remove.connect(self._sig_remove)
+ self.view.sig_update.connect(self._sig_update)
+ self.view.sig_refresh.connect(self._sig_refresh)
+
self.addons.add(*addons.default_addons())
- self.addons.add(self.state, intercept.Intercept())
+ self.addons.add(self.view, intercept.Intercept())
self.app = app.Application(
self, self.options.wdebug, self.options.wauthenticator
)
@@ -162,6 +120,33 @@ class WebMaster(master.Master):
print("Stream file error: {}".format(err), file=sys.stderr)
sys.exit(1)
+ def _sig_add(self, view, flow):
+ app.ClientConnection.broadcast(
+ type="UPDATE_FLOWS",
+ cmd="add",
+ data=app.convert_flow_to_json_dict(flow)
+ )
+
+ def _sig_update(self, view, flow):
+ app.ClientConnection.broadcast(
+ type="UPDATE_FLOWS",
+ cmd="update",
+ data=app.convert_flow_to_json_dict(flow)
+ )
+
+ def _sig_remove(self, view, flow):
+ app.ClientConnection.broadcast(
+ type="UPDATE_FLOWS",
+ cmd="remove",
+ data=dict(id=flow.id)
+ )
+
+ def _sig_refresh(self, view):
+ app.ClientConnection.broadcast(
+ type="UPDATE_FLOWS",
+ cmd="reset"
+ )
+
def run(self): # pragma: no cover
iol = tornado.ioloop.IOLoop.instance()
@@ -178,6 +163,6 @@ class WebMaster(master.Master):
except (Stop, KeyboardInterrupt):
self.shutdown()
- def add_log(self, e, level="info"):
- super().add_log(e, level)
- return self.state.add_log(e, level)
+ # def add_log(self, e, level="info"):
+ # super().add_log(e, level)
+ # return self.state.add_log(e, level)
diff --git a/test/mitmproxy/addons/test_state.py b/test/mitmproxy/addons/test_state.py
deleted file mode 100644
index 16e79e0d..00000000
--- a/test/mitmproxy/addons/test_state.py
+++ /dev/null
@@ -1,19 +0,0 @@
-from mitmproxy.test import tflow
-from mitmproxy import proxy
-from mitmproxy import master
-from mitmproxy.addons import state
-
-
-class TestState:
- def test_duplicate_flow(self):
- s = state.State()
- fm = master.Master(None, proxy.DummyServer())
- fm.addons.add(s)
- f = tflow.tflow(resp=True)
- fm.load_flow(f)
- assert s.flow_count() == 1
-
- f2 = s.duplicate_flow(f)
- assert f2.response
- assert s.flow_count() == 2
- assert s.index(f2) == 1
diff --git a/test/mitmproxy/test_flow.py b/test/mitmproxy/test_flow.py
index 7a9d0901..295e2bea 100644
--- a/test/mitmproxy/test_flow.py
+++ b/test/mitmproxy/test_flow.py
@@ -6,7 +6,6 @@ import mitmproxy.test.tutils
from mitmproxy.net.http import Headers
import mitmproxy.io
from mitmproxy import flowfilter, options
-from mitmproxy.addons import state
from mitmproxy.contrib import tnetstring
from mitmproxy.exceptions import FlowReadException, Kill
from mitmproxy import flow
@@ -15,7 +14,7 @@ from mitmproxy import connections
from mitmproxy.proxy import ProxyConfig
from mitmproxy.proxy.server import DummyServer
from mitmproxy import master
-from . import tutils
+from . import tutils, tservers
class TestHTTPFlow:
@@ -107,20 +106,6 @@ class TestHTTPFlow:
assert not f.killable
assert f.reply.value == Kill
- def test_killall(self):
- srv = DummyServer(None)
- s = state.State()
- fm = master.Master(None, srv)
- fm.addons.add(s)
-
- f = tflow.tflow()
- f.reply.handle()
- f.intercept(fm)
-
- s.killall(fm)
- for i in s.view:
- assert "killed" in str(i.error)
-
def test_resume(self):
f = tflow.tflow()
f.reply.handle()
@@ -186,135 +171,6 @@ class TestTCPFlow:
tutils.raises(ValueError, flowfilter.match, "~", f)
-class TestState:
-
- def test_backup(self):
- c = state.State()
- f = tflow.tflow()
- c.add_flow(f)
- f.backup()
- c.revert(f)
-
- def test_flow(self):
- """
- normal flow:
-
- connect -> request -> response
- """
- c = state.State()
- f = tflow.tflow()
- c.add_flow(f)
- assert f
- assert c.flow_count() == 1
- assert c.active_flow_count() == 1
-
- newf = tflow.tflow()
- assert c.add_flow(newf)
- assert c.active_flow_count() == 2
-
- f.response = http.HTTPResponse.wrap(mitmproxy.test.tutils.tresp())
- assert c.update_flow(f)
- assert c.flow_count() == 2
- assert c.active_flow_count() == 1
-
- assert not c.update_flow(None)
- assert c.active_flow_count() == 1
-
- newf.response = http.HTTPResponse.wrap(mitmproxy.test.tutils.tresp())
- assert c.update_flow(newf)
- assert c.active_flow_count() == 0
-
- def test_err(self):
- c = state.State()
- f = tflow.tflow()
- c.add_flow(f)
- f.error = flow.Error("message")
- assert c.update_flow(f)
-
- c = state.State()
- f = tflow.tflow()
- c.add_flow(f)
- c.set_view_filter("~e")
- assert not c.view
- f.error = tflow.terr()
- assert c.update_flow(f)
- assert c.view
-
- def test_set_view_filter(self):
- c = state.State()
-
- f = tflow.tflow()
- assert len(c.view) == 0
-
- c.add_flow(f)
- assert len(c.view) == 1
-
- c.set_view_filter("~s")
- assert c.filter_txt == "~s"
- assert len(c.view) == 0
- f.response = http.HTTPResponse.wrap(mitmproxy.test.tutils.tresp())
- c.update_flow(f)
- assert len(c.view) == 1
- c.set_view_filter(None)
- assert len(c.view) == 1
-
- f = tflow.tflow()
- c.add_flow(f)
- assert len(c.view) == 2
- c.set_view_filter("~q")
- assert len(c.view) == 1
- c.set_view_filter("~s")
- assert len(c.view) == 1
-
- assert "Invalid" in c.set_view_filter("~")
-
- def _add_request(self, state):
- f = tflow.tflow()
- state.add_flow(f)
- return f
-
- def _add_response(self, state):
- f = tflow.tflow()
- state.add_flow(f)
- f.response = http.HTTPResponse.wrap(mitmproxy.test.tutils.tresp())
- state.update_flow(f)
-
- def _add_error(self, state):
- f = tflow.tflow(err=True)
- state.add_flow(f)
-
- def test_clear(self):
- c = state.State()
- f = self._add_request(c)
- f.intercepted = True
-
- c.clear()
- assert c.flow_count() == 0
-
- def test_dump_flows(self):
- c = state.State()
- self._add_request(c)
- self._add_response(c)
- self._add_request(c)
- self._add_response(c)
- self._add_request(c)
- self._add_response(c)
- self._add_error(c)
-
- flows = c.view[:]
- c.clear()
-
- c.load_flows(flows)
- assert isinstance(c.flows[0], flow.Flow)
-
- def test_accept_all(self):
- c = state.State()
- self._add_request(c)
- self._add_response(c)
- self._add_request(c)
- c.accept_all(mock.Mock())
-
-
class TestSerialize:
def _treader(self):
@@ -354,7 +210,7 @@ class TestSerialize:
def test_load_flows(self):
r = self._treader()
- s = state.State()
+ s = tservers.TestState()
fm = master.Master(None, DummyServer())
fm.addons.add(s)
fm.load_flows(r)
@@ -362,7 +218,7 @@ class TestSerialize:
def test_load_flows_reverse(self):
r = self._treader()
- s = state.State()
+ s = tservers.TestState()
opts = options.Options(
mode="reverse",
upstream_server="https://use-this-domain"
@@ -431,7 +287,7 @@ class TestFlowMaster:
assert fm.create_request("GET", "http", "example.com", 80, "/")
def test_all(self):
- s = state.State()
+ s = tservers.TestState()
fm = master.Master(None, DummyServer())
fm.addons.add(s)
f = tflow.tflow(req=None)
diff --git a/test/mitmproxy/test_server.py b/test/mitmproxy/test_server.py
index 7dd738f4..74cb5ae8 100644
--- a/test/mitmproxy/test_server.py
+++ b/test/mitmproxy/test_server.py
@@ -50,10 +50,10 @@ class CommonMixin:
def test_replay(self):
assert self.pathod("304").status_code == 304
if isinstance(self, tservers.HTTPUpstreamProxyTest) and self.ssl:
- assert len(self.master.state.view) == 2
+ assert len(self.master.state.flows) == 2
else:
- assert len(self.master.state.view) == 1
- l = self.master.state.view[-1]
+ assert len(self.master.state.flows) == 1
+ l = self.master.state.flows[-1]
assert l.response.status_code == 304
l.request.path = "/p/305"
self.wait_until_not_live(l)
@@ -87,7 +87,7 @@ class CommonMixin:
# In Upstream mode with SSL, we may already have a previous CONNECT
# request.
- l = self.master.state.view[-1]
+ l = self.master.state.flows[-1]
assert l.client_conn.address
assert "host" in l.request.headers
assert l.response.status_code == 304
@@ -589,7 +589,7 @@ class TestProxy(tservers.HTTPProxyTest):
f = self.pathod("304")
assert f.status_code == 304
- f = self.master.state.view[0]
+ f = self.master.state.flows[0]
assert f.client_conn.address
assert "host" in f.request.headers
assert f.response.status_code == 304
@@ -601,7 +601,7 @@ class TestProxy(tservers.HTTPProxyTest):
f = self.pathod("304:b@1k:p50,1")
assert f.status_code == 304
- response = self.master.state.view[0].response
+ response = self.master.state.flows[0].response
# timestamp_start might fire a bit late, so we play safe and only require 300ms.
assert 0.3 <= response.timestamp_end - response.timestamp_start
@@ -620,8 +620,8 @@ class TestProxy(tservers.HTTPProxyTest):
connection.recv(50000)
connection.close()
- request, response = self.master.state.view[
- 0].request, self.master.state.view[0].response
+ request, response = self.master.state.flows[
+ 0].request, self.master.state.flows[0].response
assert response.status_code == 304 # sanity test for our low level request
# timestamp_start might fire a bit late, so we play safe and only require 300ms.
assert 0.3 <= request.timestamp_end - request.timestamp_start
@@ -647,8 +647,8 @@ class TestProxy(tservers.HTTPProxyTest):
recvd += len(connection.recv(5000))
connection.close()
- first_flow = self.master.state.view[0]
- second_flow = self.master.state.view[1]
+ first_flow = self.master.state.flows[0]
+ second_flow = self.master.state.flows[1]
assert first_flow.server_conn.timestamp_tcp_setup
assert first_flow.server_conn.timestamp_ssl_setup is None
assert second_flow.server_conn.timestamp_tcp_setup
@@ -657,7 +657,7 @@ class TestProxy(tservers.HTTPProxyTest):
def test_request_ip(self):
f = self.pathod("200:b@100")
assert f.status_code == 200
- f = self.master.state.view[0]
+ f = self.master.state.flows[0]
assert f.server_conn.address == ("127.0.0.1", self.server.port)
@@ -668,7 +668,7 @@ class TestProxySSL(tservers.HTTPProxyTest):
# tests that the ssl timestamp is present when ssl is used
f = self.pathod("304:b@10k")
assert f.status_code == 304
- first_flow = self.master.state.view[0]
+ first_flow = self.master.state.flows[0]
assert first_flow.server_conn.timestamp_ssl_setup
diff --git a/test/mitmproxy/test_web_master.py b/test/mitmproxy/test_web_master.py
index 77280644..298b14eb 100644
--- a/test/mitmproxy/test_web_master.py
+++ b/test/mitmproxy/test_web_master.py
@@ -12,4 +12,4 @@ class TestWebMaster(mastertest.MasterTest):
m = self.mkmaster()
for i in (1, 2, 3):
self.dummy_cycle(m, 1, b"")
- assert len(m.state.flows) == i
+ assert len(m.view) == i
diff --git a/test/mitmproxy/tservers.py b/test/mitmproxy/tservers.py
index e07102e1..f9dfde30 100644
--- a/test/mitmproxy/tservers.py
+++ b/test/mitmproxy/tservers.py
@@ -7,7 +7,6 @@ import sys
from mitmproxy.proxy.config import ProxyConfig
from mitmproxy.proxy.server import ProxyServer
from mitmproxy import master
-from mitmproxy.addons import state
import pathod.test
import pathod.pathoc
from mitmproxy import controller
@@ -15,6 +14,23 @@ from mitmproxy import options
from mitmproxy import exceptions
+class TestState:
+ def __init__(self):
+ self.flows = []
+
+ def request(self, f):
+ if f not in self.flows:
+ self.flows.append(f)
+
+ def response(self, f):
+ if f not in self.flows:
+ self.flows.append(f)
+
+ # FIXME: compat with old state - remove in favor of len(state.flows)
+ def flow_count(self):
+ return len(self.flows)
+
+
class TestMaster(master.Master):
def __init__(self, opts, config):
@@ -23,7 +39,7 @@ class TestMaster(master.Master):
def clear_addons(self, addons):
self.addons.clear()
- self.state = state.State()
+ self.state = TestState()
self.addons.add(self.state)
self.addons.add(*addons)
diff --git a/tox.ini b/tox.ini
index d969abec..8e3e51de 100644
--- a/tox.ini
+++ b/tox.ini
@@ -21,4 +21,4 @@ commands = sphinx-build -W -b html -d {envtmpdir}/doctrees . {envtmpdir}/html
commands =
flake8 --jobs 8 --count mitmproxy pathod examples test
rstcheck README.rst
- mypy --silent-imports mitmproxy/addonmanager.py mitmproxy/proxy/protocol/
+ mypy --silent-imports mitmproxy/addons mitmproxy/addonmanager.py mitmproxy/proxy/protocol/