diff options
27 files changed, 183 insertions, 170 deletions
diff --git a/mitmproxy/master.py b/mitmproxy/master.py index 2bc78f4b..b41e2a8d 100644 --- a/mitmproxy/master.py +++ b/mitmproxy/master.py @@ -10,6 +10,7 @@ from mitmproxy import exceptions from mitmproxy import command from mitmproxy import http from mitmproxy import log +from mitmproxy.net import server_spec from mitmproxy.proxy.protocol import http_replay from mitmproxy.types import basethread @@ -32,16 +33,25 @@ class Master: """ The master handles mitmproxy's main event loop. """ - def __init__(self, opts, server): - self.options = opts or options.Options() + def __init__(self, opts): + self.options = opts or options.Options() # type: options.Options self.commands = command.CommandManager(self) self.addons = addonmanager.AddonManager(self) self.event_queue = queue.Queue() self.should_exit = threading.Event() - self.server = server + self._server = None self.first_tick = True - channel = controller.Channel(self.event_queue, self.should_exit) - server.set_channel(channel) + + @property + def server(self): + return self._server + + @server.setter + def server(self, server): + server.set_channel( + controller.Channel(self.event_queue, self.should_exit) + ) + self._server = server @contextlib.contextmanager def handlecontext(self): @@ -71,7 +81,8 @@ class Master: def start(self): self.should_exit.clear() - ServerThread(self.server).start() + if self.server: + ServerThread(self.server).start() def run(self): self.start() @@ -101,7 +112,8 @@ class Master: return changed def shutdown(self): - self.server.shutdown() + if self.server: + self.server.shutdown() self.should_exit.set() self.addons.trigger("done") @@ -110,10 +122,10 @@ class Master: Loads a flow """ if isinstance(f, http.HTTPFlow): - if self.server and self.options.mode.startswith("reverse:"): - f.request.host = self.server.config.upstream_server.address[0] - f.request.port = self.server.config.upstream_server.address[1] - f.request.scheme = self.server.config.upstream_server.scheme + if self.options.mode.startswith("reverse:"): + _, upstream_spec = server_spec.parse_with_mode(self.options.mode) + f.request.host, f.request.port = upstream_spec.address + f.request.scheme = upstream_spec.scheme f.reply = controller.DummyReply() for e, o in eventsequence.iterate(f): self.addons.handle_lifecycle(e, o) @@ -168,7 +180,7 @@ class Master: f.request.headers.insert(0, "host", host) rt = http_replay.RequestReplayThread( - self.server.config, + self.options, f, self.event_queue, self.should_exit diff --git a/mitmproxy/options.py b/mitmproxy/options.py index 10aaee12..20151c19 100644 --- a/mitmproxy/options.py +++ b/mitmproxy/options.py @@ -516,24 +516,6 @@ class Options(optmanager.OptManager): "Limit which flows are displayed." ) - # Web options - self.add_option( - "web_open_browser", bool, True, - "Start a browser." - ) - self.add_option( - "web_debug", bool, False, - "Mitmweb debugging." - ) - self.add_option( - "web_port", int, 8081, - "Mitmweb port." - ) - self.add_option( - "web_iface", str, "127.0.0.1", - "Mitmweb interface." - ) - # Dump options self.add_option( "flow_detail", int, 1, diff --git a/mitmproxy/proxy/config.py b/mitmproxy/proxy/config.py index b809d89a..9458cd42 100644 --- a/mitmproxy/proxy/config.py +++ b/mitmproxy/proxy/config.py @@ -1,6 +1,6 @@ import os import re -from typing import Any +import typing from OpenSSL import SSL, crypto @@ -42,10 +42,11 @@ class ProxyConfig: self.certstore = None # type: certs.CertStore self.client_certs = None # type: str self.openssl_verification_mode_server = None # type: int + self.upstream_server = None # type: typing.Optional[server_spec.ServerSpec] self.configure(options, set(options.keys())) options.changed.connect(self.configure) - def configure(self, options: moptions.Options, updated: Any) -> None: + def configure(self, options: moptions.Options, updated: typing.Any) -> None: if options.add_upstream_certs_to_client_chain and not options.ssl_insecure: raise exceptions.OptionsError( "The verify-upstream-cert requires certificate verification to be disabled. " @@ -58,8 +59,10 @@ class ProxyConfig: else: self.openssl_verification_mode_server = SSL.VERIFY_PEER - self.check_ignore = HostMatcher(options.ignore_hosts) - self.check_tcp = HostMatcher(options.tcp_hosts) + if "ignore_hosts" in updated: + self.check_ignore = HostMatcher(options.ignore_hosts) + if "tcp_hosts" in updated: + self.check_tcp = HostMatcher(options.tcp_hosts) self.openssl_method_client, self.openssl_options_client = \ tcp.sslversion_choices[options.ssl_version_client] diff --git a/mitmproxy/proxy/protocol/http_replay.py b/mitmproxy/proxy/protocol/http_replay.py index 1aa91847..915c71c4 100644 --- a/mitmproxy/proxy/protocol/http_replay.py +++ b/mitmproxy/proxy/protocol/http_replay.py @@ -1,9 +1,15 @@ +import queue +import threading +import typing + from mitmproxy import log from mitmproxy import controller from mitmproxy import exceptions from mitmproxy import http from mitmproxy import flow +from mitmproxy import options from mitmproxy import connections +from mitmproxy.net import server_spec from mitmproxy.net.http import http1 from mitmproxy.types import basethread @@ -14,12 +20,19 @@ from mitmproxy.types import basethread class RequestReplayThread(basethread.BaseThread): name = "RequestReplayThread" - def __init__(self, config, f, event_queue, should_exit): + def __init__( + self, + opts: options.Options, + f: http.HTTPFlow, + event_queue: typing.Optional[queue.Queue], + should_exit: threading.Event + ) -> None: """ event_queue can be a queue or None, if no scripthooks should be processed. """ - self.config, self.f = config, f + self.options = opts + self.f = f f.live = True if event_queue: self.channel = controller.Channel(event_queue, should_exit) @@ -31,7 +44,7 @@ class RequestReplayThread(basethread.BaseThread): def run(self): r = self.f.request - bsl = self.config.options._processed.get("body_size_limit") + bsl = self.options._processed.get("body_size_limit") first_line_format_backup = r.first_line_format server = None try: @@ -45,9 +58,9 @@ class RequestReplayThread(basethread.BaseThread): if not self.f.response: # In all modes, we directly connect to the server displayed - if self.config.options.mode.startswith("upstream:"): - server_address = self.config.upstream_server.address - server = connections.ServerConnection(server_address, (self.config.options.listen_host, 0)) + if self.options.mode.startswith("upstream:"): + server_address = server_spec.parse_with_mode(self.options.mode)[1].address + server = connections.ServerConnection(server_address, (self.options.listen_host, 0)) server.connect() if r.scheme == "https": connect_request = http.make_connect_request((r.data.host, r.port)) @@ -61,7 +74,7 @@ class RequestReplayThread(basethread.BaseThread): if resp.status_code != 200: raise exceptions.ReplayException("Upstream server refuses CONNECT request") server.establish_ssl( - self.config.client_certs, + self.options.client_certs, sni=self.f.server_conn.sni ) r.first_line_format = "relative" @@ -71,12 +84,12 @@ class RequestReplayThread(basethread.BaseThread): server_address = (r.host, r.port) server = connections.ServerConnection( server_address, - (self.config.options.listen_host, 0) + (self.options.listen_host, 0) ) server.connect() if r.scheme == "https": server.establish_ssl( - self.config.client_certs, + self.options.client_certs, sni=self.f.server_conn.sni ) r.first_line_format = "relative" diff --git a/mitmproxy/test/taddons.py b/mitmproxy/test/taddons.py index 49142871..6160746a 100644 --- a/mitmproxy/test/taddons.py +++ b/mitmproxy/test/taddons.py @@ -1,12 +1,11 @@ -import sys import contextlib +import sys import mitmproxy.master import mitmproxy.options -from mitmproxy import proxy from mitmproxy import addonmanager -from mitmproxy import eventsequence from mitmproxy import command +from mitmproxy import eventsequence from mitmproxy.addons import script @@ -59,10 +58,11 @@ class context: handlers can run as they would within mitmproxy. The context also provides a number of helper methods for common testing scenarios. """ - def __init__(self, master = None, options = None): + + def __init__(self, master=None, options=None): options = options or mitmproxy.options.Options() self.master = master or RecordingMaster( - options, proxy.DummyServer(options) + options ) self.options = self.master.options self.wrapped = None diff --git a/mitmproxy/tools/console/master.py b/mitmproxy/tools/console/master.py index 8c8cfe61..ef3ab0b3 100644 --- a/mitmproxy/tools/console/master.py +++ b/mitmproxy/tools/console/master.py @@ -28,18 +28,11 @@ from mitmproxy.tools.console import window class ConsoleMaster(master.Master): - def __init__(self, options, server): - super().__init__(options, server) - - if not sys.stdout.isatty(): - print("Error: mitmproxy's console interface requires a tty. " - "Please run mitmproxy in an interactive shell environment.", file=sys.stderr) - sys.exit(1) + def __init__(self, opts): + super().__init__(opts) self.view = view.View() # type: view.View self.stream_path = None - # This line is just for type hinting - self.options = self.options # type: Options self.keymap = keymap.Keymap(self) defaultkeys.map(self.keymap) self.options.errored.connect(self.options_error) @@ -160,10 +153,10 @@ class ConsoleMaster(master.Master): self.ui.start() os.unlink(name) - def set_palette(self, options, updated): + def set_palette(self, opts, updated): self.ui.register_palette( - palettes.palettes[options.console_palette].palette( - options.console_palette_transparent + palettes.palettes[opts.console_palette].palette( + opts.console_palette_transparent ) ) self.ui.clear() @@ -178,6 +171,11 @@ class ConsoleMaster(master.Master): self.loop.process_input([key]) def run(self): + if not sys.stdout.isatty(): + print("Error: mitmproxy's console interface requires a tty. " + "Please run mitmproxy in an interactive shell environment.", file=sys.stderr) + sys.exit(1) + self.ui = urwid.raw_display.Screen() self.ui.set_terminal_properties(256) self.set_palette(self.options, None) diff --git a/mitmproxy/tools/console/statusbar.py b/mitmproxy/tools/console/statusbar.py index 7628c475..5bfc611c 100644 --- a/mitmproxy/tools/console/statusbar.py +++ b/mitmproxy/tools/console/statusbar.py @@ -257,11 +257,11 @@ class StatusBar(urwid.WidgetWrap): ('heading', ("%s %s [%s/%s]" % (arrow, marked, offset, fc)).ljust(11)), ] - if self.master.server.bound: - host = self.master.server.address[0] - if host == "0.0.0.0": + if self.master.options.server: + host = self.master.options.listen_host + if host == "0.0.0.0" or host == "": host = "*" - boundaddr = "[%s:%s]" % (host, self.master.server.address[1]) + boundaddr = "[%s:%s]" % (host, self.master.options.listen_port) else: boundaddr = "" t.extend(self.get_status()) diff --git a/mitmproxy/tools/dump.py b/mitmproxy/tools/dump.py index 4d0ccf4b..af04f8a3 100644 --- a/mitmproxy/tools/dump.py +++ b/mitmproxy/tools/dump.py @@ -18,11 +18,10 @@ class DumpMaster(master.Master): def __init__( self, options: options.Options, - server, with_termlog=True, with_dumper=True, ) -> None: - master.Master.__init__(self, options, server) + super().__init__(options) self.errorcheck = ErrorCheck() if with_termlog: self.addons.add(termlog.TermLog(), termstatus.TermStatus()) diff --git a/mitmproxy/tools/main.py b/mitmproxy/tools/main.py index 1575de98..e8cdffca 100644 --- a/mitmproxy/tools/main.py +++ b/mitmproxy/tools/main.py @@ -1,22 +1,25 @@ from __future__ import print_function # this is here for the version check to work on Python 2. + import sys -# This must be at the very top, before importing anything else that might break! -# Keep all other imports below with the 'noqa' magic comment. if sys.version_info < (3, 5): + # This must be before any mitmproxy imports, as they already break! + # Keep all other imports below with the 'noqa' magic comment. print("#" * 49, file=sys.stderr) print("# mitmproxy only supports Python 3.5 and above! #", file=sys.stderr) print("#" * 49, file=sys.stderr) +import argparse # noqa import os # noqa import signal # noqa +import typing # noqa from mitmproxy.tools import cmdline # noqa -from mitmproxy import exceptions # noqa +from mitmproxy import exceptions, master # noqa from mitmproxy import options # noqa from mitmproxy import optmanager # noqa from mitmproxy import proxy # noqa -from mitmproxy import log # noqa +from mitmproxy import log # noqa from mitmproxy.utils import debug # noqa @@ -53,7 +56,12 @@ def process_options(parser, opts, args): return proxy.config.ProxyConfig(opts) -def run(MasterKlass, args, extra=None): # pragma: no cover +def run( + master_cls: typing.Type[master.Master], + make_parser: typing.Callable[[options.Options], argparse.ArgumentParser], + arguments: typing.Sequence[str], + extra=typing.Callable[[typing.Any], dict] +): # pragma: no cover """ extra: Extra argument processing callable which returns a dict of options. @@ -61,12 +69,14 @@ def run(MasterKlass, args, extra=None): # pragma: no cover debug.register_info_dumpers() opts = options.Options() - parser = cmdline.mitmdump(opts) - args = parser.parse_args(args) - master = None + master = master_cls(opts) + + parser = make_parser(opts) + args = parser.parse_args(arguments) try: unknown = optmanager.load_paths(opts, args.conf) pconf = process_options(parser, opts, args) + server = None # type: typing.Any if pconf.options.server: try: server = proxy.server.ProxyServer(pconf) @@ -76,7 +86,7 @@ def run(MasterKlass, args, extra=None): # pragma: no cover else: server = proxy.server.DummyServer(pconf) - master = MasterKlass(opts, server) + master.server = server master.addons.trigger("configure", opts.keys()) master.addons.trigger("tick") remaining = opts.update_known(**unknown) @@ -114,7 +124,7 @@ def mitmproxy(args=None): # pragma: no cover assert_utf8_env() from mitmproxy.tools import console - run(console.master.ConsoleMaster, args) + run(console.master.ConsoleMaster, cmdline.mitmproxy, args) def mitmdump(args=None): # pragma: no cover @@ -124,16 +134,16 @@ def mitmdump(args=None): # pragma: no cover if args.filter_args: v = " ".join(args.filter_args) return dict( - view_filter = v, - save_stream_filter = v, + view_filter=v, + save_stream_filter=v, ) return {} - m = run(dump.DumpMaster, args, extra) + m = run(dump.DumpMaster, cmdline.mitmdump, args, extra) if m and m.errorcheck.has_errored: sys.exit(1) def mitmweb(args=None): # pragma: no cover from mitmproxy.tools import web - run(web.master.WebMaster, args) + run(web.master.WebMaster, cmdline.mitmweb, args) diff --git a/mitmproxy/tools/web/master.py b/mitmproxy/tools/web/master.py index dc5b2627..b13aeff9 100644 --- a/mitmproxy/tools/web/master.py +++ b/mitmproxy/tools/web/master.py @@ -13,12 +13,12 @@ from mitmproxy.addons import termlog from mitmproxy.addons import view from mitmproxy.addons import termstatus from mitmproxy.options import Options # noqa -from mitmproxy.tools.web import app +from mitmproxy.tools.web import app, webaddons class WebMaster(master.Master): - def __init__(self, options, server, with_termlog=True): - super().__init__(options, server) + def __init__(self, options, with_termlog=True): + super().__init__(options) self.view = view.View() self.view.sig_view_add.connect(self._sig_view_add) self.view.sig_view_remove.connect(self._sig_view_remove) @@ -34,6 +34,7 @@ class WebMaster(master.Master): self.addons.add(*addons.default_addons()) self.addons.add( + webaddons.WebAddon(), intercept.Intercept(), readfile.ReadFile(), self.view, @@ -44,8 +45,6 @@ class WebMaster(master.Master): self.app = app.Application( self, self.options.web_debug ) - # This line is just for type hinting - self.options = self.options # type: Options def _sig_view_add(self, view, flow): app.ClientConnection.broadcast( diff --git a/mitmproxy/tools/web/webaddons.py b/mitmproxy/tools/web/webaddons.py new file mode 100644 index 00000000..6b52188c --- /dev/null +++ b/mitmproxy/tools/web/webaddons.py @@ -0,0 +1,18 @@ +class WebAddon: + def load(self, loader): + loader.add_option( + "web_open_browser", bool, True, + "Start a browser." + ) + loader.add_option( + "web_debug", bool, False, + "Enable mitmweb debugging." + ) + loader.add_option( + "web_port", int, 8081, + "Web UI port." + ) + loader.add_option( + "web_iface", str, "127.0.0.1", + "Web UI interface." + ) diff --git a/test/filename_matching.py b/test/filename_matching.py index 51cedf03..e74848d4 100644 --- a/test/filename_matching.py +++ b/test/filename_matching.py @@ -22,7 +22,7 @@ def check_src_files_have_test(): def check_test_files_have_src(): unknown_test_files = [] - excluded = ['test/mitmproxy/data/', 'test/mitmproxy/net/data/', '/tservers.py'] + excluded = ['test/mitmproxy/data/', 'test/mitmproxy/net/data/', '/tservers.py', '/conftest.py'] test_files = glob.glob('test/mitmproxy/**/*.py', recursive=True) + glob.glob('test/pathod/**/*.py', recursive=True) test_files = [f for f in test_files if os.path.basename(f) != '__init__.py'] test_files = [f for f in test_files if not any(os.path.normpath(p) in f for p in excluded)] diff --git a/test/mitmproxy/addons/test_termstatus.py b/test/mitmproxy/addons/test_termstatus.py index 2debaff5..5f960a1c 100644 --- a/test/mitmproxy/addons/test_termstatus.py +++ b/test/mitmproxy/addons/test_termstatus.py @@ -1,3 +1,4 @@ +from mitmproxy import proxy from mitmproxy.addons import termstatus from mitmproxy.test import taddons @@ -5,6 +6,7 @@ from mitmproxy.test import taddons def test_configure(): ts = termstatus.TermStatus() with taddons.context() as ctx: + ctx.master.server = proxy.DummyServer() ctx.configure(ts, server=False) ts.running() assert not ctx.master.logs diff --git a/test/mitmproxy/proxy/protocol/test_http2.py b/test/mitmproxy/proxy/protocol/test_http2.py index 583e6e27..5e6fa701 100644 --- a/test/mitmproxy/proxy/protocol/test_http2.py +++ b/test/mitmproxy/proxy/protocol/test_http2.py @@ -8,7 +8,6 @@ import pytest import h2 from mitmproxy import options -from mitmproxy.proxy.config import ProxyConfig import mitmproxy.net from ...net import tservers as net_tservers @@ -89,10 +88,8 @@ class _Http2TestBase: @classmethod def setup_class(cls): - opts = cls.get_options() - cls.config = ProxyConfig(opts) - - tmaster = tservers.TestMaster(opts, cls.config) + cls.options = cls.get_options() + tmaster = tservers.TestMaster(cls.options) cls.proxy = tservers.ProxyThread(tmaster) cls.proxy.start() @@ -319,7 +316,7 @@ class TestRequestWithPriority(_Http2Test): (False, (None, None, None), (None, None, None)), ]) def test_request_with_priority(self, http2_priority_enabled, priority, expected_priority): - self.config.options.http2_priority = http2_priority_enabled + self.options.http2_priority = http2_priority_enabled h2_conn = self.setup_connection() @@ -397,7 +394,7 @@ class TestPriority(_Http2Test): (False, (True, 42424242, 42), []), ]) def test_priority(self, prioritize_before, http2_priority_enabled, priority, expected_priority): - self.config.options.http2_priority = http2_priority_enabled + self.options.http2_priority = http2_priority_enabled self.__class__.priority_data = [] h2_conn = self.setup_connection() @@ -508,8 +505,10 @@ class TestBodySizeLimit(_Http2Test): return True def test_body_size_limit(self): - self.config.options.body_size_limit = "20" - self.config.options._processed["body_size_limit"] = 20 + self.options.body_size_limit = "20" + + # FIXME: This should not be required? + self.options._processed["body_size_limit"] = 20 h2_conn = self.setup_connection() diff --git a/test/mitmproxy/proxy/protocol/test_websocket.py b/test/mitmproxy/proxy/protocol/test_websocket.py index 58857f92..460d85f8 100644 --- a/test/mitmproxy/proxy/protocol/test_websocket.py +++ b/test/mitmproxy/proxy/protocol/test_websocket.py @@ -7,7 +7,6 @@ from mitmproxy import options from mitmproxy import exceptions from mitmproxy.http import HTTPFlow from mitmproxy.websocket import WebSocketFlow -from mitmproxy.proxy.config import ProxyConfig from mitmproxy.net import tcp from mitmproxy.net import http @@ -49,10 +48,8 @@ class _WebSocketTestBase: @classmethod def setup_class(cls): - opts = cls.get_options() - cls.config = ProxyConfig(opts) - - tmaster = tservers.TestMaster(opts, cls.config) + cls.options = cls.get_options() + tmaster = tservers.TestMaster(cls.options) cls.proxy = tservers.ProxyThread(tmaster) cls.proxy.start() diff --git a/test/mitmproxy/proxy/test_server.py b/test/mitmproxy/proxy/test_server.py index 4cae756a..562f822c 100644 --- a/test/mitmproxy/proxy/test_server.py +++ b/test/mitmproxy/proxy/test_server.py @@ -117,13 +117,12 @@ class TcpMixin: def _ignore_on(self): assert not hasattr(self, "_ignore_backup") - self._ignore_backup = self.config.check_ignore - self.config.check_ignore = HostMatcher( - [".+:%s" % self.server.port] + self.config.check_ignore.patterns) + self._ignore_backup = self.options.ignore_hosts + self.options.ignore_hosts = [".+:%s" % self.server.port] + self.options.ignore_hosts def _ignore_off(self): assert hasattr(self, "_ignore_backup") - self.config.check_ignore = self._ignore_backup + self.options.ignore_hosts = self._ignore_backup del self._ignore_backup def test_ignore(self): @@ -163,13 +162,12 @@ class TcpMixin: def _tcpproxy_on(self): assert not hasattr(self, "_tcpproxy_backup") - self._tcpproxy_backup = self.config.check_tcp - self.config.check_tcp = HostMatcher( - [".+:%s" % self.server.port] + self.config.check_tcp.patterns) + self._tcpproxy_backup = self.options.tcp_hosts + self.options.tcp_hosts = [".+:%s" % self.server.port] + self.options.tcp_hosts def _tcpproxy_off(self): assert hasattr(self, "_tcpproxy_backup") - self.config.check_tcp = self._tcpproxy_backup + self.options.tcp_hosts = self._tcpproxy_backup del self._tcpproxy_backup def test_tcp(self): @@ -194,7 +192,8 @@ class TcpMixin: i2_cert = certs.SSLCert(i2.sslinfo.certchain[0]) n_cert = certs.SSLCert(n.sslinfo.certchain[0]) - assert i_cert == i2_cert == n_cert + assert i_cert == i2_cert + assert i_cert != n_cert # Make sure that TCP messages are in the event log. # Re-enable and fix this when we start keeping TCPFlows in the state. @@ -353,22 +352,22 @@ class TestHTTPS(tservers.HTTPProxyTest, CommonMixin, TcpMixin): def test_clientcert_file(self): try: - self.config.client_certs = os.path.join( + self.options.client_certs = os.path.join( tutils.test_data.path("mitmproxy/data/clientcert"), "client.pem") f = self.pathod("304") assert f.status_code == 304 assert self.server.last_log()["request"]["clientcert"]["keyinfo"] finally: - self.config.client_certs = None + self.options.client_certs = None def test_clientcert_dir(self): try: - self.config.client_certs = tutils.test_data.path("mitmproxy/data/clientcert") + self.options.client_certs = tutils.test_data.path("mitmproxy/data/clientcert") f = self.pathod("304") assert f.status_code == 304 assert self.server.last_log()["request"]["clientcert"]["keyinfo"] finally: - self.config.client_certs = None + self.options.client_certs = None def test_error_post_connect(self): p = self.pathoc() @@ -412,7 +411,7 @@ class TestHTTPSUpstreamServerVerificationWTrustedCert(tservers.HTTPProxyTest): return p.request("get:/p/242") def test_verification_w_cadir(self): - self.config.options.update( + self.options.update( ssl_insecure=False, ssl_verify_upstream_trusted_cadir=tutils.test_data.path( "mitmproxy/data/servercert/" @@ -422,7 +421,7 @@ class TestHTTPSUpstreamServerVerificationWTrustedCert(tservers.HTTPProxyTest): assert self._request().status_code == 242 def test_verification_w_pemfile(self): - self.config.options.update( + self.options.update( ssl_insecure=False, ssl_verify_upstream_trusted_cadir=None, ssl_verify_upstream_trusted_ca=tutils.test_data.path( @@ -458,7 +457,7 @@ class TestHTTPSUpstreamServerVerificationWBadCert(tservers.HTTPProxyTest): return opts def test_no_verification_w_bad_cert(self): - self.config.options.ssl_insecure = True + self.options.ssl_insecure = True r = self._request() assert r.status_code == 242 @@ -466,7 +465,7 @@ class TestHTTPSUpstreamServerVerificationWBadCert(tservers.HTTPProxyTest): # We only test for a single invalid cert here. # Actual testing of different root-causes (invalid hostname, expired, ...) # is done in mitmproxy.net. - self.config.options.ssl_insecure = False + self.options.ssl_insecure = False r = self._request() assert r.status_code == 502 assert b"Certificate Verification Error" in r.raw_content @@ -493,7 +492,7 @@ class TestReverse(tservers.ReverseProxyTest, CommonMixin, TcpMixin): reverse = True def test_host_header(self): - self.config.options.keep_host_header = True + self.options.keep_host_header = True p = self.pathoc() with p.connect(): resp = p.request("get:/p/200:h'Host'='example.com'") @@ -503,7 +502,7 @@ class TestReverse(tservers.ReverseProxyTest, CommonMixin, TcpMixin): assert req.host_header == "example.com" def test_overridden_host_header(self): - self.config.options.keep_host_header = False # default value + self.options.keep_host_header = False # default value p = self.pathoc() with p.connect(): resp = p.request("get:/p/200:h'Host'='example.com'") diff --git a/test/mitmproxy/test_addonmanager.py b/test/mitmproxy/test_addonmanager.py index fc048571..accf48e0 100644 --- a/test/mitmproxy/test_addonmanager.py +++ b/test/mitmproxy/test_addonmanager.py @@ -6,7 +6,6 @@ from mitmproxy import exceptions from mitmproxy import options from mitmproxy import command from mitmproxy import master -from mitmproxy import proxy from mitmproxy.test import taddons from mitmproxy.test import tflow @@ -51,7 +50,7 @@ def test_command(): def test_halt(): o = options.Options() - m = master.Master(o, proxy.DummyServer(o)) + m = master.Master(o) a = addonmanager.AddonManager(m) halt = THalt() end = TAddon("end") @@ -68,7 +67,7 @@ def test_halt(): def test_lifecycle(): o = options.Options() - m = master.Master(o, proxy.DummyServer(o)) + m = master.Master(o) a = addonmanager.AddonManager(m) a.add(TAddon("one")) @@ -141,7 +140,7 @@ def test_simple(): def test_load_option(): o = options.Options() - m = master.Master(o, proxy.DummyServer(o)) + m = master.Master(o) a = addonmanager.AddonManager(m) a.add(AOption()) assert "custom_option" in m.options._options @@ -149,7 +148,7 @@ def test_load_option(): def test_nesting(): o = options.Options() - m = master.Master(o, proxy.DummyServer(o)) + m = master.Master(o) a = addonmanager.AddonManager(m) a.add( diff --git a/test/mitmproxy/test_controller.py b/test/mitmproxy/test_controller.py index 2e13d298..e840380a 100644 --- a/test/mitmproxy/test_controller.py +++ b/test/mitmproxy/test_controller.py @@ -30,7 +30,8 @@ class TestMaster: assert ctx.master.should_exit.is_set() def test_server_simple(self): - m = master.Master(None, proxy.DummyServer(None)) + m = master.Master(None) + m.server = proxy.DummyServer() m.start() m.shutdown() m.start() diff --git a/test/mitmproxy/test_flow.py b/test/mitmproxy/test_flow.py index 0b04c4c1..7f9d577b 100644 --- a/test/mitmproxy/test_flow.py +++ b/test/mitmproxy/test_flow.py @@ -6,13 +6,11 @@ from mitmproxy.test import tflow, tutils import mitmproxy.io from mitmproxy import flowfilter from mitmproxy import options -from mitmproxy.proxy import config from mitmproxy.io import tnetstring from mitmproxy.exceptions import FlowReadException, ReplayException, ControlException from mitmproxy import flow from mitmproxy import http from mitmproxy.net import http as net_http -from mitmproxy.proxy.server import DummyServer from mitmproxy import master from . import tservers @@ -93,8 +91,7 @@ class TestFlowMaster: opts = options.Options( mode="reverse:https://use-this-domain" ) - conf = config.ProxyConfig(opts) - fm = master.Master(opts, DummyServer(conf)) + fm = master.Master(opts) fm.addons.add(s) f = tflow.tflow(resp=True) fm.load_flow(f) @@ -102,8 +99,7 @@ class TestFlowMaster: def test_replay(self): opts = options.Options() - conf = config.ProxyConfig(opts) - fm = master.Master(opts, DummyServer(conf)) + fm = master.Master(opts) f = tflow.tflow(resp=True) f.request.content = None with pytest.raises(ReplayException, match="missing"): @@ -131,7 +127,7 @@ class TestFlowMaster: def test_all(self): s = tservers.TestState() - fm = master.Master(None, DummyServer()) + fm = master.Master(None) fm.addons.add(s) f = tflow.tflow(req=None) fm.addons.handle_lifecycle("clientconnect", f.client_conn) diff --git a/test/mitmproxy/tools/console/conftest.py b/test/mitmproxy/tools/console/conftest.py deleted file mode 100644 index afd94c6a..00000000 --- a/test/mitmproxy/tools/console/conftest.py +++ /dev/null @@ -1,9 +0,0 @@ -from unittest import mock - -import pytest - - -@pytest.fixture(scope="module", autouse=True) -def definitely_atty(): - with mock.patch("sys.stdout.isatty", lambda: True): - yield diff --git a/test/mitmproxy/tools/console/test_master.py b/test/mitmproxy/tools/console/test_master.py index ef357c76..3aa0dc54 100644 --- a/test/mitmproxy/tools/console/test_master.py +++ b/test/mitmproxy/tools/console/test_master.py @@ -1,7 +1,6 @@ import urwid from mitmproxy import options -from mitmproxy import proxy from mitmproxy.test import tflow from mitmproxy.test import tutils from mitmproxy.tools import console @@ -30,7 +29,7 @@ class TestMaster(tservers.MasterTest): if "verbosity" not in opts: opts["verbosity"] = 'warn' o = options.Options(**opts) - m = console.master.ConsoleMaster(o, proxy.DummyServer()) + m = console.master.ConsoleMaster(o) m.addons.trigger("configure", o.keys()) return m diff --git a/test/mitmproxy/tools/console/test_statusbar.py b/test/mitmproxy/tools/console/test_statusbar.py index 55a3c4a0..2f7825c9 100644 --- a/test/mitmproxy/tools/console/test_statusbar.py +++ b/test/mitmproxy/tools/console/test_statusbar.py @@ -1,4 +1,4 @@ -from mitmproxy import options, proxy +from mitmproxy import options from mitmproxy.tools.console import statusbar, master @@ -26,7 +26,7 @@ def test_statusbar(monkeypatch): scripts=["nonexistent"], save_stream_file="foo", ) - m = master.ConsoleMaster(o, proxy.DummyServer()) + m = master.ConsoleMaster(o) monkeypatch.setattr(m.addons.get("clientplayback"), "count", lambda: 42) monkeypatch.setattr(m.addons.get("serverplayback"), "count", lambda: 42) diff --git a/test/mitmproxy/tools/test_cmdline.py b/test/mitmproxy/tools/test_cmdline.py index 65cfeb07..e247dc1d 100644 --- a/test/mitmproxy/tools/test_cmdline.py +++ b/test/mitmproxy/tools/test_cmdline.py @@ -1,7 +1,8 @@ import argparse -from mitmproxy.tools import cmdline -from mitmproxy.tools import main + from mitmproxy import options +from mitmproxy.tools import cmdline, web, dump, console +from mitmproxy.tools import main def test_common(): @@ -14,17 +15,20 @@ def test_common(): def test_mitmproxy(): opts = options.Options() + console.master.ConsoleMaster(opts) ap = cmdline.mitmproxy(opts) assert ap def test_mitmdump(): opts = options.Options() + dump.DumpMaster(opts) ap = cmdline.mitmdump(opts) assert ap def test_mitmweb(): opts = options.Options() + web.master.WebMaster(opts) ap = cmdline.mitmweb(opts) assert ap diff --git a/test/mitmproxy/tools/test_dump.py b/test/mitmproxy/tools/test_dump.py index 597333af..952c3f4f 100644 --- a/test/mitmproxy/tools/test_dump.py +++ b/test/mitmproxy/tools/test_dump.py @@ -1,7 +1,6 @@ import pytest from unittest import mock -from mitmproxy import proxy from mitmproxy import log from mitmproxy import controller from mitmproxy import options @@ -13,7 +12,7 @@ from .. import tservers class TestDumpMaster(tservers.MasterTest): def mkmaster(self, flt, **opts): o = options.Options(view_filter=flt, verbosity='error', flow_detail=0, **opts) - m = dump.DumpMaster(o, proxy.DummyServer(), with_termlog=False, with_dumper=False) + m = dump.DumpMaster(o, with_termlog=False, with_dumper=False) return m def test_has_error(self): @@ -27,12 +26,12 @@ class TestDumpMaster(tservers.MasterTest): def test_addons_termlog(self, termlog): with mock.patch('sys.stdout'): o = options.Options() - m = dump.DumpMaster(o, proxy.DummyServer(), with_termlog=termlog) + m = dump.DumpMaster(o, with_termlog=termlog) assert (m.addons.get('termlog') is not None) == termlog @pytest.mark.parametrize("dumper", [False, True]) def test_addons_dumper(self, dumper): with mock.patch('sys.stdout'): o = options.Options() - m = dump.DumpMaster(o, proxy.DummyServer(), with_dumper=dumper) + m = dump.DumpMaster(o, with_dumper=dumper) assert (m.addons.get('dumper') is not None) == dumper diff --git a/test/mitmproxy/tools/web/test_app.py b/test/mitmproxy/tools/web/test_app.py index 4d290284..091ef5e8 100644 --- a/test/mitmproxy/tools/web/test_app.py +++ b/test/mitmproxy/tools/web/test_app.py @@ -7,7 +7,6 @@ from tornado import httpclient from tornado import websocket from mitmproxy import exceptions -from mitmproxy import proxy from mitmproxy import options from mitmproxy.test import tflow from mitmproxy.tools.web import app @@ -21,7 +20,7 @@ def json(resp: httpclient.HTTPResponse): class TestApp(tornado.testing.AsyncHTTPTestCase): def get_app(self): o = options.Options(http2=False) - m = webmaster.WebMaster(o, proxy.DummyServer(), with_termlog=False) + m = webmaster.WebMaster(o, with_termlog=False) f = tflow.tflow(resp=True) f.id = "42" m.view.add([f]) @@ -323,5 +322,5 @@ class TestApp(tornado.testing.AsyncHTTPTestCase): web_root = os.path.join(here, os.pardir, os.pardir, os.pardir, os.pardir, 'web') tflow_path = os.path.join(web_root, 'src/js/__tests__/ducks/_tflow.js') content = """export default function(){{\n return {tflow_json}\n}}""".format(tflow_json=tflow_json) - with open(tflow_path, 'w') as f: + with open(tflow_path, 'w', newline="\n") as f: f.write(content) diff --git a/test/mitmproxy/tools/web/test_master.py b/test/mitmproxy/tools/web/test_master.py index 27f99a18..2bceb5ca 100644 --- a/test/mitmproxy/tools/web/test_master.py +++ b/test/mitmproxy/tools/web/test_master.py @@ -1,7 +1,5 @@ from mitmproxy.tools.web import master -from mitmproxy import proxy from mitmproxy import options -from mitmproxy.proxy.config import ProxyConfig from ... import tservers @@ -9,8 +7,7 @@ from ... import tservers class TestWebMaster(tservers.MasterTest): def mkmaster(self, **opts): o = options.Options(**opts) - c = ProxyConfig(o) - return master.WebMaster(o, proxy.DummyServer(c)) + return master.WebMaster(o) def test_basic(self): m = self.mkmaster() diff --git a/test/mitmproxy/tservers.py b/test/mitmproxy/tservers.py index 9faaf20e..dd5bb327 100644 --- a/test/mitmproxy/tservers.py +++ b/test/mitmproxy/tservers.py @@ -69,9 +69,10 @@ class TestState: class TestMaster(taddons.RecordingMaster): - def __init__(self, opts, config): - s = ProxyServer(config) - super().__init__(opts, s) + def __init__(self, opts): + super().__init__(opts) + config = ProxyConfig(opts) + self.server = ProxyServer(config) def clear_addons(self, addons): self.addons.clear() @@ -129,9 +130,8 @@ class ProxyTestBase: ssl=cls.ssl, ssloptions=cls.ssloptions) - opts = cls.get_options() - cls.config = ProxyConfig(opts) - tmaster = cls.masterclass(opts, cls.config) + cls.options = cls.get_options() + tmaster = cls.masterclass(cls.options) cls.proxy = ProxyThread(tmaster) cls.proxy.start() @@ -338,19 +338,16 @@ class ChainProxyTest(ProxyTestBase): @classmethod def setup_class(cls): + # We need to initialize the chain first so that the normal server gets a correct config. cls.chain = [] - super().setup_class() for _ in range(cls.n): opts = cls.get_options() - config = ProxyConfig(opts) - tmaster = cls.masterclass(opts, config) + tmaster = cls.masterclass(opts) proxy = ProxyThread(tmaster) proxy.start() cls.chain.insert(0, proxy) - # Patch the orginal proxy to upstream mode - opts = cls.get_options() - cls.config = cls.proxy.tmaster.config = cls.proxy.tmaster.server.config = ProxyConfig(opts) + super().setup_class() @classmethod def teardown_class(cls): |