aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.travis.yml8
-rw-r--r--examples/filt.py20
-rw-r--r--examples/flowwriter.py25
-rw-r--r--examples/iframe_injector.py37
-rw-r--r--examples/stub.py2
-rw-r--r--mitmproxy/addons.py15
-rw-r--r--mitmproxy/builtins/anticache.py2
-rw-r--r--mitmproxy/builtins/anticomp.py2
-rw-r--r--mitmproxy/builtins/dumper.py79
-rw-r--r--mitmproxy/builtins/filestreamer.py2
-rw-r--r--mitmproxy/builtins/replace.py2
-rw-r--r--mitmproxy/builtins/script.py95
-rw-r--r--mitmproxy/builtins/setheaders.py2
-rw-r--r--mitmproxy/builtins/stickyauth.py2
-rw-r--r--mitmproxy/builtins/stickycookie.py2
-rw-r--r--mitmproxy/console/master.py2
-rw-r--r--mitmproxy/ctx.py2
-rw-r--r--mitmproxy/dump.py4
-rw-r--r--mitmproxy/filt.py7
-rw-r--r--mitmproxy/optmanager.py18
-rw-r--r--mitmproxy/protocol/http2.py2
-rw-r--r--mitmproxy/proxy/config.py4
-rw-r--r--mitmproxy/web/master.py2
-rw-r--r--netlib/strutils.py3
-rw-r--r--test/mitmproxy/builtins/test_anticache.py5
-rw-r--r--test/mitmproxy/builtins/test_anticomp.py5
-rw-r--r--test/mitmproxy/builtins/test_dumper.py29
-rw-r--r--test/mitmproxy/builtins/test_filestreamer.py13
-rw-r--r--test/mitmproxy/builtins/test_replace.py26
-rw-r--r--test/mitmproxy/builtins/test_script.py49
-rw-r--r--test/mitmproxy/builtins/test_setheaders.py13
-rw-r--r--test/mitmproxy/builtins/test_stickyauth.py5
-rw-r--r--test/mitmproxy/builtins/test_stickycookie.py11
-rw-r--r--test/mitmproxy/data/addonscripts/addon.py22
-rw-r--r--test/mitmproxy/data/addonscripts/recorder.py36
-rw-r--r--test/mitmproxy/data/dumpfile-011bin5465 -> 5046 bytes
-rw-r--r--test/mitmproxy/script/test_concurrent.py2
-rw-r--r--test/mitmproxy/test_addons.py5
-rw-r--r--test/mitmproxy/test_examples.py5
-rw-r--r--test/mitmproxy/test_optmanager.py8
-rw-r--r--test/mitmproxy/test_protocol_http2.py75
-rw-r--r--test/mitmproxy/test_server.py4
-rw-r--r--test/mitmproxy/tservers.py2
43 files changed, 380 insertions, 274 deletions
diff --git a/.travis.yml b/.travis.yml
index e832d058..e9566ebe 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -20,10 +20,10 @@ matrix:
include:
- python: 3.5
env: TOXENV=lint
-# - os: osx
-# osx_image: xcode7.3
-# language: generic
-# env: TOXENV=py35
+ - os: osx
+ osx_image: xcode7.3
+ language: generic
+ env: TOXENV=py35
- python: 3.5
env: TOXENV=py35
- python: 3.5
diff --git a/examples/filt.py b/examples/filt.py
index 21744edd..9ccf9fa1 100644
--- a/examples/filt.py
+++ b/examples/filt.py
@@ -1,18 +1,20 @@
-# This scripts demonstrates how to use mitmproxy's filter pattern in inline scripts.
+# This scripts demonstrates how to use mitmproxy's filter pattern in scripts.
# Usage: mitmdump -s "filt.py FILTER"
import sys
from mitmproxy import filt
-state = {}
+
+class Filter:
+ def __init__(self, spec):
+ self.filter = filt.parse(spec)
+
+ def response(self, flow):
+ if flow.match(self.filter):
+ print("Flow matches filter:")
+ print(flow)
def start():
if len(sys.argv) != 2:
raise ValueError("Usage: -s 'filt.py FILTER'")
- state["filter"] = filt.parse(sys.argv[1])
-
-
-def response(flow):
- if flow.match(state["filter"]):
- print("Flow matches filter:")
- print(flow)
+ return Filter(sys.argv[1])
diff --git a/examples/flowwriter.py b/examples/flowwriter.py
index 07c7ca20..df2e5a40 100644
--- a/examples/flowwriter.py
+++ b/examples/flowwriter.py
@@ -3,20 +3,21 @@ import sys
from mitmproxy.flow import FlowWriter
-state = {}
+
+class Writer:
+ def __init__(self, path):
+ if path == "-":
+ f = sys.stdout
+ else:
+ f = open(path, "wb")
+ self.w = FlowWriter(f)
+
+ def response(self, flow):
+ if random.choice([True, False]):
+ self.w.add(flow)
def start():
if len(sys.argv) != 2:
raise ValueError('Usage: -s "flowriter.py filename"')
-
- if sys.argv[1] == "-":
- f = sys.stdout
- else:
- f = open(sys.argv[1], "wb")
- state["flow_writer"] = FlowWriter(f)
-
-
-def response(flow):
- if random.choice([True, False]):
- state["flow_writer"].add(flow)
+ return Writer(sys.argv[1])
diff --git a/examples/iframe_injector.py b/examples/iframe_injector.py
index 352c3c24..33d18bbd 100644
--- a/examples/iframe_injector.py
+++ b/examples/iframe_injector.py
@@ -3,26 +3,27 @@
import sys
from bs4 import BeautifulSoup
-iframe_url = None
+
+class Injector:
+ def __init__(self, iframe_url):
+ self.iframe_url = iframe_url
+
+ def response(self, flow):
+ if flow.request.host in self.iframe_url:
+ return
+ html = BeautifulSoup(flow.response.content, "lxml")
+ if html.body:
+ iframe = html.new_tag(
+ "iframe",
+ src=self.iframe_url,
+ frameborder=0,
+ height=0,
+ width=0)
+ html.body.insert(0, iframe)
+ flow.response.content = str(html).encode("utf8")
def start():
if len(sys.argv) != 2:
raise ValueError('Usage: -s "iframe_injector.py url"')
- global iframe_url
- iframe_url = sys.argv[1]
-
-
-def response(flow):
- if flow.request.host in iframe_url:
- return
- html = BeautifulSoup(flow.response.content, "lxml")
- if html.body:
- iframe = html.new_tag(
- "iframe",
- src=iframe_url,
- frameborder=0,
- height=0,
- width=0)
- html.body.insert(0, iframe)
- flow.response.content = str(html).encode("utf8")
+ return Injector(sys.argv[1])
diff --git a/examples/stub.py b/examples/stub.py
index e5b4a39a..4f5061e2 100644
--- a/examples/stub.py
+++ b/examples/stub.py
@@ -11,7 +11,7 @@ def start():
mitmproxy.ctx.log("start")
-def configure(options):
+def configure(options, updated):
"""
Called once on script startup before any other events, and whenever options changes.
"""
diff --git a/mitmproxy/addons.py b/mitmproxy/addons.py
index c779aaf8..a4bea9fa 100644
--- a/mitmproxy/addons.py
+++ b/mitmproxy/addons.py
@@ -13,16 +13,23 @@ class Addons(object):
self.master = master
master.options.changed.connect(self.options_update)
- def options_update(self, options):
+ def options_update(self, options, updated):
for i in self.chain:
with self.master.handlecontext():
- i.configure(options)
+ i.configure(options, updated)
- def add(self, *addons):
+ def add(self, options, *addons):
+ if not addons:
+ raise ValueError("No adons specified.")
self.chain.extend(addons)
for i in addons:
self.invoke_with_context(i, "start")
- self.invoke_with_context(i, "configure", self.master.options)
+ self.invoke_with_context(
+ i,
+ "configure",
+ self.master.options,
+ self.master.options.keys()
+ )
def remove(self, addon):
self.chain = [i for i in self.chain if i is not addon]
diff --git a/mitmproxy/builtins/anticache.py b/mitmproxy/builtins/anticache.py
index f208e2fb..41a5ed95 100644
--- a/mitmproxy/builtins/anticache.py
+++ b/mitmproxy/builtins/anticache.py
@@ -5,7 +5,7 @@ class AntiCache:
def __init__(self):
self.enabled = False
- def configure(self, options):
+ def configure(self, options, updated):
self.enabled = options.anticache
def request(self, flow):
diff --git a/mitmproxy/builtins/anticomp.py b/mitmproxy/builtins/anticomp.py
index 50bd1b73..823e960c 100644
--- a/mitmproxy/builtins/anticomp.py
+++ b/mitmproxy/builtins/anticomp.py
@@ -5,7 +5,7 @@ class AntiComp:
def __init__(self):
self.enabled = False
- def configure(self, options):
+ def configure(self, options, updated):
self.enabled = options.anticomp
def request(self, flow):
diff --git a/mitmproxy/builtins/dumper.py b/mitmproxy/builtins/dumper.py
index 239630fb..74c2e6b2 100644
--- a/mitmproxy/builtins/dumper.py
+++ b/mitmproxy/builtins/dumper.py
@@ -5,6 +5,8 @@ import traceback
import click
+import typing # noqa
+
from mitmproxy import contentviews
from mitmproxy import ctx
from mitmproxy import exceptions
@@ -19,12 +21,25 @@ def indent(n, text):
return "\n".join(pad + i for i in l)
-class Dumper():
+class Dumper(object):
def __init__(self):
- self.filter = None
- self.flow_detail = None
- self.outfp = None
- self.showhost = None
+ self.filter = None # type: filt.TFilter
+ self.flow_detail = None # type: int
+ self.outfp = None # type: typing.io.TextIO
+ self.showhost = None # type: bool
+
+ def configure(self, options, updated):
+ if options.filtstr:
+ self.filter = filt.parse(options.filtstr)
+ if not self.filter:
+ raise exceptions.OptionsError(
+ "Invalid filter expression: %s" % options.filtstr
+ )
+ else:
+ self.filter = None
+ self.flow_detail = options.flow_detail
+ self.outfp = options.tfile
+ self.showhost = options.showhost
def echo(self, text, ident=None, **style):
if ident:
@@ -59,7 +74,7 @@ class Dumper():
self.echo("")
try:
- type, lines = contentviews.get_content_view(
+ _, lines = contentviews.get_content_view(
contentviews.get("Auto"),
content,
headers=getattr(message, "headers", None)
@@ -67,7 +82,7 @@ class Dumper():
except exceptions.ContentViewException:
s = "Content viewer failed: \n" + traceback.format_exc()
ctx.log.debug(s)
- type, lines = contentviews.get_content_view(
+ _, lines = contentviews.get_content_view(
contentviews.get("Raw"),
content,
headers=getattr(message, "headers", None)
@@ -114,9 +129,8 @@ class Dumper():
if flow.client_conn:
client = click.style(
strutils.escape_control_characters(
- flow.client_conn.address.host
- ),
- bold=True
+ repr(flow.client_conn.address)
+ )
)
elif flow.request.is_replay:
client = click.style("[replay]", fg="yellow", bold=True)
@@ -139,17 +153,23 @@ class Dumper():
url = flow.request.url
url = click.style(strutils.escape_control_characters(url), bold=True)
- httpversion = ""
+ http_version = ""
if flow.request.http_version not in ("HTTP/1.1", "HTTP/1.0"):
# We hide "normal" HTTP 1.
- httpversion = " " + flow.request.http_version
+ http_version = " " + flow.request.http_version
- line = "{stickycookie}{client} {method} {url}{httpversion}".format(
- stickycookie=stickycookie,
+ if self.flow_detail >= 2:
+ linebreak = "\n "
+ else:
+ linebreak = ""
+
+ line = "{client}: {linebreak}{stickycookie}{method} {url}{http_version}".format(
client=client,
+ stickycookie=stickycookie,
+ linebreak=linebreak,
method=method,
url=url,
- httpversion=httpversion
+ http_version=http_version
)
self.echo(line)
@@ -185,9 +205,14 @@ class Dumper():
size = human.pretty_size(len(flow.response.raw_content))
size = click.style(size, bold=True)
- arrows = click.style(" <<", bold=True)
+ arrows = click.style(" <<", bold=True)
+ if self.flow_detail == 1:
+ # This aligns the HTTP response code with the HTTP request method:
+ # 127.0.0.1:59519: GET http://example.com/
+ # << 304 Not Modified 0b
+ arrows = " " * (len(repr(flow.client_conn.address)) - 2) + arrows
- line = "{replay} {arrows} {code} {reason} {size}".format(
+ line = "{replay}{arrows} {code} {reason} {size}".format(
replay=replay,
arrows=arrows,
code=code,
@@ -211,25 +236,12 @@ class Dumper():
def match(self, f):
if self.flow_detail == 0:
return False
- if not self.filt:
+ if not self.filter:
return True
- elif f.match(self.filt):
+ elif f.match(self.filter):
return True
return False
- def configure(self, options):
- if options.filtstr:
- self.filt = filt.parse(options.filtstr)
- if not self.filt:
- raise exceptions.OptionsError(
- "Invalid filter expression: %s" % options.filtstr
- )
- else:
- self.filt = None
- self.flow_detail = options.flow_detail
- self.outfp = options.tfile
- self.showhost = options.showhost
-
def response(self, f):
if self.match(f):
self.echo_flow(f)
@@ -239,8 +251,7 @@ class Dumper():
self.echo_flow(f)
def tcp_message(self, f):
- # FIXME: Filter should be applied here
- if self.options.flow_detail == 0:
+ if not self.match(f):
return
message = f.messages[-1]
direction = "->" if message.from_client else "<-"
diff --git a/mitmproxy/builtins/filestreamer.py b/mitmproxy/builtins/filestreamer.py
index 97ddc7c4..ffa565ac 100644
--- a/mitmproxy/builtins/filestreamer.py
+++ b/mitmproxy/builtins/filestreamer.py
@@ -19,7 +19,7 @@ class FileStreamer:
self.stream = io.FilteredFlowWriter(f, filt)
self.active_flows = set()
- def configure(self, options):
+ def configure(self, options, updated):
# We're already streaming - stop the previous stream and restart
if self.stream:
self.done()
diff --git a/mitmproxy/builtins/replace.py b/mitmproxy/builtins/replace.py
index 83b96cee..74d30c05 100644
--- a/mitmproxy/builtins/replace.py
+++ b/mitmproxy/builtins/replace.py
@@ -8,7 +8,7 @@ class Replace:
def __init__(self):
self.lst = []
- def configure(self, options):
+ def configure(self, options, updated):
"""
.replacements is a list of tuples (fpat, rex, s):
diff --git a/mitmproxy/builtins/script.py b/mitmproxy/builtins/script.py
index ab068e47..c960dd1c 100644
--- a/mitmproxy/builtins/script.py
+++ b/mitmproxy/builtins/script.py
@@ -16,6 +16,19 @@ import watchdog.events
from watchdog.observers import polling
+class NS:
+ def __init__(self, ns):
+ self.__dict__["ns"] = ns
+
+ def __getattr__(self, key):
+ if key not in self.ns:
+ raise AttributeError("No such element: %s", key)
+ return self.ns[key]
+
+ def __setattr__(self, key, value):
+ self.__dict__["ns"][key] = value
+
+
def parse_command(command):
"""
Returns a (path, args) tuple.
@@ -74,18 +87,27 @@ def load_script(path, args):
ns = {'__file__': os.path.abspath(path)}
with scriptenv(path, args):
exec(code, ns, ns)
- return ns
+ return NS(ns)
class ReloadHandler(watchdog.events.FileSystemEventHandler):
def __init__(self, callback):
self.callback = callback
+ def filter(self, event):
+ if event.is_directory:
+ return False
+ if os.path.basename(event.src_path).startswith("."):
+ return False
+ return True
+
def on_modified(self, event):
- self.callback()
+ if self.filter(event):
+ self.callback()
def on_created(self, event):
- self.callback()
+ if self.filter(event):
+ self.callback()
class Script:
@@ -118,29 +140,35 @@ class Script:
# It's possible for ns to be un-initialised if we failed during
# configure
if self.ns is not None and not self.dead:
- func = self.ns.get(name)
+ func = getattr(self.ns, name, None)
if func:
with scriptenv(self.path, self.args):
- func(*args, **kwargs)
+ return func(*args, **kwargs)
def reload(self):
self.should_reload.set()
+ def load_script(self):
+ self.ns = load_script(self.path, self.args)
+ ret = self.run("start")
+ if ret:
+ self.ns = ret
+ self.run("start")
+
def tick(self):
if self.should_reload.is_set():
self.should_reload.clear()
ctx.log.info("Reloading script: %s" % self.name)
self.ns = load_script(self.path, self.args)
self.start()
- self.configure(self.last_options)
+ self.configure(self.last_options, self.last_options.keys())
else:
self.run("tick")
def start(self):
- self.ns = load_script(self.path, self.args)
- self.run("start")
+ self.load_script()
- def configure(self, options):
+ def configure(self, options, updated):
self.last_options = options
if not self.observer:
self.observer = polling.PollingObserver()
@@ -150,7 +178,7 @@ class Script:
os.path.dirname(self.path) or "."
)
self.observer.start()
- self.run("configure", options)
+ self.run("configure", options, updated)
def done(self):
self.run("done")
@@ -161,26 +189,27 @@ class ScriptLoader():
"""
An addon that manages loading scripts from options.
"""
- def configure(self, options):
- for s in options.scripts:
- if options.scripts.count(s) > 1:
- raise exceptions.OptionsError("Duplicate script: %s" % s)
-
- for a in ctx.master.addons.chain[:]:
- if isinstance(a, Script) and a.name not in options.scripts:
- ctx.log.info("Un-loading script: %s" % a.name)
- ctx.master.addons.remove(a)
-
- current = {}
- for a in ctx.master.addons.chain[:]:
- if isinstance(a, Script):
- current[a.name] = a
- ctx.master.addons.chain.remove(a)
-
- for s in options.scripts:
- if s in current:
- ctx.master.addons.chain.append(current[s])
- else:
- ctx.log.info("Loading script: %s" % s)
- sc = Script(s)
- ctx.master.addons.add(sc)
+ def configure(self, options, updated):
+ if "scripts" in updated:
+ for s in options.scripts:
+ if options.scripts.count(s) > 1:
+ raise exceptions.OptionsError("Duplicate script: %s" % s)
+
+ for a in ctx.master.addons.chain[:]:
+ if isinstance(a, Script) and a.name not in options.scripts:
+ ctx.log.info("Un-loading script: %s" % a.name)
+ ctx.master.addons.remove(a)
+
+ current = {}
+ for a in ctx.master.addons.chain[:]:
+ if isinstance(a, Script):
+ current[a.name] = a
+ ctx.master.addons.chain.remove(a)
+
+ for s in options.scripts:
+ if s in current:
+ ctx.master.addons.chain.append(current[s])
+ else:
+ ctx.log.info("Loading script: %s" % s)
+ sc = Script(s)
+ ctx.master.addons.add(options, sc)
diff --git a/mitmproxy/builtins/setheaders.py b/mitmproxy/builtins/setheaders.py
index 6bda3f55..4a784a1d 100644
--- a/mitmproxy/builtins/setheaders.py
+++ b/mitmproxy/builtins/setheaders.py
@@ -6,7 +6,7 @@ class SetHeaders:
def __init__(self):
self.lst = []
- def configure(self, options):
+ def configure(self, options, updated):
"""
options.setheaders is a tuple of (fpatt, header, value)
diff --git a/mitmproxy/builtins/stickyauth.py b/mitmproxy/builtins/stickyauth.py
index 1309911c..98fb65ed 100644
--- a/mitmproxy/builtins/stickyauth.py
+++ b/mitmproxy/builtins/stickyauth.py
@@ -10,7 +10,7 @@ class StickyAuth:
self.flt = None
self.hosts = {}
- def configure(self, options):
+ def configure(self, options, updated):
if options.stickyauth:
flt = filt.parse(options.stickyauth)
if not flt:
diff --git a/mitmproxy/builtins/stickycookie.py b/mitmproxy/builtins/stickycookie.py
index dc699bb4..88333d5c 100644
--- a/mitmproxy/builtins/stickycookie.py
+++ b/mitmproxy/builtins/stickycookie.py
@@ -32,7 +32,7 @@ class StickyCookie:
self.jar = collections.defaultdict(dict)
self.flt = None
- def configure(self, options):
+ def configure(self, options, updated):
if options.stickycookie:
flt = filt.parse(options.stickycookie)
if not flt:
diff --git a/mitmproxy/console/master.py b/mitmproxy/console/master.py
index f4617f62..fad4c375 100644
--- a/mitmproxy/console/master.py
+++ b/mitmproxy/console/master.py
@@ -242,7 +242,7 @@ class ConsoleMaster(flow.FlowMaster):
signals.pop_view_state.connect(self.sig_pop_view_state)
signals.push_view_state.connect(self.sig_push_view_state)
signals.sig_add_log.connect(self.sig_add_log)
- self.addons.add(*builtins.default_addons())
+ self.addons.add(options, *builtins.default_addons())
def __setattr__(self, name, value):
self.__dict__[name] = value
diff --git a/mitmproxy/ctx.py b/mitmproxy/ctx.py
index fcfdfd0b..5d2905fa 100644
--- a/mitmproxy/ctx.py
+++ b/mitmproxy/ctx.py
@@ -1,4 +1,4 @@
from typing import Callable # noqa
master = None # type: "mitmproxy.flow.FlowMaster"
-log = None # type: Callable[[str], None]
+log = None # type: "mitmproxy.controller.Log"
diff --git a/mitmproxy/dump.py b/mitmproxy/dump.py
index 4f34ab95..83f44d87 100644
--- a/mitmproxy/dump.py
+++ b/mitmproxy/dump.py
@@ -42,8 +42,8 @@ class DumpMaster(flow.FlowMaster):
def __init__(self, server, options):
flow.FlowMaster.__init__(self, options, server, flow.State())
self.has_errored = False
- self.addons.add(*builtins.default_addons())
- self.addons.add(dumper.Dumper())
+ self.addons.add(options, *builtins.default_addons())
+ self.addons.add(options, dumper.Dumper())
# This line is just for type hinting
self.options = self.options # type: Options
self.replay_ignore_params = options.replay_ignore_params
diff --git a/mitmproxy/filt.py b/mitmproxy/filt.py
index 8b647b22..fe817757 100644
--- a/mitmproxy/filt.py
+++ b/mitmproxy/filt.py
@@ -39,9 +39,12 @@ import functools
from mitmproxy.models.http import HTTPFlow
from mitmproxy.models.tcp import TCPFlow
+from mitmproxy.models.flow import Flow
+
from netlib import strutils
import pyparsing as pp
+from typing import Callable
def only(*types):
@@ -471,7 +474,11 @@ def _make():
bnf = _make()
+TFilter = Callable[[Flow], bool]
+
+
def parse(s):
+ # type: (str) -> TFilter
try:
filt = bnf.parseString(s, parseAll=True)[0]
filt.pattern = s
diff --git a/mitmproxy/optmanager.py b/mitmproxy/optmanager.py
index e94ef51d..140c7ca8 100644
--- a/mitmproxy/optmanager.py
+++ b/mitmproxy/optmanager.py
@@ -35,7 +35,7 @@ class OptManager(object):
self.__dict__["_initialized"] = True
@contextlib.contextmanager
- def rollback(self):
+ def rollback(self, updated):
old = self._opts.copy()
try:
yield
@@ -44,7 +44,7 @@ class OptManager(object):
self.errored.send(self, exc=e)
# Rollback
self.__dict__["_opts"] = old
- self.changed.send(self)
+ self.changed.send(self, updated=updated)
def __eq__(self, other):
return self._opts == other._opts
@@ -62,22 +62,22 @@ class OptManager(object):
if not self._initialized:
self._opts[attr] = value
return
- if attr not in self._opts:
- raise KeyError("No such option: %s" % attr)
- with self.rollback():
- self._opts[attr] = value
- self.changed.send(self)
+ self.update(**{attr: value})
+
+ def keys(self):
+ return set(self._opts.keys())
def get(self, k, d=None):
return self._opts.get(k, d)
def update(self, **kwargs):
+ updated = set(kwargs.keys())
for k in kwargs:
if k not in self._opts:
raise KeyError("No such option: %s" % k)
- with self.rollback():
+ with self.rollback(updated):
self._opts.update(kwargs)
- self.changed.send(self)
+ self.changed.send(self, updated=updated)
def setter(self, attr):
"""
diff --git a/mitmproxy/protocol/http2.py b/mitmproxy/protocol/http2.py
index 1285e10e..8308f44d 100644
--- a/mitmproxy/protocol/http2.py
+++ b/mitmproxy/protocol/http2.py
@@ -584,6 +584,8 @@ class Http2SingleStreamLayer(http._HttpTransmissionLayer, basethread.BaseThread)
except exceptions.ProtocolException as e: # pragma: no cover
self.log(repr(e), "info")
self.log(traceback.format_exc(), "debug")
+ except exceptions.Kill:
+ self.log("Connection killed", "info")
if not self.zombie:
self.zombie = time.time()
diff --git a/mitmproxy/proxy/config.py b/mitmproxy/proxy/config.py
index 7aa4c736..a74ba7e2 100644
--- a/mitmproxy/proxy/config.py
+++ b/mitmproxy/proxy/config.py
@@ -79,10 +79,10 @@ class ProxyConfig:
self.certstore = None
self.clientcerts = None
self.openssl_verification_mode_server = None
- self.configure(options)
+ self.configure(options, set(options.keys()))
options.changed.connect(self.configure)
- def configure(self, options):
+ def configure(self, options, updated):
conflict = all(
[
options.add_upstream_certs_to_client_chain,
diff --git a/mitmproxy/web/master.py b/mitmproxy/web/master.py
index 3d384612..9ddb61d4 100644
--- a/mitmproxy/web/master.py
+++ b/mitmproxy/web/master.py
@@ -136,7 +136,7 @@ class WebMaster(flow.FlowMaster):
def __init__(self, server, options):
super(WebMaster, self).__init__(options, server, WebState())
- self.addons.add(*builtins.default_addons())
+ self.addons.add(options, *builtins.default_addons())
self.app = app.Application(
self, self.options.wdebug, self.options.wauthenticator
)
diff --git a/netlib/strutils.py b/netlib/strutils.py
index 32e77927..96c8b10f 100644
--- a/netlib/strutils.py
+++ b/netlib/strutils.py
@@ -51,8 +51,7 @@ else:
def escape_control_characters(text, keep_spacing=True):
"""
- Replace all unicode C1 control characters from the given text with their respective control pictures.
- For example, a null byte is replaced with the unicode character "\u2400".
+ Replace all unicode C1 control characters from the given text with a single "."
Args:
keep_spacing: If True, tabs and newlines will not be replaced.
diff --git a/test/mitmproxy/builtins/test_anticache.py b/test/mitmproxy/builtins/test_anticache.py
index 5a00af03..ac321e26 100644
--- a/test/mitmproxy/builtins/test_anticache.py
+++ b/test/mitmproxy/builtins/test_anticache.py
@@ -8,9 +8,10 @@ from mitmproxy import options
class TestAntiCache(mastertest.MasterTest):
def test_simple(self):
s = state.State()
- m = master.FlowMaster(options.Options(anticache = True), None, s)
+ o = options.Options(anticache = True)
+ m = master.FlowMaster(o, None, s)
sa = anticache.AntiCache()
- m.addons.add(sa)
+ m.addons.add(o, sa)
f = tutils.tflow(resp=True)
self.invoke(m, "request", f)
diff --git a/test/mitmproxy/builtins/test_anticomp.py b/test/mitmproxy/builtins/test_anticomp.py
index 6bfd54bb..a5f5a270 100644
--- a/test/mitmproxy/builtins/test_anticomp.py
+++ b/test/mitmproxy/builtins/test_anticomp.py
@@ -8,9 +8,10 @@ from mitmproxy import options
class TestAntiComp(mastertest.MasterTest):
def test_simple(self):
s = state.State()
- m = master.FlowMaster(options.Options(anticomp = True), None, s)
+ o = options.Options(anticomp = True)
+ m = master.FlowMaster(o, None, s)
sa = anticomp.AntiComp()
- m.addons.add(sa)
+ m.addons.add(o, sa)
f = tutils.tflow(resp=True)
self.invoke(m, "request", f)
diff --git a/test/mitmproxy/builtins/test_dumper.py b/test/mitmproxy/builtins/test_dumper.py
index 57e3d036..6287fe86 100644
--- a/test/mitmproxy/builtins/test_dumper.py
+++ b/test/mitmproxy/builtins/test_dumper.py
@@ -15,26 +15,27 @@ class TestDumper(mastertest.MasterTest):
d = dumper.Dumper()
sio = StringIO()
- d.configure(dump.Options(tfile = sio, flow_detail = 0))
+ updated = set(["tfile", "flow_detail"])
+ d.configure(dump.Options(tfile = sio, flow_detail = 0), updated)
d.response(tutils.tflow())
assert not sio.getvalue()
- d.configure(dump.Options(tfile = sio, flow_detail = 4))
+ d.configure(dump.Options(tfile = sio, flow_detail = 4), updated)
d.response(tutils.tflow())
assert sio.getvalue()
sio = StringIO()
- d.configure(dump.Options(tfile = sio, flow_detail = 4))
+ d.configure(dump.Options(tfile = sio, flow_detail = 4), updated)
d.response(tutils.tflow(resp=True))
assert "<<" in sio.getvalue()
sio = StringIO()
- d.configure(dump.Options(tfile = sio, flow_detail = 4))
+ d.configure(dump.Options(tfile = sio, flow_detail = 4), updated)
d.response(tutils.tflow(err=True))
assert "<<" in sio.getvalue()
sio = StringIO()
- d.configure(dump.Options(tfile = sio, flow_detail = 4))
+ d.configure(dump.Options(tfile = sio, flow_detail = 4), updated)
flow = tutils.tflow()
flow.request = netlib.tutils.treq()
flow.request.stickycookie = True
@@ -47,7 +48,7 @@ class TestDumper(mastertest.MasterTest):
assert sio.getvalue()
sio = StringIO()
- d.configure(dump.Options(tfile = sio, flow_detail = 4))
+ d.configure(dump.Options(tfile = sio, flow_detail = 4), updated)
flow = tutils.tflow(resp=netlib.tutils.tresp(content=b"{"))
flow.response.headers["content-type"] = "application/json"
flow.response.status_code = 400
@@ -55,7 +56,7 @@ class TestDumper(mastertest.MasterTest):
assert sio.getvalue()
sio = StringIO()
- d.configure(dump.Options(tfile = sio))
+ d.configure(dump.Options(tfile = sio), updated)
flow = tutils.tflow()
flow.request.content = None
flow.response = models.HTTPResponse.wrap(netlib.tutils.tresp())
@@ -72,15 +73,13 @@ class TestContentView(mastertest.MasterTest):
s = state.State()
sio = StringIO()
- m = mastertest.RecordingMaster(
- dump.Options(
- flow_detail=4,
- verbosity=3,
- tfile=sio,
- ),
- None, s
+ o = dump.Options(
+ flow_detail=4,
+ verbosity=3,
+ tfile=sio,
)
+ m = mastertest.RecordingMaster(o, None, s)
d = dumper.Dumper()
- m.addons.add(d)
+ m.addons.add(o, d)
self.invoke(m, "response", tutils.tflow())
assert "Content viewer failed" in m.event_log[0][1]
diff --git a/test/mitmproxy/builtins/test_filestreamer.py b/test/mitmproxy/builtins/test_filestreamer.py
index c1d5947f..0e69b340 100644
--- a/test/mitmproxy/builtins/test_filestreamer.py
+++ b/test/mitmproxy/builtins/test_filestreamer.py
@@ -20,16 +20,13 @@ class TestStream(mastertest.MasterTest):
return list(r.stream())
s = state.State()
- m = master.FlowMaster(
- options.Options(
- outfile = (p, "wb")
- ),
- None,
- s
+ o = options.Options(
+ outfile = (p, "wb")
)
+ m = master.FlowMaster(o, None, s)
sa = filestreamer.FileStreamer()
- m.addons.add(sa)
+ m.addons.add(o, sa)
f = tutils.tflow(resp=True)
self.invoke(m, "request", f)
self.invoke(m, "response", f)
@@ -39,7 +36,7 @@ class TestStream(mastertest.MasterTest):
m.options.outfile = (p, "ab")
- m.addons.add(sa)
+ m.addons.add(o, sa)
f = tutils.tflow()
self.invoke(m, "request", f)
m.addons.remove(sa)
diff --git a/test/mitmproxy/builtins/test_replace.py b/test/mitmproxy/builtins/test_replace.py
index a0b4b722..5e70ce56 100644
--- a/test/mitmproxy/builtins/test_replace.py
+++ b/test/mitmproxy/builtins/test_replace.py
@@ -8,38 +8,38 @@ from mitmproxy import options
class TestReplace(mastertest.MasterTest):
def test_configure(self):
r = replace.Replace()
+ updated = set(["replacements"])
r.configure(options.Options(
replacements=[("one", "two", "three")]
- ))
+ ), updated)
tutils.raises(
"invalid filter pattern",
r.configure,
options.Options(
replacements=[("~b", "two", "three")]
- )
+ ),
+ updated
)
tutils.raises(
"invalid regular expression",
r.configure,
options.Options(
replacements=[("foo", "+", "three")]
- )
+ ),
+ updated
)
def test_simple(self):
s = state.State()
- m = master.FlowMaster(
- options.Options(
- replacements = [
- ("~q", "foo", "bar"),
- ("~s", "foo", "bar"),
- ]
- ),
- None,
- s
+ o = options.Options(
+ replacements = [
+ ("~q", "foo", "bar"),
+ ("~s", "foo", "bar"),
+ ]
)
+ m = master.FlowMaster(o, None, s)
sa = replace.Replace()
- m.addons.add(sa)
+ m.addons.add(o, sa)
f = tutils.tflow()
f.request.content = b"foo"
diff --git a/test/mitmproxy/builtins/test_script.py b/test/mitmproxy/builtins/test_script.py
index f37c7f94..2870fd17 100644
--- a/test/mitmproxy/builtins/test_script.py
+++ b/test/mitmproxy/builtins/test_script.py
@@ -48,39 +48,41 @@ def test_load_script():
"data/addonscripts/recorder.py"
), []
)
- assert ns["configure"]
+ assert ns.start
class TestScript(mastertest.MasterTest):
def test_simple(self):
s = state.State()
- m = master.FlowMaster(options.Options(), None, s)
+ o = options.Options()
+ m = master.FlowMaster(o, None, s)
sc = script.Script(
tutils.test_data.path(
"data/addonscripts/recorder.py"
)
)
- m.addons.add(sc)
- assert sc.ns["call_log"] == [
+ m.addons.add(o, sc)
+ assert sc.ns.call_log == [
("solo", "start", (), {}),
- ("solo", "configure", (options.Options(),), {})
+ ("solo", "configure", (o, o.keys()), {})
]
- sc.ns["call_log"] = []
+ sc.ns.call_log = []
f = tutils.tflow(resp=True)
self.invoke(m, "request", f)
- recf = sc.ns["call_log"][0]
+ recf = sc.ns.call_log[0]
assert recf[1] == "request"
def test_reload(self):
s = state.State()
- m = mastertest.RecordingMaster(options.Options(), None, s)
+ o = options.Options()
+ m = mastertest.RecordingMaster(o, None, s)
with tutils.tmpdir():
with open("foo.py", "w"):
pass
sc = script.Script("foo.py")
- m.addons.add(sc)
+ m.addons.add(o, sc)
for _ in range(100):
with open("foo.py", "a") as f:
@@ -93,19 +95,22 @@ class TestScript(mastertest.MasterTest):
def test_exception(self):
s = state.State()
- m = mastertest.RecordingMaster(options.Options(), None, s)
+ o = options.Options()
+ m = mastertest.RecordingMaster(o, None, s)
sc = script.Script(
tutils.test_data.path("data/addonscripts/error.py")
)
- m.addons.add(sc)
+ m.addons.add(o, sc)
f = tutils.tflow(resp=True)
self.invoke(m, "request", f)
assert m.event_log[0][0] == "error"
def test_duplicate_flow(self):
s = state.State()
- fm = master.FlowMaster(None, None, s)
+ o = options.Options()
+ fm = master.FlowMaster(o, None, s)
fm.addons.add(
+ o,
script.Script(
tutils.test_data.path("data/addonscripts/duplicate_flow.py")
)
@@ -116,6 +121,20 @@ class TestScript(mastertest.MasterTest):
assert not fm.state.view[0].request.is_replay
assert fm.state.view[1].request.is_replay
+ def test_addon(self):
+ s = state.State()
+ o = options.Options()
+ m = master.FlowMaster(o, None, s)
+ sc = script.Script(
+ tutils.test_data.path(
+ "data/addonscripts/addon.py"
+ )
+ )
+ m.addons.add(o, sc)
+ assert sc.ns.event_log == [
+ 'scriptstart', 'addonstart', 'addonconfigure'
+ ]
+
class TestScriptLoader(mastertest.MasterTest):
def test_simple(self):
@@ -123,7 +142,7 @@ class TestScriptLoader(mastertest.MasterTest):
o = options.Options(scripts=[])
m = master.FlowMaster(o, None, s)
sc = script.ScriptLoader()
- m.addons.add(sc)
+ m.addons.add(o, sc)
assert len(m.addons) == 1
o.update(
scripts = [
@@ -139,7 +158,7 @@ class TestScriptLoader(mastertest.MasterTest):
o = options.Options(scripts=["one", "one"])
m = master.FlowMaster(o, None, s)
sc = script.ScriptLoader()
- tutils.raises(exceptions.OptionsError, m.addons.add, sc)
+ tutils.raises(exceptions.OptionsError, m.addons.add, o, sc)
def test_order(self):
rec = tutils.test_data.path("data/addonscripts/recorder.py")
@@ -154,7 +173,7 @@ class TestScriptLoader(mastertest.MasterTest):
)
m = mastertest.RecordingMaster(o, None, s)
sc = script.ScriptLoader()
- m.addons.add(sc)
+ m.addons.add(o, sc)
debug = [(i[0], i[1]) for i in m.event_log if i[0] == "debug"]
assert debug == [
diff --git a/test/mitmproxy/builtins/test_setheaders.py b/test/mitmproxy/builtins/test_setheaders.py
index 4465719d..41c18360 100644
--- a/test/mitmproxy/builtins/test_setheaders.py
+++ b/test/mitmproxy/builtins/test_setheaders.py
@@ -8,19 +8,20 @@ from mitmproxy import options
class TestSetHeaders(mastertest.MasterTest):
def mkmaster(self, **opts):
s = state.State()
- m = mastertest.RecordingMaster(options.Options(**opts), None, s)
+ o = options.Options(**opts)
+ m = mastertest.RecordingMaster(o, None, s)
sh = setheaders.SetHeaders()
- m.addons.add(sh)
+ m.addons.add(o, sh)
return m, sh
def test_configure(self):
sh = setheaders.SetHeaders()
+ o = options.Options(
+ setheaders = [("~b", "one", "two")]
+ )
tutils.raises(
"invalid setheader filter pattern",
- sh.configure,
- options.Options(
- setheaders = [("~b", "one", "two")]
- )
+ sh.configure, o, o.keys()
)
def test_setheaders(self):
diff --git a/test/mitmproxy/builtins/test_stickyauth.py b/test/mitmproxy/builtins/test_stickyauth.py
index 9233f435..5757fb2d 100644
--- a/test/mitmproxy/builtins/test_stickyauth.py
+++ b/test/mitmproxy/builtins/test_stickyauth.py
@@ -8,9 +8,10 @@ from mitmproxy import options
class TestStickyAuth(mastertest.MasterTest):
def test_simple(self):
s = state.State()
- m = master.FlowMaster(options.Options(stickyauth = ".*"), None, s)
+ o = options.Options(stickyauth = ".*")
+ m = master.FlowMaster(o, None, s)
sa = stickyauth.StickyAuth()
- m.addons.add(sa)
+ m.addons.add(o, sa)
f = tutils.tflow(resp=True)
f.request.headers["authorization"] = "foo"
diff --git a/test/mitmproxy/builtins/test_stickycookie.py b/test/mitmproxy/builtins/test_stickycookie.py
index 81b540db..e9d92c83 100644
--- a/test/mitmproxy/builtins/test_stickycookie.py
+++ b/test/mitmproxy/builtins/test_stickycookie.py
@@ -14,22 +14,23 @@ def test_domain_match():
class TestStickyCookie(mastertest.MasterTest):
def mk(self):
s = state.State()
- m = master.FlowMaster(options.Options(stickycookie = ".*"), None, s)
+ o = options.Options(stickycookie = ".*")
+ m = master.FlowMaster(o, None, s)
sc = stickycookie.StickyCookie()
- m.addons.add(sc)
+ m.addons.add(o, sc)
return s, m, sc
def test_config(self):
sc = stickycookie.StickyCookie()
+ o = options.Options(stickycookie = "~b")
tutils.raises(
"invalid filter",
- sc.configure,
- options.Options(stickycookie = "~b")
+ sc.configure, o, o.keys()
)
def test_simple(self):
s, m, sc = self.mk()
- m.addons.add(sc)
+ m.addons.add(m.options, sc)
f = tutils.tflow(resp=True)
f.response.headers["set-cookie"] = "foo=bar"
diff --git a/test/mitmproxy/data/addonscripts/addon.py b/test/mitmproxy/data/addonscripts/addon.py
new file mode 100644
index 00000000..84173cb6
--- /dev/null
+++ b/test/mitmproxy/data/addonscripts/addon.py
@@ -0,0 +1,22 @@
+event_log = []
+
+
+class Addon:
+ @property
+ def event_log(self):
+ return event_log
+
+ def start(self):
+ event_log.append("addonstart")
+
+ def configure(self, options, updated):
+ event_log.append("addonconfigure")
+
+
+def configure(options, updated):
+ event_log.append("addonconfigure")
+
+
+def start():
+ event_log.append("scriptstart")
+ return Addon()
diff --git a/test/mitmproxy/data/addonscripts/recorder.py b/test/mitmproxy/data/addonscripts/recorder.py
index b6ac8d89..890e6f4e 100644
--- a/test/mitmproxy/data/addonscripts/recorder.py
+++ b/test/mitmproxy/data/addonscripts/recorder.py
@@ -2,24 +2,24 @@ from mitmproxy import controller
from mitmproxy import ctx
import sys
-call_log = []
-if len(sys.argv) > 1:
- name = sys.argv[1]
-else:
- name = "solo"
+class CallLogger:
+ call_log = []
-# Keep a log of all possible event calls
-evts = list(controller.Events) + ["configure"]
-for i in evts:
- def mkprox():
- evt = i
+ def __init__(self, name = "solo"):
+ self.name = name
- def prox(*args, **kwargs):
- lg = (name, evt, args, kwargs)
- if evt != "log":
- ctx.log.info(str(lg))
- call_log.append(lg)
- ctx.log.debug("%s %s" % (name, evt))
- return prox
- globals()[i] = mkprox()
+ def __getattr__(self, attr):
+ if attr in controller.Events:
+ def prox(*args, **kwargs):
+ lg = (self.name, attr, args, kwargs)
+ if attr != "log":
+ ctx.log.info(str(lg))
+ self.call_log.append(lg)
+ ctx.log.debug("%s %s" % (self.name, attr))
+ return prox
+ raise AttributeError
+
+
+def start():
+ return CallLogger(*sys.argv[1:])
diff --git a/test/mitmproxy/data/dumpfile-011 b/test/mitmproxy/data/dumpfile-011
index 2534ad89..936ac0cc 100644
--- a/test/mitmproxy/data/dumpfile-011
+++ b/test/mitmproxy/data/dumpfile-011
Binary files differ
diff --git a/test/mitmproxy/script/test_concurrent.py b/test/mitmproxy/script/test_concurrent.py
index 080746e8..a5f76994 100644
--- a/test/mitmproxy/script/test_concurrent.py
+++ b/test/mitmproxy/script/test_concurrent.py
@@ -23,7 +23,7 @@ class TestConcurrent(mastertest.MasterTest):
"data/addonscripts/concurrent_decorator.py"
)
)
- m.addons.add(sc)
+ m.addons.add(m.options, sc)
f1, f2 = tutils.tflow(), tutils.tflow()
self.invoke(m, "request", f1)
self.invoke(m, "request", f2)
diff --git a/test/mitmproxy/test_addons.py b/test/mitmproxy/test_addons.py
index 1861d4ac..a5085ea0 100644
--- a/test/mitmproxy/test_addons.py
+++ b/test/mitmproxy/test_addons.py
@@ -13,8 +13,9 @@ class TAddon:
def test_simple():
- m = controller.Master(options.Options())
+ o = options.Options()
+ m = controller.Master(o)
a = addons.Addons(m)
- a.add(TAddon("one"))
+ a.add(o, TAddon("one"))
assert a.has_addon("one")
assert not a.has_addon("two")
diff --git a/test/mitmproxy/test_examples.py b/test/mitmproxy/test_examples.py
index 0ec85f52..34fcc261 100644
--- a/test/mitmproxy/test_examples.py
+++ b/test/mitmproxy/test_examples.py
@@ -27,10 +27,11 @@ class RaiseMaster(master.FlowMaster):
def tscript(cmd, args=""):
+ o = options.Options()
cmd = example_dir.path(cmd) + " " + args
- m = RaiseMaster(options.Options(), None, state.State())
+ m = RaiseMaster(o, None, state.State())
sc = script.Script(cmd)
- m.addons.add(sc)
+ m.addons.add(o, sc)
return m, sc
diff --git a/test/mitmproxy/test_optmanager.py b/test/mitmproxy/test_optmanager.py
index 67f76ecd..8414e6b5 100644
--- a/test/mitmproxy/test_optmanager.py
+++ b/test/mitmproxy/test_optmanager.py
@@ -15,6 +15,8 @@ class TO(optmanager.OptManager):
def test_options():
o = TO(two="three")
+ assert o.keys() == set(["one", "two"])
+
assert o.one is None
assert o.two == "three"
o.one = "one"
@@ -29,7 +31,7 @@ def test_options():
rec = []
- def sub(opts):
+ def sub(opts, updated):
rec.append(copy.copy(opts))
o.changed.connect(sub)
@@ -68,7 +70,7 @@ def test_rollback():
rec = []
- def sub(opts):
+ def sub(opts, updated):
rec.append(copy.copy(opts))
recerr = []
@@ -76,7 +78,7 @@ def test_rollback():
def errsub(opts, **kwargs):
recerr.append(kwargs)
- def err(opts):
+ def err(opts, updated):
if opts.one == "ten":
raise exceptions.OptionsError()
diff --git a/test/mitmproxy/test_protocol_http2.py b/test/mitmproxy/test_protocol_http2.py
index afbffb67..aa096a72 100644
--- a/test/mitmproxy/test_protocol_http2.py
+++ b/test/mitmproxy/test_protocol_http2.py
@@ -30,7 +30,7 @@ logging.getLogger("PIL.PngImagePlugin").setLevel(logging.WARNING)
requires_alpn = pytest.mark.skipif(
not netlib.tcp.HAS_ALPN,
- reason="requires OpenSSL with ALPN support")
+ reason='requires OpenSSL with ALPN support')
class _Http2ServerBase(netlib_tservers.ServerTestBase):
@@ -80,7 +80,7 @@ class _Http2ServerBase(netlib_tservers.ServerTestBase):
print(traceback.format_exc())
break
- def handle_server_event(self, h2_conn, rfile, wfile):
+ def handle_server_event(self, event, h2_conn, rfile, wfile):
raise NotImplementedError()
@@ -88,7 +88,6 @@ class _Http2TestBase(object):
@classmethod
def setup_class(cls):
- cls.masteroptions = options.Options()
opts = cls.get_options()
cls.config = ProxyConfig(opts)
@@ -145,12 +144,14 @@ class _Http2TestBase(object):
wfile,
h2_conn,
stream_id=1,
- headers=[],
+ headers=None,
body=b'',
end_stream=None,
priority_exclusive=None,
priority_depends_on=None,
priority_weight=None):
+ if headers is None:
+ headers = []
if end_stream is None:
end_stream = (len(body) == 0)
@@ -172,12 +173,12 @@ class _Http2TestBase(object):
class _Http2Test(_Http2TestBase, _Http2ServerBase):
@classmethod
- def setup_class(self):
+ def setup_class(cls):
_Http2TestBase.setup_class()
_Http2ServerBase.setup_class()
@classmethod
- def teardown_class(self):
+ def teardown_class(cls):
_Http2TestBase.teardown_class()
_Http2ServerBase.teardown_class()
@@ -187,7 +188,7 @@ class TestSimple(_Http2Test):
request_body_buffer = b''
@classmethod
- def handle_server_event(self, event, h2_conn, rfile, wfile):
+ def handle_server_event(cls, event, h2_conn, rfile, wfile):
if isinstance(event, h2.events.ConnectionTerminated):
return False
elif isinstance(event, h2.events.RequestReceived):
@@ -214,7 +215,7 @@ class TestSimple(_Http2Test):
wfile.write(h2_conn.data_to_send())
wfile.flush()
elif isinstance(event, h2.events.DataReceived):
- self.request_body_buffer += event.data
+ cls.request_body_buffer += event.data
return True
def test_simple(self):
@@ -225,7 +226,7 @@ class TestSimple(_Http2Test):
client.wfile,
h2_conn,
headers=[
- (':authority', "127.0.0.1:%s" % self.server.server.address.port),
+ (':authority', "127.0.0.1:{}".format(self.server.server.address.port)),
(':method', 'GET'),
(':scheme', 'https'),
(':path', '/'),
@@ -269,7 +270,7 @@ class TestSimple(_Http2Test):
class TestRequestWithPriority(_Http2Test):
@classmethod
- def handle_server_event(self, event, h2_conn, rfile, wfile):
+ def handle_server_event(cls, event, h2_conn, rfile, wfile):
if isinstance(event, h2.events.ConnectionTerminated):
return False
elif isinstance(event, h2.events.RequestReceived):
@@ -301,14 +302,14 @@ class TestRequestWithPriority(_Http2Test):
client.wfile,
h2_conn,
headers=[
- (':authority', "127.0.0.1:%s" % self.server.server.address.port),
+ (':authority', "127.0.0.1:{}".format(self.server.server.address.port)),
(':method', 'GET'),
(':scheme', 'https'),
(':path', '/'),
],
- priority_exclusive = True,
- priority_depends_on = 42424242,
- priority_weight = 42,
+ priority_exclusive=True,
+ priority_depends_on=42424242,
+ priority_weight=42,
)
done = False
@@ -343,7 +344,7 @@ class TestRequestWithPriority(_Http2Test):
client.wfile,
h2_conn,
headers=[
- (':authority', "127.0.0.1:%s" % self.server.server.address.port),
+ (':authority', "127.0.0.1:{}".format(self.server.server.address.port)),
(':method', 'GET'),
(':scheme', 'https'),
(':path', '/'),
@@ -381,11 +382,11 @@ class TestPriority(_Http2Test):
priority_data = None
@classmethod
- def handle_server_event(self, event, h2_conn, rfile, wfile):
+ def handle_server_event(cls, event, h2_conn, rfile, wfile):
if isinstance(event, h2.events.ConnectionTerminated):
return False
elif isinstance(event, h2.events.PriorityUpdated):
- self.priority_data = (event.exclusive, event.depends_on, event.weight)
+ cls.priority_data = (event.exclusive, event.depends_on, event.weight)
elif isinstance(event, h2.events.RequestReceived):
import warnings
with warnings.catch_warnings():
@@ -415,7 +416,7 @@ class TestPriority(_Http2Test):
client.wfile,
h2_conn,
headers=[
- (':authority', "127.0.0.1:%s" % self.server.server.address.port),
+ (':authority', "127.0.0.1:{}".format(self.server.server.address.port)),
(':method', 'GET'),
(':scheme', 'https'),
(':path', '/'),
@@ -451,11 +452,11 @@ class TestPriorityWithExistingStream(_Http2Test):
priority_data = []
@classmethod
- def handle_server_event(self, event, h2_conn, rfile, wfile):
+ def handle_server_event(cls, event, h2_conn, rfile, wfile):
if isinstance(event, h2.events.ConnectionTerminated):
return False
elif isinstance(event, h2.events.PriorityUpdated):
- self.priority_data.append((event.exclusive, event.depends_on, event.weight))
+ cls.priority_data.append((event.exclusive, event.depends_on, event.weight))
elif isinstance(event, h2.events.RequestReceived):
assert not event.priority_updated
@@ -486,7 +487,7 @@ class TestPriorityWithExistingStream(_Http2Test):
client.wfile,
h2_conn,
headers=[
- (':authority', "127.0.0.1:%s" % self.server.server.address.port),
+ (':authority', "127.0.0.1:{}".format(self.server.server.address.port)),
(':method', 'GET'),
(':scheme', 'https'),
(':path', '/'),
@@ -527,7 +528,7 @@ class TestPriorityWithExistingStream(_Http2Test):
class TestStreamResetFromServer(_Http2Test):
@classmethod
- def handle_server_event(self, event, h2_conn, rfile, wfile):
+ def handle_server_event(cls, event, h2_conn, rfile, wfile):
if isinstance(event, h2.events.ConnectionTerminated):
return False
elif isinstance(event, h2.events.RequestReceived):
@@ -543,7 +544,7 @@ class TestStreamResetFromServer(_Http2Test):
client.wfile,
h2_conn,
headers=[
- (':authority', "127.0.0.1:%s" % self.server.server.address.port),
+ (':authority', "127.0.0.1:{}".format(self.server.server.address.port)),
(':method', 'GET'),
(':scheme', 'https'),
(':path', '/'),
@@ -578,7 +579,7 @@ class TestStreamResetFromServer(_Http2Test):
class TestBodySizeLimit(_Http2Test):
@classmethod
- def handle_server_event(self, event, h2_conn, rfile, wfile):
+ def handle_server_event(cls, event, h2_conn, rfile, wfile):
if isinstance(event, h2.events.ConnectionTerminated):
return False
return True
@@ -592,7 +593,7 @@ class TestBodySizeLimit(_Http2Test):
client.wfile,
h2_conn,
headers=[
- (':authority', "127.0.0.1:%s" % self.server.server.address.port),
+ (':authority', "127.0.0.1:{}".format(self.server.server.address.port)),
(':method', 'GET'),
(':scheme', 'https'),
(':path', '/'),
@@ -627,7 +628,7 @@ class TestBodySizeLimit(_Http2Test):
class TestPushPromise(_Http2Test):
@classmethod
- def handle_server_event(self, event, h2_conn, rfile, wfile):
+ def handle_server_event(cls, event, h2_conn, rfile, wfile):
if isinstance(event, h2.events.ConnectionTerminated):
return False
elif isinstance(event, h2.events.RequestReceived):
@@ -637,14 +638,14 @@ class TestPushPromise(_Http2Test):
h2_conn.send_headers(1, [(':status', '200')])
h2_conn.push_stream(1, 2, [
- (':authority', "127.0.0.1:%s" % self.port),
+ (':authority', "127.0.0.1:{}".format(cls.port)),
(':method', 'GET'),
(':scheme', 'https'),
(':path', '/pushed_stream_foo'),
('foo', 'bar')
])
h2_conn.push_stream(1, 4, [
- (':authority', "127.0.0.1:%s" % self.port),
+ (':authority', "127.0.0.1:{}".format(cls.port)),
(':method', 'GET'),
(':scheme', 'https'),
(':path', '/pushed_stream_bar'),
@@ -675,7 +676,7 @@ class TestPushPromise(_Http2Test):
client, h2_conn = self._setup_connection()
self._send_request(client.wfile, h2_conn, stream_id=1, headers=[
- (':authority', "127.0.0.1:%s" % self.server.server.address.port),
+ (':authority', "127.0.0.1:{}".format(self.server.server.address.port)),
(':method', 'GET'),
(':scheme', 'https'),
(':path', '/'),
@@ -728,7 +729,7 @@ class TestPushPromise(_Http2Test):
client, h2_conn = self._setup_connection()
self._send_request(client.wfile, h2_conn, stream_id=1, headers=[
- (':authority', "127.0.0.1:%s" % self.server.server.address.port),
+ (':authority', "127.0.0.1:{}".format(self.server.server.address.port)),
(':method', 'GET'),
(':scheme', 'https'),
(':path', '/'),
@@ -780,7 +781,7 @@ class TestPushPromise(_Http2Test):
class TestConnectionLost(_Http2Test):
@classmethod
- def handle_server_event(self, event, h2_conn, rfile, wfile):
+ def handle_server_event(cls, event, h2_conn, rfile, wfile):
if isinstance(event, h2.events.RequestReceived):
h2_conn.send_headers(1, [(':status', '200')])
wfile.write(h2_conn.data_to_send())
@@ -791,7 +792,7 @@ class TestConnectionLost(_Http2Test):
client, h2_conn = self._setup_connection()
self._send_request(client.wfile, h2_conn, stream_id=1, headers=[
- (':authority', "127.0.0.1:%s" % self.server.server.address.port),
+ (':authority', "127.0.0.1:{}".format(self.server.server.address.port)),
(':method', 'GET'),
(':scheme', 'https'),
(':path', '/'),
@@ -822,12 +823,12 @@ class TestConnectionLost(_Http2Test):
class TestMaxConcurrentStreams(_Http2Test):
@classmethod
- def setup_class(self):
+ def setup_class(cls):
_Http2TestBase.setup_class()
_Http2ServerBase.setup_class(h2_server_settings={h2.settings.MAX_CONCURRENT_STREAMS: 2})
@classmethod
- def handle_server_event(self, event, h2_conn, rfile, wfile):
+ def handle_server_event(cls, event, h2_conn, rfile, wfile):
if isinstance(event, h2.events.ConnectionTerminated):
return False
elif isinstance(event, h2.events.RequestReceived):
@@ -848,7 +849,7 @@ class TestMaxConcurrentStreams(_Http2Test):
# this will exceed MAX_CONCURRENT_STREAMS on the server connection
# and cause mitmproxy to throttle stream creation to the server
self._send_request(client.wfile, h2_conn, stream_id=id, headers=[
- (':authority', "127.0.0.1:%s" % self.server.server.address.port),
+ (':authority', "127.0.0.1:{}".format(self.server.server.address.port)),
(':method', 'GET'),
(':scheme', 'https'),
(':path', '/'),
@@ -883,7 +884,7 @@ class TestMaxConcurrentStreams(_Http2Test):
class TestConnectionTerminated(_Http2Test):
@classmethod
- def handle_server_event(self, event, h2_conn, rfile, wfile):
+ def handle_server_event(cls, event, h2_conn, rfile, wfile):
if isinstance(event, h2.events.RequestReceived):
h2_conn.close_connection(error_code=5, last_stream_id=42, additional_data=b'foobar')
wfile.write(h2_conn.data_to_send())
@@ -894,7 +895,7 @@ class TestConnectionTerminated(_Http2Test):
client, h2_conn = self._setup_connection()
self._send_request(client.wfile, h2_conn, headers=[
- (':authority', "127.0.0.1:%s" % self.server.server.address.port),
+ (':authority', "127.0.0.1:{}".format(self.server.server.address.port)),
(':method', 'GET'),
(':scheme', 'https'),
(':path', '/'),
diff --git a/test/mitmproxy/test_server.py b/test/mitmproxy/test_server.py
index 233af597..6230fc1f 100644
--- a/test/mitmproxy/test_server.py
+++ b/test/mitmproxy/test_server.py
@@ -291,7 +291,7 @@ class TestHTTP(tservers.HTTPProxyTest, CommonMixin, AppMixin):
s = script.Script(
tutils.test_data.path("data/addonscripts/stream_modify.py")
)
- self.master.addons.add(s)
+ self.master.addons.add(self.master.options, s)
d = self.pathod('200:b"foo"')
assert d.content == b"bar"
self.master.addons.remove(s)
@@ -523,7 +523,7 @@ class TestTransparent(tservers.TransparentProxyTest, CommonMixin, TcpMixin):
s = script.Script(
tutils.test_data.path("data/addonscripts/tcp_stream_modify.py")
)
- self.master.addons.add(s)
+ self.master.addons.add(self.master.options, s)
self._tcpproxy_on()
d = self.pathod('200:b"foo"')
self._tcpproxy_off()
diff --git a/test/mitmproxy/tservers.py b/test/mitmproxy/tservers.py
index f5119166..d364162c 100644
--- a/test/mitmproxy/tservers.py
+++ b/test/mitmproxy/tservers.py
@@ -34,7 +34,7 @@ class TestMaster(flow.FlowMaster):
s = ProxyServer(config)
state = flow.State()
flow.FlowMaster.__init__(self, opts, s, state)
- self.addons.add(*builtins.default_addons())
+ self.addons.add(opts, *builtins.default_addons())
self.apps.add(testapp, "testapp", 80)
self.apps.add(errapp, "errapp", 80)
self.clear_log()