0
Fork 0
mirror of https://github.com/ninenines/cowboy.git synced 2025-07-14 04:10:24 +00:00

HTTP/1: Ensure active mode is enabled for the next stream

In rare cases it was possible for active mode to be disabled
when there were no streams pipelined. This resulted in the
dropping of the connection due to timeouts as no data could
be received.

We now enable active mode when necessary even if there are
no streams pipelined.

This was found while benchmarking and I have not been able
to extract a test case.
This commit is contained in:
Loïc Hoguin 2025-02-04 12:12:49 +01:00
parent d889291c4f
commit 073c481656
No known key found for this signature in database
GPG key ID: 8A9DF795F6FED764

View file

@ -1392,23 +1392,24 @@ stream_terminate(State0=#state{opts=Opts, in_streamid=InStreamID, in_state=InSta
end. end.
stream_next(State0=#state{opts=Opts, active=Active, out_streamid=OutStreamID, streams=Streams}) -> stream_next(State0=#state{opts=Opts, active=Active, out_streamid=OutStreamID, streams=Streams}) ->
%% Enable active mode again if it was disabled.
State1 = case Active of
true -> State0;
false -> active(State0)
end,
NextOutStreamID = OutStreamID + 1, NextOutStreamID = OutStreamID + 1,
case lists:keyfind(NextOutStreamID, #stream.id, Streams) of case lists:keyfind(NextOutStreamID, #stream.id, Streams) of
false -> false ->
State = State0#state{out_streamid=NextOutStreamID, out_state=wait}, State = State1#state{out_streamid=NextOutStreamID, out_state=wait},
%% There are no streams remaining. We therefore can %% There are no streams remaining. We therefore can
%% and want to switch back to the request_timeout. %% and want to switch back to the request_timeout.
set_timeout(State, request_timeout); set_timeout(State, request_timeout);
#stream{queue=Commands} -> #stream{queue=Commands} ->
State = case Active of
true -> State0;
false -> active(State0)
end,
%% @todo Remove queue from the stream. %% @todo Remove queue from the stream.
%% We set the flow to the initial flow size even though %% We set the flow to the initial flow size even though
%% we might have sent some data through already due to pipelining. %% we might have sent some data through already due to pipelining.
Flow = maps:get(initial_stream_flow_size, Opts, 65535), Flow = maps:get(initial_stream_flow_size, Opts, 65535),
commands(State#state{flow=Flow, out_streamid=NextOutStreamID, out_state=wait}, commands(State1#state{flow=Flow, out_streamid=NextOutStreamID, out_state=wait},
NextOutStreamID, Commands) NextOutStreamID, Commands)
end. end.