diff options
author | Maximilian Hils <git@maximilianhils.com> | 2014-08-30 20:15:19 +0200 |
---|---|---|
committer | Maximilian Hils <git@maximilianhils.com> | 2014-08-30 20:15:19 +0200 |
commit | 1f47f7b6b29cd1229264edf75194652824d94705 (patch) | |
tree | 4b52337daddbc97aa40b80ea84e795cf7448be9b /libmproxy/protocol | |
parent | 82730c1c6ff4a1e593de48309d02de2b49cade5d (diff) | |
download | mitmproxy-1f47f7b6b29cd1229264edf75194652824d94705.tar.gz mitmproxy-1f47f7b6b29cd1229264edf75194652824d94705.tar.bz2 mitmproxy-1f47f7b6b29cd1229264edf75194652824d94705.zip |
refactor protocol handling, fix #332
Diffstat (limited to 'libmproxy/protocol')
-rw-r--r-- | libmproxy/protocol/handle.py | 27 | ||||
-rw-r--r-- | libmproxy/protocol/http.py | 55 | ||||
-rw-r--r-- | libmproxy/protocol/tcp.py | 4 |
3 files changed, 50 insertions, 36 deletions
diff --git a/libmproxy/protocol/handle.py b/libmproxy/protocol/handle.py index a238b349..100c7368 100644 --- a/libmproxy/protocol/handle.py +++ b/libmproxy/protocol/handle.py @@ -6,21 +6,12 @@ protocols = { 'tcp': dict(handler=tcp.TCPHandler) } - -def _handler(conntype, connection_handler): - if conntype in protocols: - return protocols[conntype]["handler"](connection_handler) - - raise NotImplementedError # pragma: nocover - - -def handle_messages(conntype, connection_handler): - return _handler(conntype, connection_handler).handle_messages() - - -def handle_error(conntype, connection_handler, error): - return _handler(conntype, connection_handler).handle_error(error) - - -def handle_server_reconnect(conntype, connection_handler, state): - return _handler(conntype, connection_handler).handle_server_reconnect(state)
\ No newline at end of file +def protocol_handler(protocol): + """ + @type protocol: str + @returns: libmproxy.protocol.primitives.ProtocolHandler + """ + if protocol in protocols: + return protocols[protocol]["handler"] + + raise NotImplementedError("Unknown Protocol: %s" % protocol) # pragma: nocover
\ No newline at end of file diff --git a/libmproxy/protocol/http.py b/libmproxy/protocol/http.py index 38a6cb49..b635d071 100644 --- a/libmproxy/protocol/http.py +++ b/libmproxy/protocol/http.py @@ -5,7 +5,8 @@ import threading from netlib import http, tcp, http_status import netlib.utils from netlib.odict import ODict, ODictCaseless -from .primitives import KILL, ProtocolHandler, LiveConnection, Flow, Error +from .tcp import TCPHandler +from .primitives import KILL, ProtocolHandler, Flow, Error from ..proxy.connection import ServerConnection from .. import encoding, utils, controller, stateobject, proxy @@ -914,7 +915,6 @@ class HTTPHandler(ProtocolHandler): def handle_messages(self): while self.handle_flow(): pass - self.c.close = True def get_response_from_server(self, request, include_body=True): self.c.establish_server_connection() @@ -948,9 +948,9 @@ class HTTPHandler(ProtocolHandler): req = HTTPRequest.from_stream(self.c.client_conn.rfile, body_size_limit=self.c.config.body_size_limit) self.c.log("request", "debug", [req._assemble_first_line(req.form_in)]) - send_request_upstream = self.process_request(flow, req) - if not send_request_upstream: - return True + ret = self.process_request(flow, req) + if ret is not None: + return ret # Be careful NOT to assign the request to the flow before # process_request completes. This is because the call can raise an @@ -959,7 +959,7 @@ class HTTPHandler(ProtocolHandler): # sent through to the Master. flow.request = req request_reply = self.c.channel.ask("request", flow.request) - self.determine_server_address(flow, flow.request) + self.determine_server_address(flow, flow.request) # The inline script may have changed request.host flow.server_conn = self.c.server_conn # Update server_conn attribute on the flow if request_reply is None or request_reply == KILL: @@ -1025,6 +1025,7 @@ class HTTPHandler(ProtocolHandler): else: return False + # We sent a CONNECT request to an upstream proxy. if flow.request.form_in == "authority" and flow.response.code == 200: # TODO: Eventually add headers (space/usefulness tradeoff) # Make sure to add state info before the actual upgrade happens. @@ -1034,7 +1035,15 @@ class HTTPHandler(ProtocolHandler): self.c.server_conn.state.append(("http", {"state": "connect", "host": flow.request.host, "port": flow.request.port})) - self.ssl_upgrade() + + if self.c.check_ignore_address((flow.request.host, flow.request.port)): + self.c.log("Ignore host: %s:%s" % self.c.server_conn.address(), "info") + TCPHandler(self.c).handle_messages() + return False + else: + if flow.request.port in self.c.config.ssl_ports: + self.ssl_upgrade() + self.skip_authentication = True # If the user has changed the target server on this connection, # restore the original target server @@ -1065,7 +1074,7 @@ class HTTPHandler(ProtocolHandler): if flow: flow.error = Error(message) - # FIXME: no flows without request or with both request and response at the moement. + # FIXME: no flows without request or with both request and response at the moment. if flow.request and not flow.response: self.c.channel.ask("error", flow.error) else: @@ -1103,6 +1112,13 @@ class HTTPHandler(ProtocolHandler): self.c.log("Upgrade to SSL completed.", "debug") def process_request(self, flow, request): + """ + @returns: + True, if the request should not be sent upstream + False, if the connection should be aborted + None, if the request should be sent upstream + (a status code != None should be returned directly by handle_flow) + """ if not self.skip_authentication: self.authenticate(request) @@ -1115,8 +1131,8 @@ class HTTPHandler(ProtocolHandler): if not self.c.config.get_upstream_server: self.c.set_server_address((request.host, request.port), proxy.AddressPriority.FROM_PROTOCOL) - self.c.establish_server_connection() flow.server_conn = self.c.server_conn # Update server_conn attribute on the flow + self.c.establish_server_connection() self.c.client_conn.send( 'HTTP/1.1 200 Connection established\r\n' + 'Content-Length: 0\r\n' + @@ -1124,18 +1140,24 @@ class HTTPHandler(ProtocolHandler): '\r\n' ) - self.ssl_upgrade() - self.skip_authentication = True - return False + if self.c.check_ignore_address(self.c.server_conn.address): + self.c.log("Ignore host: %s:%s" % self.c.server_conn.address(), "info") + TCPHandler(self.c).handle_messages() + return False + else: + if self.c.server_conn.address.port in self.c.config.ssl_ports: + self.ssl_upgrade() + self.skip_authentication = True + return True else: - return True + return None elif request.form_in == self.expected_form_in: if request.form_in == "absolute": if request.scheme != "http": raise http.HttpError(400, "Invalid request scheme: %s" % request.scheme) self.determine_server_address(flow, request) request.form_out = self.expected_form_out - return True + return None raise http.HttpError(400, "Invalid HTTP request form (expected: %s, got: %s)" % (self.expected_form_in, request.form_in)) @@ -1172,10 +1194,11 @@ class RequestReplayThread(threading.Thread): server_address, server_ssl = False, False if self.config.get_upstream_server: try: + # this will fail in transparent mode upstream_info = self.config.get_upstream_server(self.flow.client_conn) server_ssl = upstream_info[1] server_address = upstream_info[2:] - except proxy.ProxyError: # this will fail in transparent mode + except proxy.ProxyError: pass if not server_address: server_address = (r.get_host(), r.get_port()) @@ -1184,7 +1207,7 @@ class RequestReplayThread(threading.Thread): server.connect() if server_ssl or r.get_scheme() == "https": - if self.config.http_form_out == "absolute": + if self.config.http_form_out == "absolute": # form_out == absolute -> forward mode -> send CONNECT send_connect_request(server, r.get_host(), r.get_port()) r.form_out = "relative" server.establish_ssl(self.config.clientcerts, diff --git a/libmproxy/protocol/tcp.py b/libmproxy/protocol/tcp.py index a77a9096..00dbf4b3 100644 --- a/libmproxy/protocol/tcp.py +++ b/libmproxy/protocol/tcp.py @@ -18,7 +18,7 @@ class TCPHandler(ProtocolHandler): buf = memoryview(bytearray(self.chunk_size)) conns = [self.c.client_conn.rfile, self.c.server_conn.rfile] - while not self.c.close: + while True: r, _, _ = select.select(conns, [], [], 10) for rfile in r: if self.c.client_conn.rfile == rfile: @@ -51,7 +51,7 @@ class TCPHandler(ProtocolHandler): dst.connection.shutdown(socket.SHUT_WR) if len(conns) == 0: - self.c.close = True + return continue if src.ssl_established or dst.ssl_established: |