From fc4fe83eafc68ebb9763fa5cbee1ed7e16964c9c Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Sun, 9 Mar 2014 21:13:08 +0100 Subject: [PATCH 1/3] split up proxy.py --- libmproxy/flow.py | 1 - libmproxy/protocol/__init__.py | 9 +- libmproxy/protocol/http.py | 10 +- libmproxy/protocol/primitives.py | 2 +- libmproxy/proxy.py | 179 +++---------------------------- libmproxy/prxy/__init__.py | 0 libmproxy/prxy/connection.py | 138 ++++++++++++++++++++++++ libmproxy/prxy/exception.py | 14 +++ libmproxy/prxy/server.py | 18 ++++ test/test_dump.py | 4 +- test/test_flow.py | 5 +- test/test_proxy.py | 8 +- test/tutils.py | 7 +- 13 files changed, 207 insertions(+), 188 deletions(-) create mode 100644 libmproxy/prxy/__init__.py create mode 100644 libmproxy/prxy/connection.py create mode 100644 libmproxy/prxy/exception.py create mode 100644 libmproxy/prxy/server.py diff --git a/libmproxy/flow.py b/libmproxy/flow.py index f8ad24440..c362465ca 100644 --- a/libmproxy/flow.py +++ b/libmproxy/flow.py @@ -9,7 +9,6 @@ import flask import requests import tnetstring, filt, script from netlib import odict, wsgi -from .proxy import ClientConnection, ServerConnection # FIXME: remove circular dependency import controller, version, protocol import app from .protocol import KILL diff --git a/libmproxy/protocol/__init__.py b/libmproxy/protocol/__init__.py index 2c2e72859..392a8e3d7 100644 --- a/libmproxy/protocol/__init__.py +++ b/libmproxy/protocol/__init__.py @@ -1,14 +1,7 @@ -from ..proxy import ServerConnection, AddressPriority +from ..prxy.server import AddressPriority KILL = 0 # const for killed requests -class ConnectionTypeChange(Exception): - """ - Gets raised if the connetion type has been changed (e.g. after HTTP/1.1 101 Switching Protocols). - It's up to the raising ProtocolHandler to specify the new conntype before raising the exception. - """ - pass - class ProtocolHandler(object): def __init__(self, c): diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py index 8a2583b1f..3f9668ae4 100644 --- a/libmproxy/protocol/http.py +++ b/libmproxy/protocol/http.py @@ -1,11 +1,13 @@ import Cookie, urllib, urlparse, time, copy from email.utils import parsedate_tz, formatdate, mktime_tz +from ..prxy.connection import ServerConnection +from ..prxy.exception import ProxyError, ConnectionTypeChange +from ..prxy.server import AddressPriority import netlib.utils -from netlib import http, tcp, http_status, odict +from netlib import http, tcp, http_status from netlib.odict import ODict, ODictCaseless -from . import ProtocolHandler, ConnectionTypeChange, KILL, TemporaryServerChangeMixin -from .. import encoding, utils, version, filt, controller, stateobject -from ..proxy import ProxyError, AddressPriority, ServerConnection +from . import ProtocolHandler, KILL, TemporaryServerChangeMixin +from .. import encoding, utils, filt, controller, stateobject from .primitives import Flow, Error diff --git a/libmproxy/protocol/primitives.py b/libmproxy/protocol/primitives.py index 90191eeb8..7cee074de 100644 --- a/libmproxy/protocol/primitives.py +++ b/libmproxy/protocol/primitives.py @@ -1,5 +1,5 @@ from .. import stateobject, utils, version -from ..proxy import ServerConnection, ClientConnection +from ..prxy.connection import ClientConnection, ServerConnection import copy diff --git a/libmproxy/proxy.py b/libmproxy/proxy.py index 6dd37752d..ccb47c262 100644 --- a/libmproxy/proxy.py +++ b/libmproxy/proxy.py @@ -1,7 +1,18 @@ -import os, socket, time, threading, copy +import os +import socket +import threading + from OpenSSL import SSL + +from .prxy.connection import ClientConnection, ServerConnection +from .prxy.exception import ProxyError, ConnectionTypeChange +from .prxy.server import AddressPriority from netlib import tcp, http, certutils, http_auth -import utils, version, platform, controller, stateobject +import utils +import version +import platform +import controller + TRANSPARENT_SSL_PORTS = [443, 8443] CONF_BASENAME = "mitmproxy" @@ -9,32 +20,6 @@ CONF_DIR = "~/.mitmproxy" CA_CERT_NAME = "mitmproxy-ca.pem" - -class AddressPriority(object): - """ - Enum that signifies the priority of the given address when choosing the destination host. - Higher is better (None < i) - """ - FORCE = 5 - """forward mode""" - MANUALLY_CHANGED = 4 - """user changed the target address in the ui""" - FROM_SETTINGS = 3 - """reverse proxy mode""" - FROM_CONNECTION = 2 - """derived from transparent resolver""" - FROM_PROTOCOL = 1 - """derived from protocol (e.g. absolute-form http requests)""" - - -class ProxyError(Exception): - def __init__(self, code, msg, headers=None): - self.code, self.msg, self.headers = code, msg, headers - - def __str__(self): - return "ProxyError(%s, %s)" % (self.code, self.msg) - - class Log: def __init__(self, msg): self.msg = msg @@ -58,140 +43,6 @@ class ProxyConfig: self.certstore = certutils.CertStore.from_store(self.confdir, CONF_BASENAME) - -class ClientConnection(tcp.BaseHandler, stateobject.SimpleStateObject): - def __init__(self, client_connection, address, server): - if client_connection: # Eventually, this object is restored from state. We don't have a connection then. - tcp.BaseHandler.__init__(self, client_connection, address, server) - else: - self.connection = None - self.server = None - self.wfile = None - self.rfile = None - self.address = None - self.clientcert = None - - self.timestamp_start = utils.timestamp() - self.timestamp_end = None - self.timestamp_ssl_setup = None - - _stateobject_attributes = dict( - timestamp_start=float, - timestamp_end=float, - timestamp_ssl_setup=float - ) - - def _get_state(self): - d = super(ClientConnection, self)._get_state() - d.update( - address={"address": self.address(), "use_ipv6": self.address.use_ipv6}, - clientcert=self.cert.to_pem() if self.clientcert else None - ) - return d - - def _load_state(self, state): - super(ClientConnection, self)._load_state(state) - self.address = tcp.Address(**state["address"]) if state["address"] else None - self.clientcert = certutils.SSLCert.from_pem(state["clientcert"]) if state["clientcert"] else None - - def copy(self): - return copy.copy(self) - - def send(self, message): - self.wfile.write(message) - self.wfile.flush() - - @classmethod - def _from_state(cls, state): - f = cls(None, tuple(), None) - f._load_state(state) - return f - - def convert_to_ssl(self, *args, **kwargs): - tcp.BaseHandler.convert_to_ssl(self, *args, **kwargs) - self.timestamp_ssl_setup = utils.timestamp() - - def finish(self): - tcp.BaseHandler.finish(self) - self.timestamp_end = utils.timestamp() - - -class ServerConnection(tcp.TCPClient, stateobject.SimpleStateObject): - def __init__(self, address, priority): - tcp.TCPClient.__init__(self, address) - self.priority = priority - - self.peername = None - self.timestamp_start = None - self.timestamp_end = None - self.timestamp_tcp_setup = None - self.timestamp_ssl_setup = None - - _stateobject_attributes = dict( - peername=tuple, - timestamp_start=float, - timestamp_end=float, - timestamp_tcp_setup=float, - timestamp_ssl_setup=float, - address=tcp.Address, - source_address=tcp.Address, - cert=certutils.SSLCert, - ssl_established=bool, - sni=str - ) - - def _get_state(self): - d = super(ServerConnection, self)._get_state() - d.update( - address={"address": self.address(), "use_ipv6": self.address.use_ipv6}, - source_address= {"address": self.source_address(), - "use_ipv6": self.source_address.use_ipv6} if self.source_address else None, - cert=self.cert.to_pem() if self.cert else None - ) - return d - - def _load_state(self, state): - super(ServerConnection, self)._load_state(state) - - self.address = tcp.Address(**state["address"]) if state["address"] else None - self.source_address = tcp.Address(**state["source_address"]) if state["source_address"] else None - self.cert = certutils.SSLCert.from_pem(state["cert"]) if state["cert"] else None - - @classmethod - def _from_state(cls, state): - f = cls(tuple(), None) - f._load_state(state) - return f - - def copy(self): - return copy.copy(self) - - def connect(self): - self.timestamp_start = utils.timestamp() - tcp.TCPClient.connect(self) - self.peername = self.connection.getpeername() - self.timestamp_tcp_setup = utils.timestamp() - - def send(self, message): - self.wfile.write(message) - self.wfile.flush() - - def establish_ssl(self, clientcerts, sni): - clientcert = None - if clientcerts: - path = os.path.join(clientcerts, self.address.host.encode("idna")) + ".pem" - if os.path.exists(path): - clientcert = path - try: - self.convert_to_ssl(cert=clientcert, sni=sni) - self.timestamp_ssl_setup = utils.timestamp() - except tcp.NetLibError, v: - raise ProxyError(400, str(v)) - - def finish(self): - tcp.TCPClient.finish(self) - self.timestamp_end = utils.timestamp() - from . import protocol from .protocol.http import HTTPResponse @@ -268,7 +119,7 @@ class ConnectionHandler: while not self.close: try: protocol.handle_messages(self.conntype, self) - except protocol.ConnectionTypeChange: + except ConnectionTypeChange: self.log("Connection Type Changed: %s" % self.conntype) continue @@ -323,7 +174,7 @@ class ConnectionHandler: """ Sets a new server address with the given priority. Does not re-establish either connection or SSL handshake. - @type priority: AddressPriority + @type priority: libmproxy.prxy.server.AddressPriority """ address = tcp.Address.wrap(address) diff --git a/libmproxy/prxy/__init__.py b/libmproxy/prxy/__init__.py new file mode 100644 index 000000000..e69de29bb diff --git a/libmproxy/prxy/connection.py b/libmproxy/prxy/connection.py new file mode 100644 index 000000000..b1040c1ce --- /dev/null +++ b/libmproxy/prxy/connection.py @@ -0,0 +1,138 @@ +import copy +import os +from .. import stateobject, utils +from .exception import ProxyError +from netlib import tcp, certutils + +class ClientConnection(tcp.BaseHandler, stateobject.SimpleStateObject): + def __init__(self, client_connection, address, server): + if client_connection: # Eventually, this object is restored from state. We don't have a connection then. + tcp.BaseHandler.__init__(self, client_connection, address, server) + else: + self.connection = None + self.server = None + self.wfile = None + self.rfile = None + self.address = None + self.clientcert = None + + self.timestamp_start = utils.timestamp() + self.timestamp_end = None + self.timestamp_ssl_setup = None + + _stateobject_attributes = dict( + timestamp_start=float, + timestamp_end=float, + timestamp_ssl_setup=float + ) + + def _get_state(self): + d = super(ClientConnection, self)._get_state() + d.update( + address={"address": self.address(), "use_ipv6": self.address.use_ipv6}, + clientcert=self.cert.to_pem() if self.clientcert else None + ) + return d + + def _load_state(self, state): + super(ClientConnection, self)._load_state(state) + self.address = tcp.Address(**state["address"]) if state["address"] else None + self.clientcert = certutils.SSLCert.from_pem(state["clientcert"]) if state["clientcert"] else None + + def copy(self): + return copy.copy(self) + + def send(self, message): + self.wfile.write(message) + self.wfile.flush() + + @classmethod + def _from_state(cls, state): + f = cls(None, tuple(), None) + f._load_state(state) + return f + + def convert_to_ssl(self, *args, **kwargs): + tcp.BaseHandler.convert_to_ssl(self, *args, **kwargs) + self.timestamp_ssl_setup = utils.timestamp() + + def finish(self): + tcp.BaseHandler.finish(self) + self.timestamp_end = utils.timestamp() + + +class ServerConnection(tcp.TCPClient, stateobject.SimpleStateObject): + def __init__(self, address, priority): + tcp.TCPClient.__init__(self, address) + self.priority = priority + + self.peername = None + self.timestamp_start = None + self.timestamp_end = None + self.timestamp_tcp_setup = None + self.timestamp_ssl_setup = None + + _stateobject_attributes = dict( + peername=tuple, + timestamp_start=float, + timestamp_end=float, + timestamp_tcp_setup=float, + timestamp_ssl_setup=float, + address=tcp.Address, + source_address=tcp.Address, + cert=certutils.SSLCert, + ssl_established=bool, + sni=str + ) + + def _get_state(self): + d = super(ServerConnection, self)._get_state() + d.update( + address={"address": self.address(), "use_ipv6": self.address.use_ipv6}, + source_address= {"address": self.source_address(), + "use_ipv6": self.source_address.use_ipv6} if self.source_address else None, + cert=self.cert.to_pem() if self.cert else None + ) + return d + + def _load_state(self, state): + super(ServerConnection, self)._load_state(state) + + self.address = tcp.Address(**state["address"]) if state["address"] else None + self.source_address = tcp.Address(**state["source_address"]) if state["source_address"] else None + self.cert = certutils.SSLCert.from_pem(state["cert"]) if state["cert"] else None + + @classmethod + def _from_state(cls, state): + f = cls(tuple(), None) + f._load_state(state) + return f + + def copy(self): + return copy.copy(self) + + def connect(self): + self.timestamp_start = utils.timestamp() + tcp.TCPClient.connect(self) + self.peername = self.connection.getpeername() + self.timestamp_tcp_setup = utils.timestamp() + + def send(self, message): + self.wfile.write(message) + self.wfile.flush() + + def establish_ssl(self, clientcerts, sni): + clientcert = None + if clientcerts: + path = os.path.join(clientcerts, self.address.host.encode("idna")) + ".pem" + if os.path.exists(path): + clientcert = path + try: + self.convert_to_ssl(cert=clientcert, sni=sni) + self.timestamp_ssl_setup = utils.timestamp() + except tcp.NetLibError, v: + raise ProxyError(400, str(v)) + + def finish(self): + tcp.TCPClient.finish(self) + self.timestamp_end = utils.timestamp() \ No newline at end of file diff --git a/libmproxy/prxy/exception.py b/libmproxy/prxy/exception.py new file mode 100644 index 000000000..c43a5d75d --- /dev/null +++ b/libmproxy/prxy/exception.py @@ -0,0 +1,14 @@ +class ProxyError(Exception): + def __init__(self, code, msg, headers=None): + self.code, self.msg, self.headers = code, msg, headers + + def __str__(self): + return "ProxyError(%s, %s)" % (self.code, self.msg) + + +class ConnectionTypeChange(Exception): + """ + Gets raised if the connection type has been changed (e.g. after HTTP/1.1 101 Switching Protocols). + It's up to the raising ProtocolHandler to specify the new conntype before raising the exception. + """ + pass \ No newline at end of file diff --git a/libmproxy/prxy/server.py b/libmproxy/prxy/server.py new file mode 100644 index 000000000..441b29b47 --- /dev/null +++ b/libmproxy/prxy/server.py @@ -0,0 +1,18 @@ +__author__ = 'user' + + +class AddressPriority(object): + """ + Enum that signifies the priority of the given address when choosing the destination host. + Higher is better (None < i) + """ + FORCE = 5 + """forward mode""" + MANUALLY_CHANGED = 4 + """user changed the target address in the ui""" + FROM_SETTINGS = 3 + """reverse proxy mode""" + FROM_CONNECTION = 2 + """derived from transparent resolver""" + FROM_PROTOCOL = 1 + """derived from protocol (e.g. absolute-form http requests)""" \ No newline at end of file diff --git a/test/test_dump.py b/test/test_dump.py index 8b4b9aa53..c5c231fa4 100644 --- a/test/test_dump.py +++ b/test/test_dump.py @@ -1,6 +1,6 @@ import os from cStringIO import StringIO -from libmproxy import dump, flow, proxy +from libmproxy import dump, flow, proxy, prxy import tutils import mock @@ -27,7 +27,7 @@ class TestDumpMaster: cc = req.flow.client_conn cc.reply = mock.MagicMock() m.handle_clientconnect(cc) - sc = proxy.ServerConnection((req.get_host(), req.get_port()), None) + sc = prxy.connection.ServerConnection((req.get_host(), req.get_port()), None) sc.reply = mock.MagicMock() m.handle_serverconnection(sc) m.handle_request(req) diff --git a/test/test_flow.py b/test/test_flow.py index fbead1ca9..c7e39f738 100644 --- a/test/test_flow.py +++ b/test/test_flow.py @@ -4,6 +4,7 @@ import email.utils from libmproxy import filt, protocol, controller, utils, tnetstring, proxy, flow from libmproxy.protocol.primitives import Error, Flow from libmproxy.protocol.http import decoded +from libmproxy.prxy.connection import ClientConnection, ServerConnection from netlib import tcp import tutils @@ -586,7 +587,7 @@ class TestFlowMaster: req = tutils.treq() fm.handle_clientconnect(req.flow.client_conn) assert fm.scripts[0].ns["log"][-1] == "clientconnect" - sc = proxy.ServerConnection((req.get_host(), req.get_port()), None) + sc = ServerConnection((req.get_host(), req.get_port()), None) sc.reply = controller.DummyReply() fm.handle_serverconnection(sc) assert fm.scripts[0].ns["log"][-1] == "serverconnect" @@ -1159,7 +1160,7 @@ class TestClientConnection: def test_state(self): c = tutils.tclient_conn() - assert proxy.ClientConnection._from_state(c._get_state()) == c + assert ClientConnection._from_state(c._get_state()) == c c2 = tutils.tclient_conn() c2.address.address = (c2.address.host, 4242) diff --git a/test/test_proxy.py b/test/test_proxy.py index b15e3f846..2a4a250e6 100644 --- a/test/test_proxy.py +++ b/test/test_proxy.py @@ -1,5 +1,7 @@ import argparse from libmproxy import proxy, flow, cmdline +from libmproxy.prxy.connection import ServerConnection +from libmproxy.prxy.exception import ProxyError import tutils from libpathod import test from netlib import http, tcp @@ -7,7 +9,7 @@ import mock def test_proxy_error(): - p = proxy.ProxyError(111, "msg") + p = ProxyError(111, "msg") assert str(p) @@ -19,7 +21,7 @@ class TestServerConnection: self.d.shutdown() def test_simple(self): - sc = proxy.ServerConnection((self.d.IFACE, self.d.port), None) + sc = ServerConnection((self.d.IFACE, self.d.port), None) sc.connect() r = tutils.treq() r.flow.server_conn = sc @@ -31,7 +33,7 @@ class TestServerConnection: sc.finish() def test_terminate_error(self): - sc = proxy.ServerConnection((self.d.IFACE, self.d.port), None) + sc = ServerConnection((self.d.IFACE, self.d.port), None) sc.connect() sc.connection = mock.Mock() sc.connection.recv = mock.Mock(return_value=False) diff --git a/test/tutils.py b/test/tutils.py index b1bfc831c..8690d67d0 100644 --- a/test/tutils.py +++ b/test/tutils.py @@ -2,6 +2,7 @@ import os, shutil, tempfile from contextlib import contextmanager from libmproxy import flow, utils, controller, proxy from libmproxy.protocol import http +from libmproxy.prxy.connection import ClientConnection, ServerConnection import mock_urwid from libmproxy.console.flowview import FlowView from libmproxy.console import ConsoleState @@ -21,7 +22,7 @@ def SkipWindows(fn): def tclient_conn(): - c = proxy.ClientConnection._from_state(dict( + c = ClientConnection._from_state(dict( address=dict(address=("address", 22), use_ipv6=True), clientcert=None )) @@ -30,7 +31,7 @@ def tclient_conn(): def tserver_conn(): - c = proxy.ServerConnection._from_state(dict( + c = ServerConnection._from_state(dict( address=dict(address=("address", 22), use_ipv6=True), source_address=dict(address=("address", 22), use_ipv6=True), cert=None @@ -69,7 +70,7 @@ def tresp(req=None, content="message"): headers = flow.ODictCaseless() headers["header_response"] = ["svalue"] cert = certutils.SSLCert.from_der(file(test_data.path("data/dercert"), "rb").read()) - f.server_conn = proxy.ServerConnection._from_state(dict( + f.server_conn = ServerConnection._from_state(dict( address=dict(address=("address", 22), use_ipv6=True), source_address=None, cert=cert.to_pem())) From 5598a8de82f28232fb4407911a8643dceacc9ebc Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Sun, 9 Mar 2014 21:51:24 +0100 Subject: [PATCH 2/3] finish proxy.py split up --- libmproxy/app.py | 4 +- libmproxy/cmdline.py | 4 +- libmproxy/flow.py | 40 +++- libmproxy/protocol/__init__.py | 2 +- libmproxy/protocol/http.py | 6 +- libmproxy/protocol/primitives.py | 2 +- libmproxy/{prxy => proxy}/__init__.py | 0 libmproxy/proxy/config.py | 124 ++++++++++++ libmproxy/{prxy => proxy}/connection.py | 3 +- libmproxy/proxy/primitives.py | 40 ++++ libmproxy/{proxy.py => proxy/server.py} | 256 +++++------------------- libmproxy/prxy/exception.py | 14 -- libmproxy/prxy/server.py | 18 -- mitmdump | 11 +- mitmproxy | 11 +- test/test_dump.py | 7 +- test/test_flow.py | 12 +- test/test_protocol_http.py | 1 - test/test_proxy.py | 14 +- test/test_server.py | 4 +- test/tservers.py | 10 +- test/tutils.py | 4 +- 22 files changed, 294 insertions(+), 293 deletions(-) rename libmproxy/{prxy => proxy}/__init__.py (100%) create mode 100644 libmproxy/proxy/config.py rename libmproxy/{prxy => proxy}/connection.py (98%) create mode 100644 libmproxy/proxy/primitives.py rename libmproxy/{proxy.py => proxy/server.py} (62%) delete mode 100644 libmproxy/prxy/exception.py delete mode 100644 libmproxy/prxy/server.py diff --git a/libmproxy/app.py b/libmproxy/app.py index 24187704a..697210318 100644 --- a/libmproxy/app.py +++ b/libmproxy/app.py @@ -17,12 +17,12 @@ def index(): @mapp.route("/cert/pem") def certs_pem(): - p = os.path.join(master().server.config.confdir, proxy.CONF_BASENAME + "-ca-cert.pem") + p = os.path.join(master().server.config.confdir, proxy.config.CONF_BASENAME + "-ca-cert.pem") return flask.Response(open(p, "rb").read(), mimetype='application/x-x509-ca-cert') @mapp.route("/cert/p12") def certs_p12(): - p = os.path.join(master().server.config.confdir, proxy.CONF_BASENAME + "-ca-cert.p12") + p = os.path.join(master().server.config.confdir, proxy.config.CONF_BASENAME + "-ca-cert.p12") return flask.Response(open(p, "rb").read(), mimetype='application/x-pkcs12') diff --git a/libmproxy/cmdline.py b/libmproxy/cmdline.py index 7950d40b8..72c137698 100644 --- a/libmproxy/cmdline.py +++ b/libmproxy/cmdline.py @@ -1,4 +1,4 @@ -import proxy +from . import proxy import re, filt import argparse @@ -387,4 +387,4 @@ def common_options(parser): help="Allow access to users specified in an Apache htpasswd file." ) - proxy.ssl_option_group(parser) + proxy.config.ssl_option_group(parser) diff --git a/libmproxy/flow.py b/libmproxy/flow.py index c362465ca..452fd783e 100644 --- a/libmproxy/flow.py +++ b/libmproxy/flow.py @@ -7,13 +7,15 @@ import hashlib, Cookie, cookielib, re, threading import os import flask import requests +from . import controller, protocol +from .protocol import http +from .proxy.connection import ServerConnection +from .proxy.primitives import ProxyError import tnetstring, filt, script -from netlib import odict, wsgi -import controller, version, protocol +from netlib import odict, wsgi, tcp +import netlib.http +import version import app -from .protocol import KILL -from .protocol.http import HTTPResponse, CONTENT_MISSING -from .proxy import RequestReplayThread ODict = odict.ODict ODictCaseless = odict.ODictCaseless @@ -564,7 +566,7 @@ class FlowMaster(controller.Master): rflow = self.server_playback.next_flow(flow) if not rflow: return None - response = HTTPResponse._from_state(rflow.response._get_state()) + response = http.HTTPResponse._from_state(rflow.response._get_state()) response.is_replay = True if self.refresh_server_playback: response.refresh() @@ -641,7 +643,7 @@ class FlowMaster(controller.Master): """ if f.intercepting: return "Can't replay while intercepting..." - if f.request.content == CONTENT_MISSING: + if f.request.content == http.CONTENT_MISSING: return "Can't replay request with missing content..." if f.request: f.request.is_replay = True @@ -692,7 +694,7 @@ class FlowMaster(controller.Master): err = app.serve(r, r.flow.client_conn.wfile, **{"mitmproxy.master": self}) if err: self.add_event("Error in wsgi app. %s"%err, "error") - r.reply(KILL) + r.reply(protocol.KILL) return f = self.state.add_request(r) self.replacehooks.run(f) @@ -784,3 +786,25 @@ class FilteredFlowWriter: d = f._get_state() tnetstring.dump(d, self.fo) + +class RequestReplayThread(threading.Thread): + name="RequestReplayThread" + + def __init__(self, config, flow, masterq): + self.config, self.flow, self.channel = config, flow, controller.Channel(masterq) + threading.Thread.__init__(self) + + def run(self): + try: + r = self.flow.request + server = ServerConnection(self.flow.server_conn.address(), None) + server.connect() + if self.flow.server_conn.ssl_established: + server.establish_ssl(self.config.clientcerts, + self.flow.server_conn.sni) + server.send(r._assemble()) + self.flow.response = http.HTTPResponse.from_stream(server.rfile, r.method, body_size_limit=self.config.body_size_limit) + self.channel.ask("response", self.flow.response) + except (ProxyError, netlib.http.HttpError, tcp.NetLibError), v: + self.flow.error = protocol.primitives.Error(str(v)) + self.channel.ask("error", self.flow.error) \ No newline at end of file diff --git a/libmproxy/protocol/__init__.py b/libmproxy/protocol/__init__.py index 392a8e3d7..6200757f8 100644 --- a/libmproxy/protocol/__init__.py +++ b/libmproxy/protocol/__init__.py @@ -1,4 +1,4 @@ -from ..prxy.server import AddressPriority +from libmproxy.proxy.primitives import AddressPriority KILL = 0 # const for killed requests diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py index 3f9668ae4..77a09e614 100644 --- a/libmproxy/protocol/http.py +++ b/libmproxy/protocol/http.py @@ -1,8 +1,8 @@ import Cookie, urllib, urlparse, time, copy from email.utils import parsedate_tz, formatdate, mktime_tz -from ..prxy.connection import ServerConnection -from ..prxy.exception import ProxyError, ConnectionTypeChange -from ..prxy.server import AddressPriority +from libmproxy.proxy.primitives import AddressPriority +from ..proxy.connection import ServerConnection +from ..proxy.primitives import ProxyError, ConnectionTypeChange import netlib.utils from netlib import http, tcp, http_status from netlib.odict import ODict, ODictCaseless diff --git a/libmproxy/protocol/primitives.py b/libmproxy/protocol/primitives.py index 7cee074de..f27014587 100644 --- a/libmproxy/protocol/primitives.py +++ b/libmproxy/protocol/primitives.py @@ -1,5 +1,5 @@ from .. import stateobject, utils, version -from ..prxy.connection import ClientConnection, ServerConnection +from ..proxy.connection import ClientConnection, ServerConnection import copy diff --git a/libmproxy/prxy/__init__.py b/libmproxy/proxy/__init__.py similarity index 100% rename from libmproxy/prxy/__init__.py rename to libmproxy/proxy/__init__.py diff --git a/libmproxy/proxy/config.py b/libmproxy/proxy/config.py new file mode 100644 index 000000000..38c6ce890 --- /dev/null +++ b/libmproxy/proxy/config.py @@ -0,0 +1,124 @@ +import os +from .. import utils, platform +from netlib import http_auth, certutils + + +TRANSPARENT_SSL_PORTS = [443, 8443] +CONF_BASENAME = "mitmproxy" +CONF_DIR = "~/.mitmproxy" + + +class ProxyConfig: + def __init__(self, confdir=CONF_DIR, clientcerts=None, + no_upstream_cert=False, body_size_limit=None, reverse_proxy=None, + forward_proxy=None, transparent_proxy=None, authenticator=None, + ciphers=None, certs=None + ): + self.ciphers = ciphers + self.clientcerts = clientcerts + self.no_upstream_cert = no_upstream_cert + self.body_size_limit = body_size_limit + self.reverse_proxy = reverse_proxy + self.forward_proxy = forward_proxy + self.transparent_proxy = transparent_proxy + self.authenticator = authenticator + self.confdir = os.path.expanduser(confdir) + self.certstore = certutils.CertStore.from_store(self.confdir, CONF_BASENAME) + + +def process_proxy_options(parser, options): + body_size_limit = utils.parse_size(options.body_size_limit) + if options.reverse_proxy and options.transparent_proxy: + return parser.error("Can't set both reverse proxy and transparent proxy.") + + if options.transparent_proxy: + if not platform.resolver: + return parser.error("Transparent mode not supported on this platform.") + trans = dict( + resolver=platform.resolver(), + sslports=TRANSPARENT_SSL_PORTS + ) + else: + trans = None + + if options.reverse_proxy: + rp = utils.parse_proxy_spec(options.reverse_proxy) + if not rp: + return parser.error("Invalid reverse proxy specification: %s" % options.reverse_proxy) + else: + rp = None + + if options.forward_proxy: + fp = utils.parse_proxy_spec(options.forward_proxy) + if not fp: + return parser.error("Invalid forward proxy specification: %s" % options.forward_proxy) + else: + fp = None + + if options.clientcerts: + options.clientcerts = os.path.expanduser(options.clientcerts) + if not os.path.exists(options.clientcerts) or not os.path.isdir(options.clientcerts): + return parser.error( + "Client certificate directory does not exist or is not a directory: %s" % options.clientcerts + ) + + if (options.auth_nonanonymous or options.auth_singleuser or options.auth_htpasswd): + if options.auth_singleuser: + if len(options.auth_singleuser.split(':')) != 2: + return parser.error("Invalid single-user specification. Please use the format username:password") + username, password = options.auth_singleuser.split(':') + password_manager = http_auth.PassManSingleUser(username, password) + elif options.auth_nonanonymous: + password_manager = http_auth.PassManNonAnon() + elif options.auth_htpasswd: + try: + password_manager = http_auth.PassManHtpasswd(options.auth_htpasswd) + except ValueError, v: + return parser.error(v.message) + authenticator = http_auth.BasicProxyAuth(password_manager, "mitmproxy") + else: + authenticator = http_auth.NullProxyAuth(None) + + certs = [] + for i in options.certs: + parts = i.split("=", 1) + if len(parts) == 1: + parts = ["*", parts[0]] + parts[1] = os.path.expanduser(parts[1]) + if not os.path.exists(parts[1]): + parser.error("Certificate file does not exist: %s"%parts[1]) + certs.append(parts) + + return ProxyConfig( + clientcerts=options.clientcerts, + body_size_limit=body_size_limit, + no_upstream_cert=options.no_upstream_cert, + reverse_proxy=rp, + forward_proxy=fp, + transparent_proxy=trans, + authenticator=authenticator, + ciphers=options.ciphers, + certs = certs, + ) + + +def ssl_option_group(parser): + group = parser.add_argument_group("SSL") + group.add_argument( + "--cert", dest='certs', default=[], type=str, + metavar = "SPEC", action="append", + help='Add an SSL certificate. SPEC is of the form "[domain=]path". '\ + 'The domain may include a wildcard, and is equal to "*" if not specified. '\ + 'The file at path is a certificate in PEM format. If a private key is included in the PEM, '\ + 'it is used, else the default key in the conf dir is used. Can be passed multiple times.' + ) + group.add_argument( + "--client-certs", action="store", + type=str, dest="clientcerts", default=None, + help="Client certificate directory." + ) + group.add_argument( + "--ciphers", action="store", + type=str, dest="ciphers", default=None, + help="SSL cipher specification." + ) \ No newline at end of file diff --git a/libmproxy/prxy/connection.py b/libmproxy/proxy/connection.py similarity index 98% rename from libmproxy/prxy/connection.py rename to libmproxy/proxy/connection.py index b1040c1ce..3a0273af3 100644 --- a/libmproxy/prxy/connection.py +++ b/libmproxy/proxy/connection.py @@ -1,9 +1,10 @@ import copy import os from .. import stateobject, utils -from .exception import ProxyError +from .primitives import ProxyError from netlib import tcp, certutils + class ClientConnection(tcp.BaseHandler, stateobject.SimpleStateObject): def __init__(self, client_connection, address, server): if client_connection: # Eventually, this object is restored from state. We don't have a connection then. diff --git a/libmproxy/proxy/primitives.py b/libmproxy/proxy/primitives.py new file mode 100644 index 000000000..8dd0e16a0 --- /dev/null +++ b/libmproxy/proxy/primitives.py @@ -0,0 +1,40 @@ +class ProxyError(Exception): + def __init__(self, code, msg, headers=None): + self.code, self.msg, self.headers = code, msg, headers + + def __str__(self): + return "ProxyError(%s, %s)" % (self.code, self.msg) + + +class ConnectionTypeChange(Exception): + """ + Gets raised if the connection type has been changed (e.g. after HTTP/1.1 101 Switching Protocols). + It's up to the raising ProtocolHandler to specify the new conntype before raising the exception. + """ + pass + + +class ProxyServerError(Exception): + pass + + +class AddressPriority(object): + """ + Enum that signifies the priority of the given address when choosing the destination host. + Higher is better (None < i) + """ + FORCE = 5 + """forward mode""" + MANUALLY_CHANGED = 4 + """user changed the target address in the ui""" + FROM_SETTINGS = 3 + """reverse proxy mode""" + FROM_CONNECTION = 2 + """derived from transparent resolver""" + FROM_PROTOCOL = 1 + """derived from protocol (e.g. absolute-form http requests)""" + + +class Log: + def __init__(self, msg): + self.msg = msg \ No newline at end of file diff --git a/libmproxy/proxy.py b/libmproxy/proxy/server.py similarity index 62% rename from libmproxy/proxy.py rename to libmproxy/proxy/server.py index ccb47c262..37ec7758b 100644 --- a/libmproxy/proxy.py +++ b/libmproxy/proxy/server.py @@ -1,73 +1,51 @@ -import os import socket -import threading - -from OpenSSL import SSL - -from .prxy.connection import ClientConnection, ServerConnection -from .prxy.exception import ProxyError, ConnectionTypeChange -from .prxy.server import AddressPriority -from netlib import tcp, http, certutils, http_auth -import utils -import version -import platform -import controller +from .. import version, protocol +from libmproxy.proxy.primitives import Log +from .primitives import ProxyServerError +from .connection import ClientConnection, ServerConnection +from .primitives import ProxyError, ConnectionTypeChange, AddressPriority +from netlib import tcp -TRANSPARENT_SSL_PORTS = [443, 8443] -CONF_BASENAME = "mitmproxy" -CONF_DIR = "~/.mitmproxy" -CA_CERT_NAME = "mitmproxy-ca.pem" +class DummyServer: + bound = False + + def __init__(self, config): + self.config = config + + def start_slave(self, *args): + pass + + def shutdown(self): + pass -class Log: - def __init__(self, msg): - self.msg = msg - - -class ProxyConfig: - def __init__(self, confdir=CONF_DIR, clientcerts=None, - no_upstream_cert=False, body_size_limit=None, reverse_proxy=None, - forward_proxy=None, transparent_proxy=None, authenticator=None, - ciphers=None, certs=None - ): - self.ciphers = ciphers - self.clientcerts = clientcerts - self.no_upstream_cert = no_upstream_cert - self.body_size_limit = body_size_limit - self.reverse_proxy = reverse_proxy - self.forward_proxy = forward_proxy - self.transparent_proxy = transparent_proxy - self.authenticator = authenticator - self.confdir = os.path.expanduser(confdir) - self.certstore = certutils.CertStore.from_store(self.confdir, CONF_BASENAME) - - -from . import protocol -from .protocol.http import HTTPResponse - - -class RequestReplayThread(threading.Thread): - name="RequestReplayThread" - - def __init__(self, config, flow, masterq): - self.config, self.flow, self.channel = config, flow, controller.Channel(masterq) - threading.Thread.__init__(self) - - def run(self): +class ProxyServer(tcp.TCPServer): + allow_reuse_address = True + bound = True + def __init__(self, config, port, host='', server_version=version.NAMEVERSION): + """ + Raises ProxyServerError if there's a startup problem. + """ + self.config = config + self.server_version = server_version try: - r = self.flow.request - server = ServerConnection(self.flow.server_conn.address(), None) - server.connect() - if self.flow.server_conn.ssl_established: - server.establish_ssl(self.config.clientcerts, - self.flow.server_conn.sni) - server.send(r._assemble()) - self.flow.response = HTTPResponse.from_stream(server.rfile, r.method, body_size_limit=self.config.body_size_limit) - self.channel.ask("response", self.flow.response) - except (ProxyError, http.HttpError, tcp.NetLibError), v: - self.flow.error = protocol.primitives.Error(str(v)) - self.channel.ask("error", self.flow.error) + tcp.TCPServer.__init__(self, (host, port)) + except socket.error, v: + raise ProxyServerError('Error starting proxy server: ' + v.strerror) + self.channel = None + + def start_slave(self, klass, channel): + slave = klass(channel, self) + slave.start() + + def set_channel(self, channel): + self.channel = channel + + def handle_client_connection(self, conn, client_address): + h = ConnectionHandler(self.config, conn, client_address, self, self.channel, self.server_version) + h.handle() + h.finish() class ConnectionHandler: @@ -174,7 +152,7 @@ class ConnectionHandler: """ Sets a new server address with the given priority. Does not re-establish either connection or SSL handshake. - @type priority: libmproxy.prxy.server.AddressPriority + @type priority: libmproxy.proxy.primitives.AddressPriority """ address = tcp.Address.wrap(address) @@ -241,7 +219,7 @@ class ConnectionHandler: raise ProxyError(502, "SSL to Client already established.") cert, key = self.find_cert() self.client_conn.convert_to_ssl( - cert, key, + cert, key, handle_sni = self.handle_sni, cipher_list = self.config.ciphers ) @@ -306,148 +284,4 @@ class ConnectionHandler: # An unhandled exception in this method will core dump PyOpenSSL, so # make dang sure it doesn't happen. except Exception, e: # pragma: no cover - pass - - -class ProxyServerError(Exception): - pass - - -class ProxyServer(tcp.TCPServer): - allow_reuse_address = True - bound = True - def __init__(self, config, port, host='', server_version=version.NAMEVERSION): - """ - Raises ProxyServerError if there's a startup problem. - """ - self.config = config - self.server_version = server_version - try: - tcp.TCPServer.__init__(self, (host, port)) - except socket.error, v: - raise ProxyServerError('Error starting proxy server: ' + v.strerror) - self.channel = None - - def start_slave(self, klass, channel): - slave = klass(channel, self) - slave.start() - - def set_channel(self, channel): - self.channel = channel - - def handle_client_connection(self, conn, client_address): - h = ConnectionHandler(self.config, conn, client_address, self, self.channel, self.server_version) - h.handle() - h.finish() - - -class DummyServer: - bound = False - - def __init__(self, config): - self.config = config - - def start_slave(self, *args): - pass - - def shutdown(self): - pass - - -# Command-line utils -def ssl_option_group(parser): - group = parser.add_argument_group("SSL") - group.add_argument( - "--cert", dest='certs', default=[], type=str, - metavar = "SPEC", action="append", - help='Add an SSL certificate. SPEC is of the form "[domain=]path". '\ - 'The domain may include a wildcard, and is equal to "*" if not specified. '\ - 'The file at path is a certificate in PEM format. If a private key is included in the PEM, '\ - 'it is used, else the default key in the conf dir is used. Can be passed multiple times.' - ) - group.add_argument( - "--client-certs", action="store", - type=str, dest="clientcerts", default=None, - help="Client certificate directory." - ) - group.add_argument( - "--ciphers", action="store", - type=str, dest="ciphers", default=None, - help="SSL cipher specification." - ) - - -def process_proxy_options(parser, options): - body_size_limit = utils.parse_size(options.body_size_limit) - if options.reverse_proxy and options.transparent_proxy: - return parser.error("Can't set both reverse proxy and transparent proxy.") - - if options.transparent_proxy: - if not platform.resolver: - return parser.error("Transparent mode not supported on this platform.") - trans = dict( - resolver=platform.resolver(), - sslports=TRANSPARENT_SSL_PORTS - ) - else: - trans = None - - if options.reverse_proxy: - rp = utils.parse_proxy_spec(options.reverse_proxy) - if not rp: - return parser.error("Invalid reverse proxy specification: %s" % options.reverse_proxy) - else: - rp = None - - if options.forward_proxy: - fp = utils.parse_proxy_spec(options.forward_proxy) - if not fp: - return parser.error("Invalid forward proxy specification: %s" % options.forward_proxy) - else: - fp = None - - if options.clientcerts: - options.clientcerts = os.path.expanduser(options.clientcerts) - if not os.path.exists(options.clientcerts) or not os.path.isdir(options.clientcerts): - return parser.error( - "Client certificate directory does not exist or is not a directory: %s" % options.clientcerts - ) - - if (options.auth_nonanonymous or options.auth_singleuser or options.auth_htpasswd): - if options.auth_singleuser: - if len(options.auth_singleuser.split(':')) != 2: - return parser.error("Invalid single-user specification. Please use the format username:password") - username, password = options.auth_singleuser.split(':') - password_manager = http_auth.PassManSingleUser(username, password) - elif options.auth_nonanonymous: - password_manager = http_auth.PassManNonAnon() - elif options.auth_htpasswd: - try: - password_manager = http_auth.PassManHtpasswd(options.auth_htpasswd) - except ValueError, v: - return parser.error(v.message) - authenticator = http_auth.BasicProxyAuth(password_manager, "mitmproxy") - else: - authenticator = http_auth.NullProxyAuth(None) - - certs = [] - for i in options.certs: - parts = i.split("=", 1) - if len(parts) == 1: - parts = ["*", parts[0]] - parts[1] = os.path.expanduser(parts[1]) - if not os.path.exists(parts[1]): - parser.error("Certificate file does not exist: %s"%parts[1]) - certs.append(parts) - - return ProxyConfig( - clientcerts=options.clientcerts, - body_size_limit=body_size_limit, - no_upstream_cert=options.no_upstream_cert, - reverse_proxy=rp, - forward_proxy=fp, - transparent_proxy=trans, - authenticator=authenticator, - ciphers=options.ciphers, - certs = certs, - ) + pass \ No newline at end of file diff --git a/libmproxy/prxy/exception.py b/libmproxy/prxy/exception.py deleted file mode 100644 index c43a5d75d..000000000 --- a/libmproxy/prxy/exception.py +++ /dev/null @@ -1,14 +0,0 @@ -class ProxyError(Exception): - def __init__(self, code, msg, headers=None): - self.code, self.msg, self.headers = code, msg, headers - - def __str__(self): - return "ProxyError(%s, %s)" % (self.code, self.msg) - - -class ConnectionTypeChange(Exception): - """ - Gets raised if the connection type has been changed (e.g. after HTTP/1.1 101 Switching Protocols). - It's up to the raising ProtocolHandler to specify the new conntype before raising the exception. - """ - pass \ No newline at end of file diff --git a/libmproxy/prxy/server.py b/libmproxy/prxy/server.py deleted file mode 100644 index 441b29b47..000000000 --- a/libmproxy/prxy/server.py +++ /dev/null @@ -1,18 +0,0 @@ -__author__ = 'user' - - -class AddressPriority(object): - """ - Enum that signifies the priority of the given address when choosing the destination host. - Higher is better (None < i) - """ - FORCE = 5 - """forward mode""" - MANUALLY_CHANGED = 4 - """user changed the target address in the ui""" - FROM_SETTINGS = 3 - """reverse proxy mode""" - FROM_CONNECTION = 2 - """derived from transparent resolver""" - FROM_PROTOCOL = 1 - """derived from protocol (e.g. absolute-form http requests)""" \ No newline at end of file diff --git a/mitmdump b/mitmdump index 49d129d6a..5ab7c0766 100755 --- a/mitmdump +++ b/mitmdump @@ -1,6 +1,9 @@ #!/usr/bin/env python import sys, signal from libmproxy import proxy, dump, cmdline +from libmproxy.proxy.config import process_proxy_options +from libmproxy.proxy.primitives import ProxyServerError +from libmproxy.proxy.server import DummyServer, ProxyServer import libmproxy.version, netlib.version import argparse @@ -25,13 +28,13 @@ if __name__ == '__main__': if options.quiet: options.verbose = 0 - proxyconfig = proxy.process_proxy_options(parser, options) + proxyconfig = process_proxy_options(parser, options) if options.no_server: - server = proxy.DummyServer(proxyconfig) + server = DummyServer(proxyconfig) else: try: - server = proxy.ProxyServer(proxyconfig, options.port, options.addr) - except proxy.ProxyServerError, v: + server = ProxyServer(proxyconfig, options.port, options.addr) + except ProxyServerError, v: print >> sys.stderr, "mitmdump:", v.args[0] sys.exit(1) diff --git a/mitmproxy b/mitmproxy index 7cc9e3f94..934d17725 100755 --- a/mitmproxy +++ b/mitmproxy @@ -1,6 +1,9 @@ #!/usr/bin/env python import sys, argparse, os from libmproxy import proxy, console, cmdline +from libmproxy.proxy.config import process_proxy_options +from libmproxy.proxy.primitives import ProxyServerError +from libmproxy.proxy.server import DummyServer, ProxyServer import libmproxy.version, netlib.version from libmproxy.console import palettes @@ -33,14 +36,14 @@ if __name__ == '__main__': ) options = parser.parse_args() - config = proxy.process_proxy_options(parser, options) + config = process_proxy_options(parser, options) if options.no_server: - server = proxy.DummyServer(config) + server = DummyServer(config) else: try: - server = proxy.ProxyServer(config, options.port, options.addr) - except proxy.ProxyServerError, v: + server = ProxyServer(config, options.port, options.addr) + except ProxyServerError, v: print >> sys.stderr, "mitmproxy:", v.args[0] sys.exit(1) diff --git a/test/test_dump.py b/test/test_dump.py index c5c231fa4..0f7d9bea0 100644 --- a/test/test_dump.py +++ b/test/test_dump.py @@ -1,6 +1,7 @@ import os from cStringIO import StringIO -from libmproxy import dump, flow, proxy, prxy +from libmproxy import dump, flow, proxy +from libmproxy.proxy.primitives import Log import tutils import mock @@ -21,13 +22,13 @@ def test_strfuncs(): class TestDumpMaster: def _cycle(self, m, content): req = tutils.treq(content=content) - l = proxy.Log("connect") + l = Log("connect") l.reply = mock.MagicMock() m.handle_log(l) cc = req.flow.client_conn cc.reply = mock.MagicMock() m.handle_clientconnect(cc) - sc = prxy.connection.ServerConnection((req.get_host(), req.get_port()), None) + sc = proxy.connection.ServerConnection((req.get_host(), req.get_port()), None) sc.reply = mock.MagicMock() m.handle_serverconnection(sc) m.handle_request(req) diff --git a/test/test_flow.py b/test/test_flow.py index c7e39f738..2365c08c9 100644 --- a/test/test_flow.py +++ b/test/test_flow.py @@ -1,10 +1,10 @@ import Queue, time, os.path from cStringIO import StringIO import email.utils -from libmproxy import filt, protocol, controller, utils, tnetstring, proxy, flow +from libmproxy import filt, protocol, controller, utils, tnetstring, flow from libmproxy.protocol.primitives import Error, Flow -from libmproxy.protocol.http import decoded -from libmproxy.prxy.connection import ClientConnection, ServerConnection +from libmproxy.protocol.http import decoded, CONTENT_MISSING +from libmproxy.proxy.connection import ClientConnection, ServerConnection from netlib import tcp import tutils @@ -566,7 +566,7 @@ class TestFlowMaster: s = flow.State() fm = flow.FlowMaster(None, s) f = tutils.tflow_full() - f.request.content = flow.CONTENT_MISSING + f.request.content = CONTENT_MISSING assert "missing" in fm.replay_request(f) f.intercepting = True @@ -796,7 +796,7 @@ class TestRequest: assert r._assemble() assert r.size() == len(r._assemble()) - r.content = flow.CONTENT_MISSING + r.content = CONTENT_MISSING tutils.raises("Cannot assemble flow with CONTENT_MISSING", r._assemble) def test_get_url(self): @@ -1004,7 +1004,7 @@ class TestResponse: assert resp._assemble() assert resp.size() == len(resp._assemble()) - resp.content = flow.CONTENT_MISSING + resp.content = CONTENT_MISSING tutils.raises("Cannot assemble flow with CONTENT_MISSING", resp._assemble) def test_refresh(self): diff --git a/test/test_protocol_http.py b/test/test_protocol_http.py index 3f37928cb..6ff0cb65a 100644 --- a/test/test_protocol_http.py +++ b/test/test_protocol_http.py @@ -1,4 +1,3 @@ -from libmproxy import proxy # FIXME: Remove from libmproxy.protocol.http import * from libmproxy.protocol import KILL from cStringIO import StringIO diff --git a/test/test_proxy.py b/test/test_proxy.py index 2a4a250e6..f53aa7621 100644 --- a/test/test_proxy.py +++ b/test/test_proxy.py @@ -1,7 +1,9 @@ import argparse -from libmproxy import proxy, flow, cmdline -from libmproxy.prxy.connection import ServerConnection -from libmproxy.prxy.exception import ProxyError +from libmproxy import cmdline +from libmproxy.proxy.config import process_proxy_options +from libmproxy.proxy.connection import ServerConnection +from libmproxy.proxy.primitives import ProxyError +from libmproxy.proxy.server import DummyServer, ProxyServer import tutils from libpathod import test from netlib import http, tcp @@ -58,7 +60,7 @@ class TestProcessProxyOptions: cmdline.common_options(parser) opts = parser.parse_args(args=args) m = MockParser() - return m, proxy.process_proxy_options(m, opts) + return m, process_proxy_options(m, opts) def assert_err(self, err, *args): m, p = self.p(*args) @@ -117,12 +119,12 @@ class TestProxyServer: parser = argparse.ArgumentParser() cmdline.common_options(parser) opts = parser.parse_args(args=[]) - tutils.raises("error starting proxy server", proxy.ProxyServer, opts, 1) + tutils.raises("error starting proxy server", ProxyServer, opts, 1) class TestDummyServer: def test_simple(self): - d = proxy.DummyServer(None) + d = DummyServer(None) d.start_slave() d.shutdown() diff --git a/test/test_server.py b/test/test_server.py index ed21e75ce..43ef546d1 100644 --- a/test/test_server.py +++ b/test/test_server.py @@ -3,8 +3,8 @@ import mock from netlib import tcp, http_auth, http from libpathod import pathoc, pathod import tutils, tservers -from libmproxy import flow, proxy from libmproxy.protocol import KILL +from libmproxy.protocol.http import CONTENT_MISSING """ Note that the choice of response code in these tests matters more than you @@ -381,7 +381,7 @@ class TestTransparentResolveError(tservers.TransparentProxTest): class MasterIncomplete(tservers.TestMaster): def handle_request(self, m): resp = tutils.tresp() - resp.content = flow.CONTENT_MISSING + resp.content = CONTENT_MISSING m.reply(resp) diff --git a/test/tservers.py b/test/tservers.py index cf9b3f73e..bfafc8cd6 100644 --- a/test/tservers.py +++ b/test/tservers.py @@ -2,8 +2,10 @@ import os.path import threading, Queue import shutil, tempfile import flask +from libmproxy.proxy.config import ProxyConfig +from libmproxy.proxy.server import ProxyServer import libpathod.test, libpathod.pathoc -from libmproxy import proxy, flow, controller +from libmproxy import flow, controller from libmproxy.cmdline import APP_HOST, APP_PORT import tutils @@ -24,7 +26,7 @@ def errapp(environ, start_response): class TestMaster(flow.FlowMaster): def __init__(self, config): - s = proxy.ProxyServer(config, 0) + s = ProxyServer(config, 0) state = flow.State() flow.FlowMaster.__init__(self, s, state) self.apps.add(testapp, "testapp", 80) @@ -84,7 +86,7 @@ class ProxTestBase(object): cls.server2 = libpathod.test.Daemon(ssl=cls.ssl, ssloptions=cls.ssloptions) pconf = cls.get_proxy_config() cls.confdir = os.path.join(tempfile.gettempdir(), "mitmproxy") - config = proxy.ProxyConfig( + config = ProxyConfig( no_upstream_cert = cls.no_upstream_cert, confdir = cls.confdir, authenticator = cls.authenticator, @@ -256,7 +258,7 @@ class ChainProxTest(ProxTestBase): Chain n instances of mitmproxy in a row - because we can. """ n = 2 - chain_config = [lambda: proxy.ProxyConfig( + chain_config = [lambda: ProxyConfig( )] * n @classmethod def setupAll(cls): diff --git a/test/tutils.py b/test/tutils.py index 8690d67d0..3f6592b0e 100644 --- a/test/tutils.py +++ b/test/tutils.py @@ -1,8 +1,8 @@ import os, shutil, tempfile from contextlib import contextmanager -from libmproxy import flow, utils, controller, proxy +from libmproxy import flow, utils, controller from libmproxy.protocol import http -from libmproxy.prxy.connection import ClientConnection, ServerConnection +from libmproxy.proxy.connection import ClientConnection, ServerConnection import mock_urwid from libmproxy.console.flowview import FlowView from libmproxy.console import ConsoleState From dd3aedca01a61f2fe33d009320f7fe656f1fc671 Mon Sep 17 00:00:00 2001 From: Maximilian Hils Date: Sun, 9 Mar 2014 21:59:53 +0100 Subject: [PATCH 3/3] fix mentions of CONTENT_MISSING in libmproxy.console --- libmproxy/console/common.py | 5 +++-- libmproxy/console/flowview.py | 7 ++++--- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/libmproxy/console/common.py b/libmproxy/console/common.py index 715bed801..7e2ecbf53 100644 --- a/libmproxy/console/common.py +++ b/libmproxy/console/common.py @@ -1,6 +1,7 @@ import urwid import urwid.util -from .. import utils, flow +from .. import utils +from ..protocol.http import CONTENT_MISSING VIEW_LIST = 0 @@ -183,7 +184,7 @@ def format_flow(f, focus, extended=False, hostheader=False, padding=2): if f.response: if f.response.content: contentdesc = utils.pretty_size(len(f.response.content)) - elif f.response.content == flow.CONTENT_MISSING: + elif f.response.content == CONTENT_MISSING: contentdesc = "[content missing]" else: contentdesc = "[no content]" diff --git a/libmproxy/console/flowview.py b/libmproxy/console/flowview.py index 3486f57e7..f5b5f83f4 100644 --- a/libmproxy/console/flowview.py +++ b/libmproxy/console/flowview.py @@ -2,6 +2,7 @@ import os, sys, copy import urwid import common, grideditor, contentview from .. import utils, flow, controller +from ..protocol.http import CONTENT_MISSING class SearchError(Exception): pass @@ -150,7 +151,7 @@ class FlowView(common.WWrap): return (description, text_objects) def cont_view_handle_missing(self, conn, viewmode): - if conn.content == flow.CONTENT_MISSING: + if conn.content == CONTENT_MISSING: msg, body = "", [urwid.Text([("error", "[content missing]")])], 0 else: msg, body = self.content_view(viewmode, conn) @@ -178,7 +179,7 @@ class FlowView(common.WWrap): override = self.override_get() viewmode = self.viewmode_get(override) msg, body = self.cont_view_handle_missing(conn, viewmode) - elif conn.content == flow.CONTENT_MISSING: + elif conn.content == CONTENT_MISSING: pass return headers, msg, body @@ -643,7 +644,7 @@ class FlowView(common.WWrap): def delete_body(self, t): if t == "m": - val = flow.CONTENT_MISSING + val = CONTENT_MISSING else: val = None if self.state.view_flow_mode == common.VIEW_FLOW_REQUEST: