diff options
author | Thomas Kriechbaumer <thomas@kriechbaumer.name> | 2015-08-16 15:19:11 +0200 |
---|---|---|
committer | Thomas Kriechbaumer <thomas@kriechbaumer.name> | 2015-08-16 15:19:11 +0200 |
commit | 38c456bb627c4570e0ed983229ec8ef2f120a4b6 (patch) | |
tree | 2119fb74f6f4884b2e7edd91322ac09d3b6cd7e3 | |
parent | c04fa1b233224d28e85be34ab5b6a8718497488c (diff) | |
download | mitmproxy-38c456bb627c4570e0ed983229ec8ef2f120a4b6.tar.gz mitmproxy-38c456bb627c4570e0ed983229ec8ef2f120a4b6.tar.bz2 mitmproxy-38c456bb627c4570e0ed983229ec8ef2f120a4b6.zip |
implement Http1 and Http2 protocols as layers
-rw-r--r-- | libmproxy/protocol2/http.py | 51 | ||||
-rw-r--r-- | libmproxy/protocol2/http_protocol_mock.py | 50 | ||||
-rw-r--r-- | libmproxy/protocol2/http_proxy.py | 8 | ||||
-rw-r--r-- | libmproxy/protocol2/layer.py | 1 | ||||
-rw-r--r-- | libmproxy/protocol2/root_context.py | 13 | ||||
-rw-r--r-- | libmproxy/protocol2/tls.py | 1 |
6 files changed, 54 insertions, 70 deletions
diff --git a/libmproxy/protocol2/http.py b/libmproxy/protocol2/http.py index 7cc27652..cabec806 100644 --- a/libmproxy/protocol2/http.py +++ b/libmproxy/protocol2/http.py @@ -9,15 +9,42 @@ from libmproxy.protocol import KILL from libmproxy.protocol.http import HTTPFlow from libmproxy.protocol.http_wrappers import HTTPResponse, HTTPRequest -from libmproxy.protocol2.http_protocol_mock import HTTP1 from libmproxy.protocol2.tls import TlsLayer from netlib import tcp from netlib.http import status_codes, http1, HttpErrorConnClosed from netlib.http.semantics import CONTENT_MISSING from netlib import odict from netlib.tcp import NetLibError +from netlib.http.http1 import HTTP1Protocol +from netlib.http.http2 import HTTP2Protocol + +class Http1Layer(Layer): + def __init__(self, ctx, mode): + super(Http1Layer, self).__init__(ctx) + self.mode = mode + self.client_protocol = HTTP1Protocol(self.client_conn) + self.server_protocol = HTTP1Protocol(self.server_conn) + + def __call__(self): + from .http import HttpLayer + layer = HttpLayer(self, self.mode) + for message in layer(): + yield message +class Http2Layer(Layer): + def __init__(self, ctx, mode): + super(Http2Layer, self).__init__(ctx) + self.mode = mode + self.client_protocol = HTTP2Protocol(self.client_conn, is_server=True) + self.server_protocol = HTTP2Protocol(self.server_conn, is_server=False) + + def __call__(self): + from .http import HttpLayer + layer = HttpLayer(self, self.mode) + for message in layer(): + yield message + def make_error_response(status_code, message, headers=None): response = status_codes.RESPONSES.get(status_code, "Unknown") body = """ @@ -79,8 +106,8 @@ class HttpLayer(Layer): while True: try: try: - request = HTTP1.read_request( - self.client_conn, + request = HTTPRequest.from_protocol( + self.client_protocol, body_size_limit=self.config.body_size_limit ) except tcp.NetLibError: @@ -168,12 +195,12 @@ class HttpLayer(Layer): # streaming: # First send the headers and then transfer the response # incrementally: - h = HTTP1._assemble_response_first_line(flow.response) + h = self.client_protocol._assemble_response_first_line(flow.response) self.send_to_client(h + "\r\n") - h = HTTP1._assemble_response_headers(flow.response, preserve_transfer_encoding=True) + h = self.client_protocol._assemble_response_headers(flow.response, preserve_transfer_encoding=True) self.send_to_client(h + "\r\n") - chunks = HTTP1.read_http_body_chunked( + chunks = self.client_protocol.read_http_body_chunked( flow.response.headers, self.config.body_size_limit, flow.request.method, @@ -196,8 +223,8 @@ class HttpLayer(Layer): # TODO: Add second attempt. self.send_to_server(flow.request) - flow.response = HTTP1.read_response( - self.server_conn, + flow.response = HTTPResponse.from_protocol( + self.server_protocol, flow.request.method, body_size_limit=self.config.body_size_limit, include_body=False, @@ -211,8 +238,8 @@ class HttpLayer(Layer): if flow.response.stream: flow.response.content = CONTENT_MISSING - else: - flow.response.content = HTTP1.read_http_body( + elif isinstance(self.server_protocol, http1.HTTP1Protocol): + flow.response.content = self.server_protocol.read_http_body( self.server_conn, flow.response.headers, self.config.body_size_limit, @@ -329,9 +356,9 @@ class HttpLayer(Layer): raise InvalidCredentials("Proxy Authentication Required") def send_to_server(self, message): - self.server_conn.send(HTTP1.assemble(message)) + self.server_conn.send(self.server_protocol.assemble(message)) def send_to_client(self, message): # FIXME # - possibly do some http2 stuff here - self.client_conn.send(HTTP1.assemble(message)) + self.client_conn.send(self.client_protocol.assemble(message)) diff --git a/libmproxy/protocol2/http_protocol_mock.py b/libmproxy/protocol2/http_protocol_mock.py deleted file mode 100644 index dd3643f6..00000000 --- a/libmproxy/protocol2/http_protocol_mock.py +++ /dev/null @@ -1,50 +0,0 @@ -""" -Temporary mock to sort out API discrepancies -""" -from libmproxy.protocol.http_wrappers import HTTPResponse, HTTPRequest -from netlib.http.http1 import HTTP1Protocol - - -class HTTP1(object): - @staticmethod - def read_request(connection, *args, **kwargs): - """ - :type connection: object - """ - return HTTPRequest.from_protocol(HTTP1Protocol(connection), *args, **kwargs) - - @staticmethod - def read_response(connection, *args, **kwargs): - """ - :type connection: object - """ - return HTTPResponse.from_protocol(HTTP1Protocol(connection), *args, **kwargs) - - @staticmethod - def read_http_body(connection, *args, **kwargs): - """ - :type connection: object - """ - return HTTP1Protocol(connection).read_http_body(*args, **kwargs) - - - @staticmethod - def _assemble_response_first_line(*args, **kwargs): - return HTTP1Protocol()._assemble_response_first_line(*args, **kwargs) - - - @staticmethod - def _assemble_response_headers(*args, **kwargs): - return HTTP1Protocol()._assemble_response_headers(*args, **kwargs) - - - @staticmethod - def read_http_body_chunked(connection, *args, **kwargs): - """ - :type connection: object - """ - return HTTP1Protocol(connection).read_http_body_chunked(*args, **kwargs) - - @staticmethod - def assemble(*args, **kwargs): - return HTTP1Protocol().assemble(*args, **kwargs)
\ No newline at end of file diff --git a/libmproxy/protocol2/http_proxy.py b/libmproxy/protocol2/http_proxy.py index ca70b012..7f5957ac 100644 --- a/libmproxy/protocol2/http_proxy.py +++ b/libmproxy/protocol2/http_proxy.py @@ -1,12 +1,12 @@ from __future__ import (absolute_import, print_function, division) from .layer import Layer, ServerConnectionMixin -from .http import HttpLayer +from .http import Http1Layer, HttpLayer class HttpProxy(Layer, ServerConnectionMixin): def __call__(self): - layer = HttpLayer(self, "regular") + layer = Http1Layer(self, "regular") for message in layer(): if not self._handle_server_message(message): yield message @@ -18,7 +18,7 @@ class HttpUpstreamProxy(Layer, ServerConnectionMixin): self.server_address = server_address def __call__(self): - layer = HttpLayer(self, "upstream") + layer = Http1Layer(self, "upstream") for message in layer(): if not self._handle_server_message(message): - yield message
\ No newline at end of file + yield message diff --git a/libmproxy/protocol2/layer.py b/libmproxy/protocol2/layer.py index c1648a62..31b74552 100644 --- a/libmproxy/protocol2/layer.py +++ b/libmproxy/protocol2/layer.py @@ -64,6 +64,7 @@ class Layer(_LayerCodeCompletion): """ super(Layer, self).__init__() self.ctx = ctx + print("%s -> %s" % (repr(ctx), repr(self))) def __call__(self): """ diff --git a/libmproxy/protocol2/root_context.py b/libmproxy/protocol2/root_context.py index bda8b12b..a68560c2 100644 --- a/libmproxy/protocol2/root_context.py +++ b/libmproxy/protocol2/root_context.py @@ -2,7 +2,7 @@ from __future__ import (absolute_import, print_function, division) from .rawtcp import RawTcpLayer from .tls import TlsLayer -from .http import HttpLayer +from .http import Http1Layer, Http2Layer, HttpLayer class RootContext(object): """ @@ -34,13 +34,20 @@ class RootContext(object): d[2] in ('\x00', '\x01', '\x02', '\x03') ) + # TODO: build is_http2_magic check here, maybe this is an easy way to detect h2c + if not d: return if is_tls_client_hello: return TlsLayer(top_layer, True, True) - elif isinstance(top_layer, TlsLayer) and isinstance(top_layer.ctx, HttpLayer): - return HttpLayer(top_layer, "transparent") + elif isinstance(top_layer, TlsLayer): + if top_layer.client_conn.get_alpn_proto_negotiated() == 'h2': + return Http2Layer(top_layer, 'regular') # TODO: regular correct here? + else: + return Http1Layer(top_layer, 'regular') # TODO: regular correct here? + elif isinstance(top_layer, TlsLayer) and isinstance(top_layer.ctx, Http1Layer): + return Http1Layer(top_layer, "transparent") else: return RawTcpLayer(top_layer) diff --git a/libmproxy/protocol2/tls.py b/libmproxy/protocol2/tls.py index fcc12f18..8e367728 100644 --- a/libmproxy/protocol2/tls.py +++ b/libmproxy/protocol2/tls.py @@ -157,7 +157,6 @@ class TlsLayer(Layer): self.yield_from_callback(Reconnect()) self.client_alpn_protos = options - print("foo: %s" % options) if alpn_preference in options: return bytes(alpn_preference) |