Skip to content

Commit ed809af

Browse files
authored
Merge pull request #829 from ycastorium/fix_http2_window_match
fix: Invalid match in handle_h2_frame/2
2 parents 0db3fb4 + dce9abb commit ed809af

File tree

2 files changed

+101
-2
lines changed

2 files changed

+101
-2
lines changed

src/hackney_conn.erl

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2690,20 +2690,34 @@ handle_h2_frame({goaway, LastStreamId, ErrorCode, _DebugData}, Data) ->
26902690

26912691
handle_h2_frame({window_update, Increment}, Data) ->
26922692
%% Connection-level window update
2693-
#conn_data{h2_machine = H2Machine} = Data,
2693+
#conn_data{h2_machine = H2Machine, transport = Transport, socket = Socket} = Data,
26942694
case hackney_http2_machine:frame({window_update, Increment}, H2Machine) of
26952695
{ok, H2Machine2} ->
26962696
{ok, Data#conn_data{h2_machine = H2Machine2}};
2697+
{send, SendList, H2Machine2} ->
2698+
case send_h2_data_frames(Transport, Socket, SendList, H2Machine2) of
2699+
{ok, H2Machine3} ->
2700+
{ok, Data#conn_data{h2_machine = H2Machine3}};
2701+
{error, Reason} ->
2702+
{error, Reason, Data}
2703+
end;
26972704
{error, Reason, _H2Machine} ->
26982705
{error, Reason, Data}
26992706
end;
27002707

27012708
handle_h2_frame({window_update, StreamId, Increment}, Data) ->
27022709
%% Stream-level window update
2703-
#conn_data{h2_machine = H2Machine} = Data,
2710+
#conn_data{h2_machine = H2Machine, transport = Transport, socket = Socket} = Data,
27042711
case hackney_http2_machine:frame({window_update, StreamId, Increment}, H2Machine) of
27052712
{ok, H2Machine2} ->
27062713
{ok, Data#conn_data{h2_machine = H2Machine2}};
2714+
{send, SendList, H2Machine2} ->
2715+
case send_h2_data_frames(Transport, Socket, SendList, H2Machine2) of
2716+
{ok, H2Machine3} ->
2717+
{ok, Data#conn_data{h2_machine = H2Machine3}};
2718+
{error, Reason} ->
2719+
{error, Reason, Data}
2720+
end;
27072721
{error, Reason, _H2Machine} ->
27082722
{error, Reason, Data}
27092723
end;

test/hackney_http2_machine_tests.erl

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -232,6 +232,75 @@ is_lingering_stream_test() ->
232232
{ok, _Preface, State} = hackney_http2_machine:init(client, ?TEST_OPTS),
233233
?assertEqual(false, hackney_http2_machine:is_lingering_stream(1, State)).
234234

235+
%%====================================================================
236+
%% Window Update Send Tests
237+
%%====================================================================
238+
239+
setup_stream_with_headers(ServerSettings) ->
240+
{ok, _Preface, S0} = hackney_http2_machine:init(client, ?TEST_OPTS),
241+
{ok, S1} = hackney_http2_machine:frame({settings, ServerSettings}, S0),
242+
{ok, S2} = hackney_http2_machine:frame(settings_ack, S1),
243+
{ok, StreamID, S3} = hackney_http2_machine:init_stream(<<"POST">>, S2),
244+
PseudoHeaders = #{
245+
method => <<"POST">>,
246+
scheme => <<"https">>,
247+
authority => <<"example.com">>,
248+
path => <<"/upload">>
249+
},
250+
Headers = [{<<"content-type">>, <<"application/octet-stream">>}],
251+
{ok, nofin, _HeaderBlock, S4} = hackney_http2_machine:prepare_headers(
252+
StreamID, S3, nofin, PseudoHeaders, Headers),
253+
{StreamID, S4}.
254+
255+
conn_window_update_sends_queued_data_test() ->
256+
{StreamID, S0} = setup_stream_with_headers(#{initial_window_size => 200000}),
257+
FillData = {data, binary:copy(<<0>>, 65535)},
258+
{send, _, S1} = hackney_http2_machine:send_or_queue_data(StreamID, S0, nofin, FillData),
259+
QueuedData = {data, binary:copy(<<1>>, 10000)},
260+
{ok, S2} = hackney_http2_machine:send_or_queue_data(StreamID, S1, fin, QueuedData),
261+
BufferSize = hackney_http2_machine:get_connection_local_buffer_size(S2),
262+
?assert(BufferSize > 0),
263+
{send, SendList, _S3} = hackney_http2_machine:frame({window_update, 50000}, S2),
264+
?assert(is_list(SendList)),
265+
?assert(length(SendList) > 0).
266+
267+
stream_window_update_sends_queued_data_test() ->
268+
{StreamID, S0} = setup_stream_with_headers(#{initial_window_size => 100}),
269+
FillData = {data, binary:copy(<<0>>, 100)},
270+
{send, _, S1} = hackney_http2_machine:send_or_queue_data(StreamID, S0, nofin, FillData),
271+
QueuedData = {data, binary:copy(<<1>>, 500)},
272+
{ok, S2} = hackney_http2_machine:send_or_queue_data(StreamID, S1, fin, QueuedData),
273+
{send, SendList, _S3} = hackney_http2_machine:frame(
274+
{window_update, StreamID, 10000}, S2),
275+
?assert(is_list(SendList)),
276+
?assert(length(SendList) > 0),
277+
[{SentStreamID, _, _} | _] = SendList,
278+
?assertEqual(StreamID, SentStreamID).
279+
280+
conn_window_update_no_queued_data_test() ->
281+
{ok, _Preface, S0} = hackney_http2_machine:init(client, ?TEST_OPTS),
282+
{ok, S1} = hackney_http2_machine:frame({settings, #{}}, S0),
283+
{ok, S2} = hackney_http2_machine:frame(settings_ack, S1),
284+
{ok, S3} = hackney_http2_machine:frame({window_update, 1000}, S2),
285+
?assert(is_tuple(S3)).
286+
287+
stream_window_update_no_queued_data_test() ->
288+
{StreamID, S0} = setup_stream_with_headers(#{}),
289+
{ok, S1} = hackney_http2_machine:frame({window_update, StreamID, 1000}, S0),
290+
?assert(is_tuple(S1)).
291+
292+
conn_window_update_overflow_test() ->
293+
{ok, _Preface, S0} = hackney_http2_machine:init(client, ?TEST_OPTS),
294+
{ok, S1} = hackney_http2_machine:frame({settings, #{}}, S0),
295+
{ok, S2} = hackney_http2_machine:frame(settings_ack, S1),
296+
{error, {connection_error, flow_control_error, _}, _S3} =
297+
hackney_http2_machine:frame({window_update, 16#7fffffff}, S2).
298+
299+
stream_window_update_overflow_test() ->
300+
{StreamID, S0} = setup_stream_with_headers(#{}),
301+
Result = hackney_http2_machine:frame({window_update, StreamID, 16#7fffffff}, S0),
302+
?assertMatch({error, {stream_error, StreamID, flow_control_error, _}, _}, Result).
303+
235304
%%====================================================================
236305
%% Test Suites
237306
%%====================================================================
@@ -274,3 +343,19 @@ stream_state_test_() ->
274343
{"Last streamid", fun last_streamid_test/0},
275344
{"Is lingering stream", fun is_lingering_stream_test/0}
276345
].
346+
347+
window_update_send_test_() ->
348+
[
349+
{"Conn window_update sends queued data",
350+
fun conn_window_update_sends_queued_data_test/0},
351+
{"Stream window_update sends queued data",
352+
fun stream_window_update_sends_queued_data_test/0},
353+
{"Conn window_update with no queued data",
354+
fun conn_window_update_no_queued_data_test/0},
355+
{"Stream window_update with no queued data",
356+
fun stream_window_update_no_queued_data_test/0},
357+
{"Conn window_update overflow error",
358+
fun conn_window_update_overflow_test/0},
359+
{"Stream window_update overflow error",
360+
fun stream_window_update_overflow_test/0}
361+
].

0 commit comments

Comments
 (0)