aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--issue_template.md4
-rw-r--r--mitmproxy/console/common.py8
-rw-r--r--mitmproxy/flow.py19
-rw-r--r--netlib/odict.py81
-rw-r--r--test/netlib/test_odict.py10
-rw-r--r--test/pathod/test_pathoc.py2
-rw-r--r--test/pathod/test_pathod.py7
7 files changed, 58 insertions, 73 deletions
diff --git a/issue_template.md b/issue_template.md
index 3f9be788..08d390e4 100644
--- a/issue_template.md
+++ b/issue_template.md
@@ -10,10 +10,10 @@
##### What went wrong?
-##### Any other comments?
+##### Any other comments? What have you tried so far?
---
Mitmproxy Version:
-Operating System: \ No newline at end of file
+Operating System:
diff --git a/mitmproxy/console/common.py b/mitmproxy/console/common.py
index 4e472fb6..25658dfa 100644
--- a/mitmproxy/console/common.py
+++ b/mitmproxy/console/common.py
@@ -154,7 +154,7 @@ def raw_format_flow(f, focus, extended):
if f["intercepted"] and not f["acked"]:
uc = "intercept"
- elif f["resp_code"] or f["err_msg"]:
+ elif "resp_code" in f or "err_msg" in f:
uc = "text"
else:
uc = "title"
@@ -173,7 +173,7 @@ def raw_format_flow(f, focus, extended):
("fixed", preamble, urwid.Text(""))
)
- if f["resp_code"]:
+ if "resp_code" in f:
codes = {
2: "code_200",
3: "code_300",
@@ -185,6 +185,8 @@ def raw_format_flow(f, focus, extended):
if f["resp_is_replay"]:
resp.append(fcol(SYMBOL_REPLAY, "replay"))
resp.append(fcol(f["resp_code"], ccol))
+ if extended:
+ resp.append(fcol(f["resp_reason"], ccol))
if f["intercepted"] and f["resp_code"] and not f["acked"]:
rc = "intercept"
else:
@@ -412,7 +414,6 @@ def format_flow(f, focus, extended=False, hostheader=False, marked=False):
req_http_version = f.request.http_version,
err_msg = f.error.msg if f.error else None,
- resp_code = f.response.status_code if f.response else None,
marked = marked,
)
@@ -430,6 +431,7 @@ def format_flow(f, focus, extended=False, hostheader=False, marked=False):
d.update(dict(
resp_code = f.response.status_code,
+ resp_reason = f.response.reason,
resp_is_replay = f.response.is_replay,
resp_clen = contentdesc,
roundtrip = roundtrip,
diff --git a/mitmproxy/flow.py b/mitmproxy/flow.py
index 647ebf68..a9018e16 100644
--- a/mitmproxy/flow.py
+++ b/mitmproxy/flow.py
@@ -13,6 +13,8 @@ from six.moves import http_cookies, http_cookiejar, urllib
import os
import re
+from typing import List, Optional, Set
+
from netlib import wsgi, odict
from netlib.exceptions import HttpException
from netlib.http import Headers, http1, cookies
@@ -376,8 +378,11 @@ class StickyAuthState:
f.request.headers["authorization"] = self.hosts[host]
+@six.add_metaclass(ABCMeta)
class FlowList(object):
- __metaclass__ = ABCMeta
+
+ def __init__(self):
+ self._list = [] # type: List[Flow]
def __iter__(self):
return iter(self._list)
@@ -416,7 +421,7 @@ class FlowList(object):
class FlowView(FlowList):
def __init__(self, store, filt=None):
- self._list = []
+ super(FlowView, self).__init__()
if not filt:
filt = lambda flow: True
self._build(store, filt)
@@ -458,7 +463,7 @@ class FlowStore(FlowList):
"""
def __init__(self):
- self._list = []
+ super(FlowStore, self).__init__()
self._set = set() # Used for O(1) lookups
self.views = []
self._recalculate_views()
@@ -649,18 +654,18 @@ class FlowMaster(controller.ServerMaster):
self.server_playback = None
self.client_playback = None
self.kill_nonreplay = False
- self.scripts = []
+ self.scripts = [] # type: List[script.Script]
self.pause_scripts = False
- self.stickycookie_state = False
+ self.stickycookie_state = None # type: Optional[StickyCookieState]
self.stickycookie_txt = None
- self.stickyauth_state = False
+ self.stickyauth_state = False # type: Optional[StickyAuthState]
self.stickyauth_txt = None
self.anticache = False
self.anticomp = False
- self.stream_large_bodies = False
+ self.stream_large_bodies = None # type: Optional[StreamLargeBodies]
self.refresh_server_playback = False
self.replacehooks = ReplaceHooks()
self.setheaders = SetHeaders()
diff --git a/netlib/odict.py b/netlib/odict.py
index 461192f7..8a638dab 100644
--- a/netlib/odict.py
+++ b/netlib/odict.py
@@ -1,5 +1,6 @@
from __future__ import (absolute_import, print_function, division)
import copy
+
import six
from .utils import Serializable, safe_subn
@@ -27,27 +28,24 @@ class ODict(Serializable):
def __iter__(self):
return self.lst.__iter__()
- def __getitem__(self, k):
+ def __getitem__(self, key):
"""
Returns a list of values matching key.
"""
- ret = []
- k = self._kconv(k)
- for i in self.lst:
- if self._kconv(i[0]) == k:
- ret.append(i[1])
- return ret
- def keys(self):
- return list(set([self._kconv(i[0]) for i in self.lst]))
+ key = self._kconv(key)
+ return [
+ v
+ for k, v in self.lst
+ if self._kconv(k) == key
+ ]
- def _filter_lst(self, k, lst):
- k = self._kconv(k)
- new = []
- for i in lst:
- if self._kconv(i[0]) != k:
- new.append(i)
- return new
+ def keys(self):
+ return list(
+ set(
+ self._kconv(k) for k, _ in self.lst
+ )
+ )
def __len__(self):
"""
@@ -81,14 +79,19 @@ class ODict(Serializable):
"""
Delete all items matching k.
"""
- self.lst = self._filter_lst(k, self.lst)
-
- def __contains__(self, k):
k = self._kconv(k)
- for i in self.lst:
- if self._kconv(i[0]) == k:
- return True
- return False
+ self.lst = [
+ i
+ for i in self.lst
+ if self._kconv(i[0]) != k
+ ]
+
+ def __contains__(self, key):
+ key = self._kconv(key)
+ return any(
+ self._kconv(k) == key
+ for k, _ in self.lst
+ )
def add(self, key, value, prepend=False):
if prepend:
@@ -127,40 +130,24 @@ class ODict(Serializable):
def __repr__(self):
return repr(self.lst)
- def in_any(self, key, value, caseless=False):
- """
- Do any of the values matching key contain value?
-
- If caseless is true, value comparison is case-insensitive.
- """
- if caseless:
- value = value.lower()
- for i in self[key]:
- if caseless:
- i = i.lower()
- if value in i:
- return True
- return False
-
def replace(self, pattern, repl, *args, **kwargs):
"""
Replaces a regular expression pattern with repl in both keys and
- values. Encoded content will be decoded before replacement, and
- re-encoded afterwards.
+ values.
Returns the number of replacements made.
"""
- nlst, count = [], 0
- for i in self.lst:
- k, c = safe_subn(pattern, repl, i[0], *args, **kwargs)
+ new, count = [], 0
+ for k, v in self.lst:
+ k, c = safe_subn(pattern, repl, k, *args, **kwargs)
count += c
- v, c = safe_subn(pattern, repl, i[1], *args, **kwargs)
+ v, c = safe_subn(pattern, repl, v, *args, **kwargs)
count += c
- nlst.append([k, v])
- self.lst = nlst
+ new.append([k, v])
+ self.lst = new
return count
- # Implement the StateObject protocol from mitmproxy
+ # Implement Serializable
def get_state(self):
return [tuple(i) for i in self.lst]
diff --git a/test/netlib/test_odict.py b/test/netlib/test_odict.py
index f0985ef6..b6fd6401 100644
--- a/test/netlib/test_odict.py
+++ b/test/netlib/test_odict.py
@@ -27,16 +27,6 @@ class TestODict(object):
b.set_state(state)
assert b == od
- def test_in_any(self):
- od = odict.ODict()
- od["one"] = ["atwoa", "athreea"]
- assert od.in_any("one", "two")
- assert od.in_any("one", "three")
- assert not od.in_any("one", "four")
- assert not od.in_any("nonexistent", "foo")
- assert not od.in_any("one", "TWO")
- assert od.in_any("one", "TWO", True)
-
def test_iter(self):
od = odict.ODict()
assert not [i for i in od]
diff --git a/test/pathod/test_pathoc.py b/test/pathod/test_pathoc.py
index 8d0f92ac..4e8c89c5 100644
--- a/test/pathod/test_pathoc.py
+++ b/test/pathod/test_pathoc.py
@@ -211,7 +211,7 @@ class TestDaemon(_TestDaemon):
c.stop()
@skip_windows
- @pytest.mark.xfail
+ @pytest.mark.skip(reason="race condition")
def test_wait_finish(self):
c = pathoc.Pathoc(
("127.0.0.1", self.d.port),
diff --git a/test/pathod/test_pathod.py b/test/pathod/test_pathod.py
index 1718cc0b..05a3962e 100644
--- a/test/pathod/test_pathod.py
+++ b/test/pathod/test_pathod.py
@@ -129,7 +129,7 @@ class CommonTests(tutils.DaemonTests):
l = self.d.last_log()
# FIXME: Other binary data elements
- @pytest.mark.skip
+ @pytest.mark.skip(reason="race condition")
def test_sizelimit(self):
r = self.get("200:b@1g")
assert r.status_code == 800
@@ -143,7 +143,7 @@ class CommonTests(tutils.DaemonTests):
def test_info(self):
assert tuple(self.d.info()["version"]) == version.IVERSION
- @pytest.mark.skip
+ @pytest.mark.skip(reason="race condition")
def test_logs(self):
assert self.d.clear_log()
assert not self.d.last_log()
@@ -223,7 +223,7 @@ class CommonTests(tutils.DaemonTests):
)
assert r[1].payload == "test"
- @pytest.mark.skip
+ @pytest.mark.skip(reason="race condition")
def test_websocket_frame_reflect_error(self):
r, _ = self.pathoc(
["ws:/p/", "wf:-mask:knone:f'wf:b@10':i13,'a'"],
@@ -233,6 +233,7 @@ class CommonTests(tutils.DaemonTests):
# FIXME: Race Condition?
assert "Parse error" in self.d.text_log()
+ @pytest.mark.skip(reason="race condition")
def test_websocket_frame_disconnect_error(self):
self.pathoc(["ws:/p/", "wf:b@10:d3"], ws_read_limit=0)
assert self.d.last_log()