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

Fix a few rfc7540 tests

Cowboy takes a few shortcuts to avoid wasting resources when
there is a protocol error. The RFC wants us to send a different
error depending on the state of the stream at the time of the
error, and for us to maintain the connection in cases where we
would have to spend valuable resources to decode headers. In
all these cases Cowboy will simply close the connection with
an appropriate error.
This commit is contained in:
Loïc Hoguin 2017-11-27 13:42:04 +01:00
parent 843b104fcb
commit bc82679330
No known key found for this signature in database
GPG key ID: 8A9DF795F6FED764
2 changed files with 36 additions and 18 deletions

View file

@ -360,9 +360,12 @@ frame(State, {headers, StreamID, _, _, _}) when StreamID rem 2 =:= 0 ->
terminate(State, {connection_error, protocol_error,
'HEADERS frame received with even-numbered streamid. (RFC7540 5.1.1)'});
%% HEADERS frame received on (half-)closed stream.
%%
%% We always close the connection here to avoid having to decode
%% the headers to not waste resources on non-compliant clients.
frame(State=#state{client_streamid=LastStreamID}, {headers, StreamID, _, _, _})
when StreamID =< LastStreamID ->
stream_reset(State, StreamID, {stream_error, stream_closed,
terminate(State, {connection_error, stream_closed,
'HEADERS frame received on a stream in closed or half-closed state. (RFC7540 5.1)'});
%% Single HEADERS frame headers block.
frame(State, {headers, StreamID, IsFin, head_fin, HeaderBlock}) ->
@ -895,7 +898,7 @@ stream_terminate(State0=#state{streams=Streams0, children=Children0}, StreamID,
Children = cowboy_children:shutdown(Children0, StreamID),
State0#state{streams=[Stream#stream{state=flush, local=flush}|Streams],
children=Children};
%% Otherwise we sent an RST_STREAM and/or the stream is already closed.
%% Otherwise we sent or received an RST_STREAM and/or the stream is already closed.
{value, Stream=#stream{state=StreamState}, Streams} ->
State = maybe_skip_body(State0, Stream, Reason),
stream_call_terminate(StreamID, Reason, StreamState),