1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
from mitmproxy.net.http import http1
from mitmproxy.proxy.protocol import http as httpbase
from mitmproxy.utils import human
class Http1Layer(httpbase._HttpTransmissionLayer):
def __init__(self, ctx, mode):
super().__init__(ctx)
self.mode = mode
def read_request_headers(self, flow):
return http1.read_request_head(self.client_conn.rfile)
def read_request_body(self, request):
expected_size = http1.expected_http_body_size(request)
return http1.read_body(
self.client_conn.rfile,
expected_size,
human.parse_size(self.config.options.body_size_limit)
)
def read_request_trailers(self, request):
if "Trailer" in request.headers:
# TODO: not implemented yet
self.log("HTTP/1.1 request trailer headers are not implemented yet!", "warn")
return None
def send_request_headers(self, request):
headers = http1.assemble_request_head(request)
self.server_conn.wfile.write(headers)
self.server_conn.wfile.flush()
def send_request_body(self, request, chunks):
for chunk in http1.assemble_body(request.headers, chunks, request.trailers):
self.server_conn.wfile.write(chunk)
self.server_conn.wfile.flush()
def send_request_trailers(self, request):
# HTTP/1.1 request trailer headers are sent in the body
pass
def send_request(self, request):
self.server_conn.wfile.write(http1.assemble_request(request))
self.server_conn.wfile.flush()
def read_response_headers(self):
return http1.read_response_head(self.server_conn.rfile)
def read_response_body(self, request, response):
expected_size = http1.expected_http_body_size(request, response)
return http1.read_body(
self.server_conn.rfile,
expected_size,
human.parse_size(self.config.options.body_size_limit)
)
def read_response_trailers(self, request, response):
# Trailers should actually be parsed unconditionally, the "Trailer" header is optional
if "Trailer" in response.headers:
# TODO: not implemented yet
self.log("HTTP/1.1 trailer headers are not implemented yet!", "warn")
return None
def send_response_headers(self, response):
raw = http1.assemble_response_head(response)
self.client_conn.wfile.write(raw)
self.client_conn.wfile.flush()
def send_response_body(self, response, chunks):
for chunk in http1.assemble_body(response.headers, chunks, response.trailers):
self.client_conn.wfile.write(chunk)
self.client_conn.wfile.flush()
def send_response_trailers(self, response):
# HTTP/1.1 response trailer headers are sent in the body
pass
def check_close_connection(self, flow):
request_close = http1.connection_close(
flow.request.http_version,
flow.request.headers
)
response_close = http1.connection_close(
flow.response.http_version,
flow.response.headers
)
read_until_eof = http1.expected_http_body_size(flow.request, flow.response) == -1
close_connection = request_close or response_close or read_until_eof
if flow.request.first_line_format == "authority" and flow.response.status_code == 200:
# Workaround for https://github.com/mitmproxy/mitmproxy/issues/313:
# Charles Proxy sends a CONNECT response with HTTP/1.0
# and no Content-Length header
return False
return close_connection
def __call__(self):
layer = httpbase.HttpLayer(self, self.mode)
layer()