diff --git a/CHANGELOG.md b/CHANGELOG.md index 2383cd9f1..eca8afe45 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,6 +22,8 @@ This may break users of `modify_headers` that rely on filters referencing the message body. We expect this to be uncommon, but please make yourself heard if that's not the case. ([#7286](https://github.com/mitmproxy/mitmproxy/pull/7286), @lukant) +- Increase HTTP/2 default flow control window size. + ([#7317](https://github.com/mitmproxy/mitmproxy/pull/7317), @sujaldev) - Fix a crash when handling corrupted compressed body in savehar addon and its tests. ([#7320](https://github.com/mitmproxy/mitmproxy/pull/7320), @8192bytes) - Remove dependency on `protobuf` library as it was no longer being used. diff --git a/mitmproxy/proxy/layers/http/_http_h2.py b/mitmproxy/proxy/layers/http/_http_h2.py index 75d20dcbf..ee76ddb68 100644 --- a/mitmproxy/proxy/layers/http/_http_h2.py +++ b/mitmproxy/proxy/layers/http/_http_h2.py @@ -49,9 +49,20 @@ class BufferedH2Connection(h2.connection.H2Connection): def __init__(self, config: h2.config.H2Configuration): super().__init__(config) + self.local_settings.initial_window_size = 2**31 - 1 + self.local_settings.max_frame_size = 2**17 + self.max_inbound_frame_size = 2**17 + # hyper-h2 pitfall: we need to acknowledge here, otherwise its sends out the old settings. + self.local_settings.acknowledge() self.stream_buffers = collections.defaultdict(collections.deque) self.stream_trailers = {} + def initiate_connection(self): + super().initiate_connection() + # We increase the flow-control window for new streams with a setting, + # but we need to increase the overall connection flow-control window as well. + self.increment_flow_control_window(2**31 - 1 - 65535) # maximum - default + def send_data( self, stream_id: int, diff --git a/test/mitmproxy/proxy/layers/http/test_http2.py b/test/mitmproxy/proxy/layers/http/test_http2.py index 4d73dbd9e..5829faa08 100644 --- a/test/mitmproxy/proxy/layers/http/test_http2.py +++ b/test/mitmproxy/proxy/layers/http/test_http2.py @@ -116,6 +116,7 @@ def test_simple(tctx): frames = decode_frames(initial()) assert [type(x) for x in frames] == [ hyperframe.frame.SettingsFrame, + hyperframe.frame.WindowUpdateFrame, hyperframe.frame.HeadersFrame, ] sff = FrameFactory() @@ -258,6 +259,7 @@ def test_request_trailers(tctx: Context, open_h2_server_conn: Server, stream): frames = decode_frames(server_data1.setdefault(b"") + server_data2()) assert [type(x) for x in frames] == [ hyperframe.frame.SettingsFrame, + hyperframe.frame.WindowUpdateFrame, hyperframe.frame.HeadersFrame, hyperframe.frame.DataFrame, hyperframe.frame.HeadersFrame, @@ -323,6 +325,7 @@ def test_long_response(tctx: Context, trailers): frames = decode_frames(initial()) assert [type(x) for x in frames] == [ hyperframe.frame.SettingsFrame, + hyperframe.frame.WindowUpdateFrame, hyperframe.frame.HeadersFrame, ] sff = FrameFactory() @@ -349,11 +352,6 @@ def test_long_response(tctx: Context, trailers): server, sff.build_data_frame(b"a" * 10000, flags=[]).serialize(), ) - << SendData( - server, - sff.build_window_update_frame(0, 40000).serialize() - + sff.build_window_update_frame(1, 40000).serialize(), - ) >> DataReceived( server, sff.build_data_frame(b"a" * 10000, flags=[]).serialize(), @@ -590,10 +588,11 @@ def test_no_normalization(tctx, normalize): frames = decode_frames(initial()) assert [type(x) for x in frames] == [ hyperframe.frame.SettingsFrame, + hyperframe.frame.WindowUpdateFrame, hyperframe.frame.HeadersFrame, ] assert ( - hpack.hpack.Decoder().decode(frames[1].data, True) == request_headers_lower + hpack.hpack.Decoder().decode(frames[2].data, True) == request_headers_lower if normalize else request_headers ) @@ -666,9 +665,10 @@ def test_end_stream_via_headers(tctx, stream): frames = decode_frames(forwarded_request_frames()) assert [type(x) for x in frames] == [ hyperframe.frame.SettingsFrame, + hyperframe.frame.WindowUpdateFrame, hyperframe.frame.HeadersFrame, ] - assert "END_STREAM" in frames[1].flags + assert "END_STREAM" in frames[2].flags frames = decode_frames(forwarded_response_frames()) assert [type(x) for x in frames] == [ @@ -861,6 +861,7 @@ def test_stream_concurrency(tctx): frames = decode_frames(data_req2()) assert [type(x) for x in frames] == [ hyperframe.frame.SettingsFrame, + hyperframe.frame.WindowUpdateFrame, hyperframe.frame.HeadersFrame, ] frames = decode_frames(data_req1()) @@ -920,7 +921,7 @@ def test_max_concurrency(tctx): ) << SendData(tctx.client, Placeholder(bytes)) ) - settings, req1 = decode_frames(req1_bytes()) + settings, _, req1 = decode_frames(req1_bytes()) (settings_ack,) = decode_frames(settings_ack_bytes()) (req2,) = decode_frames(req2_bytes()) @@ -961,6 +962,7 @@ def test_stream_concurrent_get_connection(tctx): frames = decode_frames(data()) assert [type(x) for x in frames] == [ hyperframe.frame.SettingsFrame, + hyperframe.frame.WindowUpdateFrame, hyperframe.frame.HeadersFrame, hyperframe.frame.HeadersFrame, ] @@ -1013,6 +1015,7 @@ def test_kill_stream(tctx): frames = decode_frames(data_req1()) assert [type(x) for x in frames] == [ hyperframe.frame.SettingsFrame, + hyperframe.frame.WindowUpdateFrame, hyperframe.frame.HeadersFrame, ] @@ -1120,6 +1123,7 @@ def test_early_server_data(tctx): ) assert [type(x) for x in decode_frames(server1())] == [ hyperframe.frame.SettingsFrame, + hyperframe.frame.WindowUpdateFrame, hyperframe.frame.SettingsFrame, ] assert [type(x) for x in decode_frames(server2())] == [ diff --git a/test/mitmproxy/proxy/layers/http/test_http_version_interop.py b/test/mitmproxy/proxy/layers/http/test_http_version_interop.py index 599793e32..b003e0777 100644 --- a/test/mitmproxy/proxy/layers/http/test_http_version_interop.py +++ b/test/mitmproxy/proxy/layers/http/test_http_version_interop.py @@ -45,7 +45,8 @@ def h2_client(tctx: Context) -> tuple[h2.connection.H2Connection, Playbook]: server_preamble = Placeholder(bytes) assert playbook << SendData(tctx.client, server_preamble) assert event_types(conn.receive_data(server_preamble())) == [ - h2.events.RemoteSettingsChanged + h2.events.RemoteSettingsChanged, + h2.events.WindowUpdated, ] settings_ack = Placeholder(bytes) @@ -134,6 +135,7 @@ def test_h1_to_h2(tctx): events = conn.receive_data(request()) assert event_types(events) == [ h2.events.RemoteSettingsChanged, + h2.events.WindowUpdated, h2.events.RequestReceived, h2.events.StreamEnded, ]