aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2018-10-01 12:36:17 +0200
committerLoïc Hoguin <[email protected]>2018-10-01 12:36:17 +0200
commitaf7629933df8e7bc151ef230d25276d8bbb907e2 (patch)
treeba763e9d370e5802f8905292d84d19c9b97789c8
parent86fc6a774e16f37bd653355b97e6836c06d8cdfc (diff)
downloadgun-af7629933df8e7bc151ef230d25276d8bbb907e2.tar.gz
gun-af7629933df8e7bc151ef230d25276d8bbb907e2.tar.bz2
gun-af7629933df8e7bc151ef230d25276d8bbb907e2.zip
Fix the remaining h2specd test failures
-rw-r--r--src/gun_http2.erl20
1 files changed, 16 insertions, 4 deletions
diff --git a/src/gun_http2.erl b/src/gun_http2.erl
index 8dc0d2b..f017c54 100644
--- a/src/gun_http2.erl
+++ b/src/gun_http2.erl
@@ -243,11 +243,18 @@ frame({ping_ack, _Opaque}, State) ->
frame(Frame={goaway, StreamID, _, _}, State) ->
terminate(State, StreamID, {stop, Frame, 'Client is going away.'});
%% Connection-wide WINDOW_UPDATE frame.
+frame({window_update, Increment}, State=#http2_state{local_window=ConnWindow})
+ when ConnWindow + Increment > 16#7fffffff ->
+ terminate(State, {connection_error, flow_control_error,
+ 'The flow control window must not be greater than 2^31-1. (RFC7540 6.9.1)'});
frame({window_update, Increment}, State=#http2_state{local_window=ConnWindow}) ->
send_data(State#http2_state{local_window=ConnWindow + Increment});
%% Stream-specific WINDOW_UPDATE frame.
frame({window_update, StreamID, Increment}, State0=#http2_state{streams=Streams0}) ->
case lists:keyfind(StreamID, #stream.id, Streams0) of
+ #stream{local_window=StreamWindow} when StreamWindow + Increment > 16#7fffffff ->
+ stream_reset(State0, StreamID, {stream_error, flow_control_error,
+ 'The flow control window must not be greater than 2^31-1. (RFC7540 6.9.1)'});
Stream0 = #stream{local_window=StreamWindow} ->
{State, Stream} = send_data(State0,
Stream0#stream{local_window=StreamWindow + Increment}),
@@ -509,27 +516,32 @@ down(#http2_state{streams=Streams}) ->
KilledStreams = [Ref || #stream{ref=Ref} <- Streams],
{KilledStreams, []}.
-terminate(#http2_state{streams=Streams}, Reason) ->
+terminate(#http2_state{socket=Socket, transport=Transport, streams=Streams}, Reason) ->
%% Because a particular stream is unknown,
%% we're sending the error message to all streams.
%% @todo We should not send duplicate messages to processes.
%% @todo We should probably also inform the owner process.
_ = [ReplyTo ! {gun_error, self(), Reason} || #stream{reply_to=ReplyTo} <- Streams],
- %% @todo Send GOAWAY frame.
%% @todo LastGoodStreamID
+ Transport:send(Socket, cow_http2:goaway(0, terminate_reason(Reason), <<>>)),
close.
-terminate(State, StreamID, Reason) ->
+terminate(State=#http2_state{socket=Socket, transport=Transport}, StreamID, Reason) ->
case get_stream_by_id(StreamID, State) of
#stream{reply_to=ReplyTo} ->
ReplyTo ! {gun_error, self(), Reason},
- %% @todo Send GOAWAY frame.
%% @todo LastGoodStreamID
+ Transport:send(Socket, cow_http2:goaway(0, terminate_reason(Reason), <<>>)),
close;
_ ->
terminate(State, Reason)
end.
+terminate_reason({connection_error, Reason, _}) -> Reason;
+terminate_reason({stop, _, _}) -> no_error;
+terminate_reason({socket_error, _, _}) -> internal_error;
+terminate_reason({internal_error, _, _}) -> internal_error.
+
%% Stream functions.
stream_decode_init(State=#http2_state{decode_state=DecodeState0}, StreamID, IsFin, HeaderBlock) ->