This commit is contained in:
Maximilian Hils 2014-08-24 14:22:11 +02:00
parent e4d6089f9a
commit b97b1f17cf
4 changed files with 49 additions and 40 deletions

View File

@ -704,7 +704,7 @@ class FlowMaster(controller.Master):
return f return f
def handle_request(self, r): def handle_request(self, r):
if r.flow.client_conn and r.flow.client_conn.wfile: if r.flow.live:
app = self.apps.get(r) app = self.apps.get(r)
if app: if app:
err = app.serve(r, r.flow.client_conn.wfile, **{"mitmproxy.master": self}) err = app.serve(r, r.flow.client_conn.wfile, **{"mitmproxy.master": self})

View File

@ -5,7 +5,7 @@ import threading
from netlib import http, tcp, http_status from netlib import http, tcp, http_status
import netlib.utils import netlib.utils
from netlib.odict import ODict, ODictCaseless from netlib.odict import ODict, ODictCaseless
from .primitives import KILL, ProtocolHandler, TemporaryServerChangeMixin, Flow, Error from .primitives import KILL, ProtocolHandler, LiveConnection, Flow, Error
from ..proxy.connection import ServerConnection from ..proxy.connection import ServerConnection
from .. import encoding, utils, controller, stateobject, proxy from .. import encoding, utils, controller, stateobject, proxy
@ -543,8 +543,8 @@ class HTTPRequest(HTTPMessage):
self.path = path self.path = path
if host != self.get_host() or port != self.get_port(): if host != self.get_host() or port != self.get_port():
if self.flow.change_server: if self.flow.live:
self.flow.change_server((host, port), ssl=is_ssl) self.flow.live.change_server((host, port), ssl=is_ssl)
else: else:
# There's not live server connection, we're just changing the attributes here. # There's not live server connection, we're just changing the attributes here.
self.flow.server_conn = ServerConnection((host, port), self.flow.server_conn = ServerConnection((host, port),
@ -789,15 +789,15 @@ class HTTPFlow(Flow):
The following additional attributes are exposed: The following additional attributes are exposed:
intercepting: Is this flow currently being intercepted? intercepting: Is this flow currently being intercepted?
live: Does this flow have a live client connection?
""" """
def __init__(self, client_conn, server_conn, change_server=None): def __init__(self, client_conn, server_conn, live=None):
super(HTTPFlow, self).__init__("http", client_conn, server_conn) super(HTTPFlow, self).__init__("http", client_conn, server_conn, live)
self.request = None self.request = None
"""@type: HTTPRequest""" """@type: HTTPRequest"""
self.response = None self.response = None
"""@type: HTTPResponse""" """@type: HTTPResponse"""
self.change_server = change_server # Used by flow.request.set_url to change the server address
self.intercepting = False # FIXME: Should that rather be an attribute of Flow? self.intercepting = False # FIXME: Should that rather be an attribute of Flow?
@ -904,7 +904,7 @@ class HttpAuthenticationError(Exception):
return "Proxy Authentication Required" return "Proxy Authentication Required"
class HTTPHandler(ProtocolHandler, TemporaryServerChangeMixin): class HTTPHandler(ProtocolHandler):
def __init__(self, c): def __init__(self, c):
super(HTTPHandler, self).__init__(c) super(HTTPHandler, self).__init__(c)
self.expected_form_in = c.config.http_form_in self.expected_form_in = c.config.http_form_in
@ -943,7 +943,7 @@ class HTTPHandler(ProtocolHandler, TemporaryServerChangeMixin):
raise v raise v
def handle_flow(self): def handle_flow(self):
flow = HTTPFlow(self.c.client_conn, self.c.server_conn, self.change_server) flow = HTTPFlow(self.c.client_conn, self.c.server_conn, self.live)
try: try:
req = HTTPRequest.from_stream(self.c.client_conn.rfile, req = HTTPRequest.from_stream(self.c.client_conn.rfile,
body_size_limit=self.c.config.body_size_limit) body_size_limit=self.c.config.body_size_limit)
@ -1038,7 +1038,8 @@ class HTTPHandler(ProtocolHandler, TemporaryServerChangeMixin):
# If the user has changed the target server on this connection, # If the user has changed the target server on this connection,
# restore the original target server # restore the original target server
self.restore_server() flow.live.restore_server()
flow.live = None
return True return True
except (HttpAuthenticationError, http.HttpError, proxy.ProxyError, tcp.NetLibError), e: except (HttpAuthenticationError, http.HttpError, proxy.ProxyError, tcp.NetLibError), e:

View File

@ -71,12 +71,14 @@ class Error(stateobject.SimpleStateObject):
class Flow(stateobject.SimpleStateObject, BackreferenceMixin): class Flow(stateobject.SimpleStateObject, BackreferenceMixin):
def __init__(self, conntype, client_conn, server_conn): def __init__(self, conntype, client_conn, server_conn, live=None):
self.conntype = conntype self.conntype = conntype
self.client_conn = client_conn self.client_conn = client_conn
"""@type: ClientConnection""" """@type: ClientConnection"""
self.server_conn = server_conn self.server_conn = server_conn
"""@type: ServerConnection""" """@type: ServerConnection"""
self.live = live # Used by flow.request.set_url to change the server address
"""@type: LiveConnection"""
self.error = None self.error = None
"""@type: Error""" """@type: Error"""
@ -140,6 +142,8 @@ class ProtocolHandler(object):
def __init__(self, c): def __init__(self, c):
self.c = c self.c = c
"""@type: libmproxy.proxy.server.ConnectionHandler""" """@type: libmproxy.proxy.server.ConnectionHandler"""
self.live = LiveConnection(c)
"""@type: LiveConnection"""
def handle_messages(self): def handle_messages(self):
""" """
@ -164,46 +168,50 @@ class ProtocolHandler(object):
raise error # pragma: nocover raise error # pragma: nocover
class TemporaryServerChangeMixin(object): class LiveConnection(object):
""" """
This mixin allows safe modification of the target server, This facade allows protocol handlers to interface with a live connection,
without any need to expose the ConnectionHandler to the Flow. without requiring the expose the ConnectionHandler.
""" """
def change_server(self, address, ssl): def __init__(self, c):
self._c = c
"""@type: libmproxy.proxy.server.ConnectionHandler"""
def change_server(self, address, ssl, persistent_change=False):
address = netlib.tcp.Address.wrap(address) address = netlib.tcp.Address.wrap(address)
if address == self.c.server_conn.address(): if address != self._c.server_conn.address:
return
priority = AddressPriority.MANUALLY_CHANGED
self.c.log("Temporarily change server connection: %s:%s -> %s:%s" % ( self._c.log("Change server connection: %s:%s -> %s:%s" % (
self.c.server_conn.address.host, self._c.server_conn.address.host,
self.c.server_conn.address.port, self._c.server_conn.address.port,
address.host, address.host,
address.port address.port
), "debug") ), "debug")
if not hasattr(self, "_backup_server_conn"): if not hasattr(self, "_backup_server_conn"):
self._backup_server_conn = self.c.server_conn self._backup_server_conn = self._c.server_conn
self.c.server_conn = None self._c.server_conn = None
else: # This is at least the second temporary change. We can kill the current connection. else: # This is at least the second temporary change. We can kill the current connection.
self.c.del_server_connection() self._c.del_server_connection()
self.c.set_server_address(address, priority) self._c.set_server_address(address, AddressPriority.MANUALLY_CHANGED)
self.c.establish_server_connection(ask=False) self._c.establish_server_connection(ask=False)
if ssl: if ssl:
self.c.establish_ssl(server=True) self._c.establish_ssl(server=True)
if hasattr(self, "_backup_server_conn") and persistent_change:
del self._backup_server_conn
def restore_server(self): def restore_server(self):
if not hasattr(self, "_backup_server_conn"): if not hasattr(self, "_backup_server_conn"):
return return
self.c.log("Restore original server connection: %s:%s -> %s:%s" % ( self._c.log("Restore original server connection: %s:%s -> %s:%s" % (
self.c.server_conn.address.host, self._c.server_conn.address.host,
self.c.server_conn.address.port, self._c.server_conn.address.port,
self._backup_server_conn.address.host, self._backup_server_conn.address.host,
self._backup_server_conn.address.port self._backup_server_conn.address.port
), "debug") ), "debug")
self.c.del_server_connection() self._c.del_server_connection()
self.c.server_conn = self._backup_server_conn self._c.server_conn = self._backup_server_conn
del self._backup_server_conn del self._backup_server_conn

View File

@ -338,9 +338,9 @@ class MasterRedirectRequest(tservers.TestMaster):
request.set_url(new) request.set_url(new)
request.set_url(new) request.set_url(new)
request.flow.change_server(("127.0.0.1", self.redirect_port), False) request.flow.live.change_server(("127.0.0.1", self.redirect_port), False)
request.set_url(url) request.set_url(url)
tutils.raises("SSL handshake error", request.flow.change_server, ("127.0.0.1", self.redirect_port), True) tutils.raises("SSL handshake error", request.flow.live.change_server, ("127.0.0.1", self.redirect_port), True)
request.set_url(new) request.set_url(new)
request.set_url(url) request.set_url(url)
request.set_url(new) request.set_url(new)