mirror of
https://github.com/Grasscutters/mitmproxy.git
synced 2024-11-23 08:11:00 +00:00
implement Http1 and Http2 protocols as layers
This commit is contained in:
parent
c04fa1b233
commit
38c456bb62
@ -9,14 +9,41 @@ 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")
|
||||
@ -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))
|
||||
|
@ -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)
|
@ -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
|
||||
yield message
|
||||
|
@ -64,6 +64,7 @@ class Layer(_LayerCodeCompletion):
|
||||
"""
|
||||
super(Layer, self).__init__()
|
||||
self.ctx = ctx
|
||||
print("%s -> %s" % (repr(ctx), repr(self)))
|
||||
|
||||
def __call__(self):
|
||||
"""
|
||||
|
@ -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)
|
||||
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user