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

Fix stream handler state being discarded on terminate

When we have to send a response before terminating a stream,
we call info. The state returned by this info call was
discarded when we called terminate after that. This commit
fixes it.

There are no tests for this, however the new metrics test
in the next commit requires the correct behavior so this
is ultimately covered.
This commit is contained in:
Loïc Hoguin 2017-10-21 13:09:20 +01:00
parent 1ef5a1c45b
commit c62ce1c63e
No known key found for this signature in database
GPG key ID: 71366FF21851DF03
2 changed files with 15 additions and 13 deletions

View file

@ -932,9 +932,8 @@ stream_reset(State, StreamID, StreamError={internal_error, _, _}) ->
stream_terminate(State0=#state{socket=Socket, transport=Transport,
out_streamid=OutStreamID, out_state=OutState,
streams=Streams0, children=Children0}, StreamID, Reason) ->
{value, #stream{state=StreamState, version=Version}, Streams}
= lists:keytake(StreamID, #stream.id, Streams0),
State1 = case OutState of
#stream{version=Version} = lists:keyfind(StreamID, #stream.id, Streams0),
State1 = #state{streams=Streams1} = case OutState of
wait when element(1, Reason) =:= internal_error ->
info(State0, StreamID, {response, 500, #{<<"content-length">> => <<"0">>}, <<>>});
wait ->
@ -945,18 +944,20 @@ stream_terminate(State0=#state{socket=Socket, transport=Transport,
_ -> %% done or Version =:= 'HTTP/1.0'
State0
end,
%% Remove the stream from the state.
{value, #stream{state=StreamState}, Streams}
= lists:keytake(StreamID, #stream.id, Streams1),
State2 = State1#state{streams=Streams},
%% Stop the stream.
stream_call_terminate(StreamID, Reason, StreamState),
Children = cowboy_children:shutdown(Children0, StreamID),
%% We reset the timeout if there are no active streams anymore.
State = case Streams of
[] -> set_timeout(State1);
_ -> State1
[] -> set_timeout(State2);
_ -> State2
end,
stream_call_terminate(StreamID, Reason, StreamState),
Children = cowboy_children:shutdown(Children0, StreamID),
%% Move on to the next stream.
%% @todo Skip the body, if any, or drop the connection if too large.
%% @todo Only do this if Current =:= StreamID.
NextOutStreamID = OutStreamID + 1,
case lists:keyfind(NextOutStreamID, #stream.id, Streams) of

View file

@ -777,8 +777,9 @@ stream_terminate(State=#state{socket=Socket, transport=Transport,
case lists:keytake(StreamID, #stream.id, Streams0) of
%% When the stream terminates normally (without sending RST_STREAM)
%% and no response was sent, we need to send a proper response back to the client.
{value, #stream{state=StreamState, local=idle}, Streams} when Reason =:= normal ->
State1 = info(State, StreamID, {response, 204, #{}, <<>>}),
{value, #stream{local=idle}, Streams} when Reason =:= normal ->
State1 = #state{streams=Streams1} = info(State, StreamID, {response, 204, #{}, <<>>}),
#stream{state=StreamState} = lists:keyfind(StreamID, #stream.id, Streams1),
stream_call_terminate(StreamID, Reason, StreamState),
Children = cowboy_children:shutdown(Children0, StreamID),
State1#state{streams=Streams, children=Children};