aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAldo Cortesi <aldo@nullcube.com>2016-07-20 11:10:15 +1200
committerAldo Cortesi <aldo@nullcube.com>2016-07-20 11:28:53 +1200
commit8317772377baa5eaa9c4d05014f952337f4d03cd (patch)
treea2aa4f84facb7af17a91a948b7f30074fb64c655
parentaa3b866e1d82b7a08d497695eb0fa2c1ddd2c2cf (diff)
downloadmitmproxy-8317772377baa5eaa9c4d05014f952337f4d03cd.tar.gz
mitmproxy-8317772377baa5eaa9c4d05014f952337f4d03cd.tar.bz2
mitmproxy-8317772377baa5eaa9c4d05014f952337f4d03cd.zip
mitproxy.options -> mitmproxy.optmanager, mitmproxy.flow.options -> mitmproxy.options
It might be slightly more felicitous to move optmanager into netlib at some point, especially if we can also use it in pathod. This also consolidates our constants in mitmproxy.options, removing some duplicates.
-rw-r--r--mitmproxy/cmdline.py43
-rw-r--r--mitmproxy/console/master.py3
-rw-r--r--mitmproxy/dump.py3
-rw-r--r--mitmproxy/flow/__init__.py3
-rw-r--r--mitmproxy/flow/options.py124
-rw-r--r--mitmproxy/options.py239
-rw-r--r--mitmproxy/optmanager.py108
-rw-r--r--mitmproxy/web/master.py3
-rw-r--r--test/mitmproxy/builtins/test_anticache.py2
-rw-r--r--test/mitmproxy/builtins/test_anticomp.py2
-rw-r--r--test/mitmproxy/builtins/test_filestreamer.py2
-rw-r--r--test/mitmproxy/builtins/test_replace.py2
-rw-r--r--test/mitmproxy/builtins/test_script.py2
-rw-r--r--test/mitmproxy/builtins/test_setheaders.py2
-rw-r--r--test/mitmproxy/builtins/test_stickyauth.py2
-rw-r--r--test/mitmproxy/builtins/test_stickycookie.py2
-rw-r--r--test/mitmproxy/test_flow.py7
-rw-r--r--test/mitmproxy/test_optmanager.py (renamed from test/mitmproxy/test_options.py)8
-rw-r--r--test/mitmproxy/test_protocol_http2.py5
-rw-r--r--test/mitmproxy/test_proxy.py2
-rw-r--r--test/mitmproxy/tservers.py10
21 files changed, 287 insertions, 287 deletions
diff --git a/mitmproxy/cmdline.py b/mitmproxy/cmdline.py
index b3d3e6dd..a6844241 100644
--- a/mitmproxy/cmdline.py
+++ b/mitmproxy/cmdline.py
@@ -8,26 +8,11 @@ import configargparse
from mitmproxy import exceptions
from mitmproxy import filt
from mitmproxy import platform
+from mitmproxy import options
from netlib import human
from netlib import tcp
from netlib import version
-APP_HOST = "mitm.it"
-APP_PORT = 80
-CA_DIR = "~/.mitmproxy"
-
-# We manually need to specify this, otherwise OpenSSL may select a non-HTTP2 cipher by default.
-# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=apache-2.2.15&openssl=1.0.2&hsts=yes&profile=old
-DEFAULT_CLIENT_CIPHERS = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:" \
- "ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:" \
- "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:" \
- "ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:" \
- "DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:" \
- "DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:" \
- "AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:" \
- "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:" \
- "!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"
-
class ParseException(Exception):
pass
@@ -310,8 +295,8 @@ def basic_options(parser):
)
parser.add_argument(
"--cadir",
- action="store", type=str, dest="cadir", default=CA_DIR,
- help="Location of the default mitmproxy CA files. (%s)" % CA_DIR
+ action="store", type=str, dest="cadir", default=options.CA_DIR,
+ help="Location of the default mitmproxy CA files. (%s)" % options.CA_DIR
)
parser.add_argument(
"--host",
@@ -462,7 +447,7 @@ def proxy_options(parser):
)
group.add_argument(
"-p", "--port",
- action="store", type=int, dest="port", default=8080,
+ action="store", type=int, dest="port", default=options.LISTEN_PORT,
help="Proxy service port."
)
group.add_argument(
@@ -509,7 +494,7 @@ def proxy_ssl_options(parser):
'as the first entry. Can be passed multiple times.')
group.add_argument(
"--ciphers-client", action="store",
- type=str, dest="ciphers_client", default=DEFAULT_CLIENT_CIPHERS,
+ type=str, dest="ciphers_client", default=options.DEFAULT_CLIENT_CIPHERS,
help="Set supported ciphers for client connections. (OpenSSL Syntax)"
)
group.add_argument(
@@ -575,18 +560,18 @@ def onboarding_app(parser):
)
group.add_argument(
"--app-host",
- action="store", dest="app_host", default=APP_HOST, metavar="host",
+ action="store", dest="app_host", default=options.APP_HOST, metavar="host",
help="""
Domain to serve the onboarding app from. For transparent mode, use
an IP when a DNS entry for the app domain is not present. Default:
%s
- """ % APP_HOST
+ """ % options.APP_HOST
)
group.add_argument(
"--app-port",
action="store",
dest="app_port",
- default=APP_PORT,
+ default=options.APP_PORT,
type=int,
metavar="80",
help="Port to serve the onboarding app from."
@@ -764,8 +749,8 @@ def mitmproxy():
usage="%(prog)s [options]",
args_for_setting_config_path=["--conf"],
default_config_files=[
- os.path.join(CA_DIR, "common.conf"),
- os.path.join(CA_DIR, "mitmproxy.conf")
+ os.path.join(options.CA_DIR, "common.conf"),
+ os.path.join(options.CA_DIR, "mitmproxy.conf")
],
add_config_file_help=True,
add_env_var_help=True
@@ -819,8 +804,8 @@ def mitmdump():
usage="%(prog)s [options] [filter]",
args_for_setting_config_path=["--conf"],
default_config_files=[
- os.path.join(CA_DIR, "common.conf"),
- os.path.join(CA_DIR, "mitmdump.conf")
+ os.path.join(options.CA_DIR, "common.conf"),
+ os.path.join(options.CA_DIR, "mitmdump.conf")
],
add_config_file_help=True,
add_env_var_help=True
@@ -849,8 +834,8 @@ def mitmweb():
usage="%(prog)s [options]",
args_for_setting_config_path=["--conf"],
default_config_files=[
- os.path.join(CA_DIR, "common.conf"),
- os.path.join(CA_DIR, "mitmweb.conf")
+ os.path.join(options.CA_DIR, "common.conf"),
+ os.path.join(options.CA_DIR, "mitmweb.conf")
],
add_config_file_help=True,
add_env_var_help=True
diff --git a/mitmproxy/console/master.py b/mitmproxy/console/master.py
index 86e889cc..59d07456 100644
--- a/mitmproxy/console/master.py
+++ b/mitmproxy/console/master.py
@@ -23,6 +23,7 @@ from mitmproxy import exceptions
from mitmproxy import flow
from mitmproxy import script
from mitmproxy import utils
+import mitmproxy.options
from mitmproxy.console import flowlist
from mitmproxy.console import flowview
from mitmproxy.console import grideditor
@@ -178,7 +179,7 @@ class ConsoleState(flow.State):
self.add_flow_setting(flow, "marked", marked)
-class Options(flow.options.Options):
+class Options(mitmproxy.options.Options):
def __init__(
self,
eventlog=False, # type: bool
diff --git a/mitmproxy/dump.py b/mitmproxy/dump.py
index 78dd2578..4f34ab95 100644
--- a/mitmproxy/dump.py
+++ b/mitmproxy/dump.py
@@ -12,6 +12,7 @@ from mitmproxy import exceptions
from mitmproxy import flow
from mitmproxy import builtins
from mitmproxy import utils
+from mitmproxy import options
from mitmproxy.builtins import dumper
from netlib import tcp
@@ -20,7 +21,7 @@ class DumpError(Exception):
pass
-class Options(flow.options.Options):
+class Options(options.Options):
def __init__(
self,
keepserving=False, # type: bool
diff --git a/mitmproxy/flow/__init__.py b/mitmproxy/flow/__init__.py
index b2ab74c6..8a64180e 100644
--- a/mitmproxy/flow/__init__.py
+++ b/mitmproxy/flow/__init__.py
@@ -7,7 +7,6 @@ from mitmproxy.flow.modules import (
AppRegistry, StreamLargeBodies, ClientPlaybackState, ServerPlaybackState
)
from mitmproxy.flow.state import State, FlowView
-from mitmproxy.flow import options
# TODO: We may want to remove the imports from .modules and just expose "modules"
@@ -16,5 +15,5 @@ __all__ = [
"FlowWriter", "FilteredFlowWriter", "FlowReader", "read_flows_from_paths",
"FlowMaster",
"AppRegistry", "StreamLargeBodies", "ClientPlaybackState",
- "ServerPlaybackState", "State", "FlowView", "options",
+ "ServerPlaybackState", "State", "FlowView",
]
diff --git a/mitmproxy/flow/options.py b/mitmproxy/flow/options.py
deleted file mode 100644
index 726952e2..00000000
--- a/mitmproxy/flow/options.py
+++ /dev/null
@@ -1,124 +0,0 @@
-from __future__ import absolute_import, print_function, division
-from mitmproxy import options
-from typing import Tuple, Optional, Sequence # noqa
-from mitmproxy import cmdline
-
-APP_HOST = "mitm.it"
-APP_PORT = 80
-
-
-class Options(options.Options):
- def __init__(
- self,
- # TODO: rename to onboarding_app_*
- app=True, # type: bool
- app_host=APP_HOST, # type: str
- app_port=APP_PORT, # type: int
- anticache=False, # type: bool
- anticomp=False, # type: bool
- client_replay=None, # type: Optional[str]
- kill=False, # type: bool
- no_server=False, # type: bool
- nopop=False, # type: bool
- refresh_server_playback=False, # type: bool
- rfile=None, # type: Optional[str]
- scripts=(), # type: Sequence[str]
- showhost=False, # type: bool
- replacements=(), # type: Sequence[Tuple[str, str, str]]
- rheaders=(), # type: Sequence[str]
- setheaders=(), # type: Sequence[Tuple[str, str, str]]
- server_replay=None, # type: Optional[str]
- stickycookie=None, # type: Optional[str]
- stickyauth=None, # type: Optional[str]
- stream_large_bodies=None, # type: Optional[str]
- verbosity=2, # type: int
- outfile=None, # type: Tuple[str, str]
- replay_ignore_content=False, # type: bool
- replay_ignore_params=(), # type: Sequence[str]
- replay_ignore_payload_params=(), # type: Sequence[str]
- replay_ignore_host=False, # type: bool
-
- # Proxy options
- auth_nonanonymous=False, # type: bool
- auth_singleuser=None, # type: Optional[str]
- auth_htpasswd=None, # type: Optional[str]
- add_upstream_certs_to_client_chain=False, # type: bool
- body_size_limit=None, # type: Optional[int]
- cadir = cmdline.CA_DIR, # type: str
- certs = (), # type: Sequence[Tuple[str, str]]
- ciphers_client = cmdline.DEFAULT_CLIENT_CIPHERS, # type: str
- ciphers_server = None, # type: Optional[str]
- clientcerts = None, # type: Optional[str]
- http2 = True, # type: bool
- ignore_hosts = (), # type: Sequence[str]
- listen_host = "", # type: str
- listen_port = 8080, # type: int
- mode = "regular", # type: str
- no_upstream_cert = False, # type: bool
- rawtcp = False, # type: bool
- upstream_server = "", # type: str
- upstream_auth = "", # type: str
- ssl_version_client="secure", # type: str
- ssl_version_server="secure", # type: str
- ssl_verify_upstream_cert=False, # type: bool
- ssl_verify_upstream_trusted_cadir=None, # type: str
- ssl_verify_upstream_trusted_ca=None, # type: str
- tcp_hosts = (), # type: Sequence[str]
- ):
- # We could replace all assignments with clever metaprogramming,
- # but type hints are a much more valueable asset.
-
- self.app = app
- self.app_host = app_host
- self.app_port = app_port
- self.anticache = anticache
- self.anticomp = anticomp
- self.client_replay = client_replay
- self.kill = kill
- self.no_server = no_server
- self.nopop = nopop
- self.refresh_server_playback = refresh_server_playback
- self.rfile = rfile
- self.scripts = scripts
- self.showhost = showhost
- self.replacements = replacements
- self.rheaders = rheaders
- self.setheaders = setheaders
- self.server_replay = server_replay
- self.stickycookie = stickycookie
- self.stickyauth = stickyauth
- self.stream_large_bodies = stream_large_bodies
- self.verbosity = verbosity
- self.outfile = outfile
- self.replay_ignore_content = replay_ignore_content
- self.replay_ignore_params = replay_ignore_params
- self.replay_ignore_payload_params = replay_ignore_payload_params
- self.replay_ignore_host = replay_ignore_host
-
- # Proxy options
- self.auth_nonanonymous = auth_nonanonymous
- self.auth_singleuser = auth_singleuser
- self.auth_htpasswd = auth_htpasswd
- self.add_upstream_certs_to_client_chain = add_upstream_certs_to_client_chain
- self.body_size_limit = body_size_limit
- self.cadir = cadir
- self.certs = certs
- self.ciphers_client = ciphers_client
- self.ciphers_server = ciphers_server
- self.clientcerts = clientcerts
- self.http2 = http2
- self.ignore_hosts = ignore_hosts
- self.listen_host = listen_host
- self.listen_port = listen_port
- self.mode = mode
- self.no_upstream_cert = no_upstream_cert
- self.rawtcp = rawtcp
- self.upstream_server = upstream_server
- self.upstream_auth = upstream_auth
- self.ssl_version_client = ssl_version_client
- self.ssl_version_server = ssl_version_server
- self.ssl_verify_upstream_cert = ssl_verify_upstream_cert
- self.ssl_verify_upstream_trusted_cadir = ssl_verify_upstream_trusted_cadir
- self.ssl_verify_upstream_trusted_ca = ssl_verify_upstream_trusted_ca
- self.tcp_hosts = tcp_hosts
- super(Options, self).__init__()
diff --git a/mitmproxy/options.py b/mitmproxy/options.py
index 94e5d573..bdc0db4e 100644
--- a/mitmproxy/options.py
+++ b/mitmproxy/options.py
@@ -1,104 +1,137 @@
from __future__ import absolute_import, print_function, division
-
-import contextlib
-import blinker
-import pprint
-
-from mitmproxy import exceptions
-
-
-class Options(object):
- """
- .changed is a blinker Signal that triggers whenever options are
- updated. If any handler in the chain raises an exceptions.OptionsError
- exception, all changes are rolled back, the exception is suppressed,
- and the .errored signal is notified.
- """
- _initialized = False
- attributes = []
-
- def __new__(cls, *args, **kwargs):
- # Initialize instance._opts before __init__ is called.
- # This allows us to call super().__init__() last, which then sets
- # ._initialized = True as the final operation.
- instance = super(Options, cls).__new__(cls)
- instance.__dict__["_opts"] = {}
- return instance
-
- def __init__(self):
- self.__dict__["changed"] = blinker.Signal()
- self.__dict__["errored"] = blinker.Signal()
- self.__dict__["_initialized"] = True
-
- @contextlib.contextmanager
- def rollback(self):
- old = self._opts.copy()
- try:
- yield
- except exceptions.OptionsError as e:
- # Notify error handlers
- self.errored.send(self, exc=e)
- # Rollback
- self.__dict__["_opts"] = old
- self.changed.send(self)
-
- def __eq__(self, other):
- return self._opts == other._opts
-
- def __copy__(self):
- return self.__class__(**self._opts)
-
- def __getattr__(self, attr):
- if attr in self._opts:
- return self._opts[attr]
- else:
- raise AttributeError("No such option: %s" % attr)
-
- def __setattr__(self, attr, value):
- 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)
-
- def get(self, k, d=None):
- return self._opts.get(k, d)
-
- def update(self, **kwargs):
- for k in kwargs:
- if k not in self._opts:
- raise KeyError("No such option: %s" % k)
- with self.rollback():
- self._opts.update(kwargs)
- self.changed.send(self)
-
- def setter(self, attr):
- """
- Generate a setter for a given attribute. This returns a callable
- taking a single argument.
- """
- if attr not in self._opts:
- raise KeyError("No such option: %s" % attr)
- return lambda x: self.__setattr__(attr, x)
-
- def toggler(self, attr):
- """
- Generate a toggler for a boolean attribute. This returns a callable
- that takes no arguments.
- """
- if attr not in self._opts:
- raise KeyError("No such option: %s" % attr)
- return lambda: self.__setattr__(attr, not getattr(self, attr))
-
- def __repr__(self):
- options = pprint.pformat(self._opts, indent=4).strip(" {}")
- if "\n" in options:
- options = "\n " + options + "\n"
- return "{mod}.{cls}({{{options}}})".format(
- mod=type(self).__module__,
- cls=type(self).__name__,
- options=options
- )
+from mitmproxy import optmanager
+from typing import Tuple, Optional, Sequence # noqa
+
+APP_HOST = "mitm.it"
+APP_PORT = 80
+CA_DIR = "~/.mitmproxy"
+LISTEN_PORT = 8080
+
+# We manually need to specify this, otherwise OpenSSL may select a non-HTTP2 cipher by default.
+# https://mozilla.github.io/server-side-tls/ssl-config-generator/?server=apache-2.2.15&openssl=1.0.2&hsts=yes&profile=old
+DEFAULT_CLIENT_CIPHERS = "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:" \
+ "ECDHE-ECDSA-AES256-GCM-SHA384:DHE-RSA-AES128-GCM-SHA256:DHE-DSS-AES128-GCM-SHA256:kEDH+AESGCM:" \
+ "ECDHE-RSA-AES128-SHA256:ECDHE-ECDSA-AES128-SHA256:ECDHE-RSA-AES128-SHA:ECDHE-ECDSA-AES128-SHA:" \
+ "ECDHE-RSA-AES256-SHA384:ECDHE-ECDSA-AES256-SHA384:ECDHE-RSA-AES256-SHA:ECDHE-ECDSA-AES256-SHA:" \
+ "DHE-RSA-AES128-SHA256:DHE-RSA-AES128-SHA:DHE-DSS-AES128-SHA256:DHE-RSA-AES256-SHA256:DHE-DSS-AES256-SHA:" \
+ "DHE-RSA-AES256-SHA:ECDHE-RSA-DES-CBC3-SHA:ECDHE-ECDSA-DES-CBC3-SHA:AES128-GCM-SHA256:AES256-GCM-SHA384:" \
+ "AES128-SHA256:AES256-SHA256:AES128-SHA:AES256-SHA:AES:DES-CBC3-SHA:" \
+ "HIGH:!aNULL:!eNULL:!EXPORT:!DES:!RC4:!MD5:!PSK:!aECDH:" \
+ "!EDH-DSS-DES-CBC3-SHA:!EDH-RSA-DES-CBC3-SHA:!KRB5-DES-CBC3-SHA"
+
+
+class Options(optmanager.OptManager):
+ def __init__(
+ self,
+ # TODO: rename to onboarding_app_*
+ app=True, # type: bool
+ app_host=APP_HOST, # type: str
+ app_port=APP_PORT, # type: int
+ anticache=False, # type: bool
+ anticomp=False, # type: bool
+ client_replay=None, # type: Optional[str]
+ kill=False, # type: bool
+ no_server=False, # type: bool
+ nopop=False, # type: bool
+ refresh_server_playback=False, # type: bool
+ rfile=None, # type: Optional[str]
+ scripts=(), # type: Sequence[str]
+ showhost=False, # type: bool
+ replacements=(), # type: Sequence[Tuple[str, str, str]]
+ rheaders=(), # type: Sequence[str]
+ setheaders=(), # type: Sequence[Tuple[str, str, str]]
+ server_replay=None, # type: Optional[str]
+ stickycookie=None, # type: Optional[str]
+ stickyauth=None, # type: Optional[str]
+ stream_large_bodies=None, # type: Optional[str]
+ verbosity=2, # type: int
+ outfile=None, # type: Tuple[str, str]
+ replay_ignore_content=False, # type: bool
+ replay_ignore_params=(), # type: Sequence[str]
+ replay_ignore_payload_params=(), # type: Sequence[str]
+ replay_ignore_host=False, # type: bool
+
+ # Proxy options
+ auth_nonanonymous=False, # type: bool
+ auth_singleuser=None, # type: Optional[str]
+ auth_htpasswd=None, # type: Optional[str]
+ add_upstream_certs_to_client_chain=False, # type: bool
+ body_size_limit=None, # type: Optional[int]
+ cadir = CA_DIR, # type: str
+ certs = (), # type: Sequence[Tuple[str, str]]
+ ciphers_client = DEFAULT_CLIENT_CIPHERS, # type: str
+ ciphers_server = None, # type: Optional[str]
+ clientcerts = None, # type: Optional[str]
+ http2 = True, # type: bool
+ ignore_hosts = (), # type: Sequence[str]
+ listen_host = "", # type: str
+ listen_port = LISTEN_PORT, # type: int
+ mode = "regular", # type: str
+ no_upstream_cert = False, # type: bool
+ rawtcp = False, # type: bool
+ upstream_server = "", # type: str
+ upstream_auth = "", # type: str
+ ssl_version_client="secure", # type: str
+ ssl_version_server="secure", # type: str
+ ssl_verify_upstream_cert=False, # type: bool
+ ssl_verify_upstream_trusted_cadir=None, # type: str
+ ssl_verify_upstream_trusted_ca=None, # type: str
+ tcp_hosts = (), # type: Sequence[str]
+ ):
+ # We could replace all assignments with clever metaprogramming,
+ # but type hints are a much more valueable asset.
+
+ self.app = app
+ self.app_host = app_host
+ self.app_port = app_port
+ self.anticache = anticache
+ self.anticomp = anticomp
+ self.client_replay = client_replay
+ self.kill = kill
+ self.no_server = no_server
+ self.nopop = nopop
+ self.refresh_server_playback = refresh_server_playback
+ self.rfile = rfile
+ self.scripts = scripts
+ self.showhost = showhost
+ self.replacements = replacements
+ self.rheaders = rheaders
+ self.setheaders = setheaders
+ self.server_replay = server_replay
+ self.stickycookie = stickycookie
+ self.stickyauth = stickyauth
+ self.stream_large_bodies = stream_large_bodies
+ self.verbosity = verbosity
+ self.outfile = outfile
+ self.replay_ignore_content = replay_ignore_content
+ self.replay_ignore_params = replay_ignore_params
+ self.replay_ignore_payload_params = replay_ignore_payload_params
+ self.replay_ignore_host = replay_ignore_host
+
+ # Proxy options
+ self.auth_nonanonymous = auth_nonanonymous
+ self.auth_singleuser = auth_singleuser
+ self.auth_htpasswd = auth_htpasswd
+ self.add_upstream_certs_to_client_chain = add_upstream_certs_to_client_chain
+ self.body_size_limit = body_size_limit
+ self.cadir = cadir
+ self.certs = certs
+ self.ciphers_client = ciphers_client
+ self.ciphers_server = ciphers_server
+ self.clientcerts = clientcerts
+ self.http2 = http2
+ self.ignore_hosts = ignore_hosts
+ self.listen_host = listen_host
+ self.listen_port = listen_port
+ self.mode = mode
+ self.no_upstream_cert = no_upstream_cert
+ self.rawtcp = rawtcp
+ self.upstream_server = upstream_server
+ self.upstream_auth = upstream_auth
+ self.ssl_version_client = ssl_version_client
+ self.ssl_version_server = ssl_version_server
+ self.ssl_verify_upstream_cert = ssl_verify_upstream_cert
+ self.ssl_verify_upstream_trusted_cadir = ssl_verify_upstream_trusted_cadir
+ self.ssl_verify_upstream_trusted_ca = ssl_verify_upstream_trusted_ca
+ self.tcp_hosts = tcp_hosts
+ super(Options, self).__init__()
diff --git a/mitmproxy/optmanager.py b/mitmproxy/optmanager.py
new file mode 100644
index 00000000..e94ef51d
--- /dev/null
+++ b/mitmproxy/optmanager.py
@@ -0,0 +1,108 @@
+from __future__ import absolute_import, print_function, division
+
+import contextlib
+import blinker
+import pprint
+
+from mitmproxy import exceptions
+
+"""
+ The base implementation for Options.
+"""
+
+
+class OptManager(object):
+ """
+ .changed is a blinker Signal that triggers whenever options are
+ updated. If any handler in the chain raises an exceptions.OptionsError
+ exception, all changes are rolled back, the exception is suppressed,
+ and the .errored signal is notified.
+ """
+ _initialized = False
+ attributes = []
+
+ def __new__(cls, *args, **kwargs):
+ # Initialize instance._opts before __init__ is called.
+ # This allows us to call super().__init__() last, which then sets
+ # ._initialized = True as the final operation.
+ instance = super(OptManager, cls).__new__(cls)
+ instance.__dict__["_opts"] = {}
+ return instance
+
+ def __init__(self):
+ self.__dict__["changed"] = blinker.Signal()
+ self.__dict__["errored"] = blinker.Signal()
+ self.__dict__["_initialized"] = True
+
+ @contextlib.contextmanager
+ def rollback(self):
+ old = self._opts.copy()
+ try:
+ yield
+ except exceptions.OptionsError as e:
+ # Notify error handlers
+ self.errored.send(self, exc=e)
+ # Rollback
+ self.__dict__["_opts"] = old
+ self.changed.send(self)
+
+ def __eq__(self, other):
+ return self._opts == other._opts
+
+ def __copy__(self):
+ return self.__class__(**self._opts)
+
+ def __getattr__(self, attr):
+ if attr in self._opts:
+ return self._opts[attr]
+ else:
+ raise AttributeError("No such option: %s" % attr)
+
+ def __setattr__(self, attr, value):
+ 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)
+
+ def get(self, k, d=None):
+ return self._opts.get(k, d)
+
+ def update(self, **kwargs):
+ for k in kwargs:
+ if k not in self._opts:
+ raise KeyError("No such option: %s" % k)
+ with self.rollback():
+ self._opts.update(kwargs)
+ self.changed.send(self)
+
+ def setter(self, attr):
+ """
+ Generate a setter for a given attribute. This returns a callable
+ taking a single argument.
+ """
+ if attr not in self._opts:
+ raise KeyError("No such option: %s" % attr)
+ return lambda x: self.__setattr__(attr, x)
+
+ def toggler(self, attr):
+ """
+ Generate a toggler for a boolean attribute. This returns a callable
+ that takes no arguments.
+ """
+ if attr not in self._opts:
+ raise KeyError("No such option: %s" % attr)
+ return lambda: self.__setattr__(attr, not getattr(self, attr))
+
+ def __repr__(self):
+ options = pprint.pformat(self._opts, indent=4).strip(" {}")
+ if "\n" in options:
+ options = "\n " + options + "\n"
+ return "{mod}.{cls}({{{options}}})".format(
+ mod=type(self).__module__,
+ cls=type(self).__name__,
+ options=options
+ )
diff --git a/mitmproxy/web/master.py b/mitmproxy/web/master.py
index a0d68191..3d384612 100644
--- a/mitmproxy/web/master.py
+++ b/mitmproxy/web/master.py
@@ -12,6 +12,7 @@ from mitmproxy import builtins
from mitmproxy import controller
from mitmproxy import exceptions
from mitmproxy import flow
+from mitmproxy import options
from mitmproxy.web import app
from netlib.http import authentication
@@ -91,7 +92,7 @@ class WebState(flow.State):
)
-class Options(flow.options.Options):
+class Options(options.Options):
def __init__(
self,
intercept=None, # type: Optional[str]
diff --git a/test/mitmproxy/builtins/test_anticache.py b/test/mitmproxy/builtins/test_anticache.py
index 127e1c1a..5a00af03 100644
--- a/test/mitmproxy/builtins/test_anticache.py
+++ b/test/mitmproxy/builtins/test_anticache.py
@@ -2,7 +2,7 @@ from .. import tutils, mastertest
from mitmproxy.builtins import anticache
from mitmproxy.flow import master
from mitmproxy.flow import state
-from mitmproxy.flow import options
+from mitmproxy import options
class TestAntiCache(mastertest.MasterTest):
diff --git a/test/mitmproxy/builtins/test_anticomp.py b/test/mitmproxy/builtins/test_anticomp.py
index 601e56c8..6bfd54bb 100644
--- a/test/mitmproxy/builtins/test_anticomp.py
+++ b/test/mitmproxy/builtins/test_anticomp.py
@@ -2,7 +2,7 @@ from .. import tutils, mastertest
from mitmproxy.builtins import anticomp
from mitmproxy.flow import master
from mitmproxy.flow import state
-from mitmproxy.flow import options
+from mitmproxy import options
class TestAntiComp(mastertest.MasterTest):
diff --git a/test/mitmproxy/builtins/test_filestreamer.py b/test/mitmproxy/builtins/test_filestreamer.py
index 002006b7..c1d5947f 100644
--- a/test/mitmproxy/builtins/test_filestreamer.py
+++ b/test/mitmproxy/builtins/test_filestreamer.py
@@ -7,7 +7,7 @@ import os.path
from mitmproxy.builtins import filestreamer
from mitmproxy.flow import master, FlowReader
from mitmproxy.flow import state
-from mitmproxy.flow import options
+from mitmproxy import options
class TestStream(mastertest.MasterTest):
diff --git a/test/mitmproxy/builtins/test_replace.py b/test/mitmproxy/builtins/test_replace.py
index f8010bec..a0b4b722 100644
--- a/test/mitmproxy/builtins/test_replace.py
+++ b/test/mitmproxy/builtins/test_replace.py
@@ -2,7 +2,7 @@ from .. import tutils, mastertest
from mitmproxy.builtins import replace
from mitmproxy.flow import master
from mitmproxy.flow import state
-from mitmproxy.flow import options
+from mitmproxy import options
class TestReplace(mastertest.MasterTest):
diff --git a/test/mitmproxy/builtins/test_script.py b/test/mitmproxy/builtins/test_script.py
index c9616249..f37c7f94 100644
--- a/test/mitmproxy/builtins/test_script.py
+++ b/test/mitmproxy/builtins/test_script.py
@@ -4,7 +4,7 @@ from mitmproxy.builtins import script
from mitmproxy import exceptions
from mitmproxy.flow import master
from mitmproxy.flow import state
-from mitmproxy.flow import options
+from mitmproxy import options
from .. import tutils, mastertest
diff --git a/test/mitmproxy/builtins/test_setheaders.py b/test/mitmproxy/builtins/test_setheaders.py
index 1a8d048c..4465719d 100644
--- a/test/mitmproxy/builtins/test_setheaders.py
+++ b/test/mitmproxy/builtins/test_setheaders.py
@@ -2,7 +2,7 @@ from .. import tutils, mastertest
from mitmproxy.builtins import setheaders
from mitmproxy.flow import state
-from mitmproxy.flow import options
+from mitmproxy import options
class TestSetHeaders(mastertest.MasterTest):
diff --git a/test/mitmproxy/builtins/test_stickyauth.py b/test/mitmproxy/builtins/test_stickyauth.py
index 1e617402..9233f435 100644
--- a/test/mitmproxy/builtins/test_stickyauth.py
+++ b/test/mitmproxy/builtins/test_stickyauth.py
@@ -2,7 +2,7 @@ from .. import tutils, mastertest
from mitmproxy.builtins import stickyauth
from mitmproxy.flow import master
from mitmproxy.flow import state
-from mitmproxy.flow import options
+from mitmproxy import options
class TestStickyAuth(mastertest.MasterTest):
diff --git a/test/mitmproxy/builtins/test_stickycookie.py b/test/mitmproxy/builtins/test_stickycookie.py
index b8d703bd..81b540db 100644
--- a/test/mitmproxy/builtins/test_stickycookie.py
+++ b/test/mitmproxy/builtins/test_stickycookie.py
@@ -2,7 +2,7 @@ from .. import tutils, mastertest
from mitmproxy.builtins import stickycookie
from mitmproxy.flow import master
from mitmproxy.flow import state
-from mitmproxy.flow import options
+from mitmproxy import options
from netlib import tutils as ntutils
diff --git a/test/mitmproxy/test_flow.py b/test/mitmproxy/test_flow.py
index e17a125c..36b212a7 100644
--- a/test/mitmproxy/test_flow.py
+++ b/test/mitmproxy/test_flow.py
@@ -3,8 +3,7 @@ import io
import netlib.utils
from netlib.http import Headers
-from mitmproxy import filt, controller, flow
-from mitmproxy.flow import options
+from mitmproxy import filt, controller, flow, options
from mitmproxy.contrib import tnetstring
from mitmproxy.exceptions import FlowReadException
from mitmproxy.models import Error
@@ -745,7 +744,7 @@ class TestFlowMaster:
f = tutils.tflow(resp=True)
pb = [tutils.tflow(resp=True), f]
fm = flow.FlowMaster(
- flow.options.Options(),
+ options.Options(),
DummyServer(ProxyConfig(options.Options())),
s
)
@@ -776,7 +775,7 @@ class TestFlowMaster:
f.response = HTTPResponse.wrap(netlib.tutils.tresp(content=f.request))
pb = [f]
- fm = flow.FlowMaster(flow.options.Options(), None, s)
+ fm = flow.FlowMaster(options.Options(), None, s)
fm.refresh_server_playback = True
assert not fm.do_server_playback(tutils.tflow())
diff --git a/test/mitmproxy/test_options.py b/test/mitmproxy/test_optmanager.py
index af619b27..67f76ecd 100644
--- a/test/mitmproxy/test_options.py
+++ b/test/mitmproxy/test_optmanager.py
@@ -1,12 +1,12 @@
from __future__ import absolute_import, print_function, division
import copy
-from mitmproxy import options
+from mitmproxy import optmanager
from mitmproxy import exceptions
from netlib import tutils
-class TO(options.Options):
+class TO(optmanager.OptManager):
def __init__(self, one=None, two=None):
self.one = one
self.two = two
@@ -93,8 +93,8 @@ def test_rollback():
def test_repr():
- assert repr(TO()) == "test.mitmproxy.test_options.TO({'one': None, 'two': None})"
- assert repr(TO(one='x' * 60)) == """test.mitmproxy.test_options.TO({
+ assert repr(TO()) == "test.mitmproxy.test_optmanager.TO({'one': None, 'two': None})"
+ assert repr(TO(one='x' * 60)) == """test.mitmproxy.test_optmanager.TO({
'one': 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx',
'two': None
})"""
diff --git a/test/mitmproxy/test_protocol_http2.py b/test/mitmproxy/test_protocol_http2.py
index d11570d9..afbffb67 100644
--- a/test/mitmproxy/test_protocol_http2.py
+++ b/test/mitmproxy/test_protocol_http2.py
@@ -9,9 +9,8 @@ import traceback
import h2
-from mitmproxy.flow import options
+from mitmproxy import options
from mitmproxy.proxy.config import ProxyConfig
-from mitmproxy.cmdline import APP_HOST, APP_PORT
import netlib
from ..netlib import tservers as netlib_tservers
@@ -94,7 +93,7 @@ class _Http2TestBase(object):
cls.config = ProxyConfig(opts)
tmaster = tservers.TestMaster(opts, cls.config)
- tmaster.start_app(APP_HOST, APP_PORT)
+ tmaster.start_app(options.APP_HOST, options.APP_PORT)
cls.proxy = tservers.ProxyThread(tmaster)
cls.proxy.start()
diff --git a/test/mitmproxy/test_proxy.py b/test/mitmproxy/test_proxy.py
index 7095d9d2..6e790e28 100644
--- a/test/mitmproxy/test_proxy.py
+++ b/test/mitmproxy/test_proxy.py
@@ -3,10 +3,10 @@ import mock
from OpenSSL import SSL
from mitmproxy import cmdline
+from mitmproxy import options
from mitmproxy.proxy import ProxyConfig
from mitmproxy.models.connections import ServerConnection
from mitmproxy.proxy.server import DummyServer, ProxyServer, ConnectionHandler
-from mitmproxy.flow import options
from mitmproxy.proxy import config
from netlib.exceptions import TcpDisconnect
from pathod import test
diff --git a/test/mitmproxy/tservers.py b/test/mitmproxy/tservers.py
index 30980e40..f5119166 100644
--- a/test/mitmproxy/tservers.py
+++ b/test/mitmproxy/tservers.py
@@ -8,9 +8,7 @@ from mitmproxy.proxy.config import ProxyConfig
from mitmproxy.proxy.server import ProxyServer
import pathod.test
import pathod.pathoc
-from mitmproxy import flow, controller
-from mitmproxy.flow import options
-from mitmproxy.cmdline import APP_HOST, APP_PORT
+from mitmproxy import flow, controller, options
from mitmproxy import builtins
testapp = flask.Flask(__name__)
@@ -93,7 +91,7 @@ class ProxyTestBase(object):
opts = cls.get_options()
cls.config = ProxyConfig(opts)
tmaster = cls.masterclass(opts, cls.config)
- tmaster.start_app(APP_HOST, APP_PORT)
+ tmaster.start_app(options.APP_HOST, options.APP_PORT)
cls.proxy = ProxyThread(tmaster)
cls.proxy.start()
@@ -160,11 +158,11 @@ class HTTPProxyTest(ProxyTestBase):
p = pathod.pathoc.Pathoc(
("127.0.0.1", self.proxy.port), True, fp=None
)
- p.connect((APP_HOST, APP_PORT))
+ p.connect((options.APP_HOST, options.APP_PORT))
return p.request("get:'%s'" % page)
else:
p = self.pathoc()
- return p.request("get:'http://%s%s'" % (APP_HOST, page))
+ return p.request("get:'http://%s%s'" % (options.APP_HOST, page))
class TResolver: