aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorViktor Söderqvist <[email protected]>2020-11-10 15:26:59 +0100
committerLoïc Hoguin <[email protected]>2020-11-27 14:16:17 +0100
commit6deddc7d3360aa0f50eb2375cc0226157185c472 (patch)
tree4d0db6813c8e8b2c0e61feb23c5693650149d08e
parentd06fcad11a00be1c56d0a76e1c46c45b1ff71edd (diff)
downloadcowlib-6deddc7d3360aa0f50eb2375cc0226157185c472.tar.gz
cowlib-6deddc7d3360aa0f50eb2375cc0226157185c472.tar.bz2
cowlib-6deddc7d3360aa0f50eb2375cc0226157185c472.zip
Handle last remote stream ID in cow_http2_machine
New function set_last_streamid/1 sets the last accepted stream ID to the last known remote stream ID. Frames with a remote stream ID greater than this are thereafter discarded by frame/2, which returns {ok, Http2Machine} for such frames.
-rw-r--r--src/cow_http2_machine.erl35
1 files changed, 32 insertions, 3 deletions
diff --git a/src/cow_http2_machine.erl b/src/cow_http2_machine.erl
index 2d7fbf5..35eb72e 100644
--- a/src/cow_http2_machine.erl
+++ b/src/cow_http2_machine.erl
@@ -33,6 +33,7 @@
-export([get_local_setting/2]).
-export([get_remote_settings/1]).
-export([get_last_streamid/1]).
+-export([set_last_streamid/1]).
-export([get_stream_local_buffer_size/2]).
-export([get_stream_local_state/2]).
-export([get_stream_remote_state/2]).
@@ -145,6 +146,7 @@
%% Stream identifiers.
local_streamid :: pos_integer(), %% The next streamid to be used.
remote_streamid = 0 :: non_neg_integer(), %% The last streamid received.
+ last_remote_streamid = 16#7fffffff :: non_neg_integer(), %% Used in GOAWAY.
%% Currently active HTTP/2 streams. Streams may be initiated either
%% by the client or by the server through PUSH_PROMISE frames.
@@ -309,11 +311,11 @@ frame(Frame, State=#http2_machine{state=settings, preface_timer=TRef}) ->
end,
settings_frame(Frame, State#http2_machine{state=normal, preface_timer=undefined});
frame(Frame, State=#http2_machine{state={continuation, _, _}}) ->
- continuation_frame(Frame, State);
+ maybe_discard_result(continuation_frame(Frame, State));
frame(settings_ack, State=#http2_machine{state=normal}) ->
settings_ack_frame(State);
frame(Frame, State=#http2_machine{state=normal}) ->
- case element(1, Frame) of
+ Result = case element(1, Frame) of
data -> data_frame(Frame, State);
headers -> headers_frame(Frame, State);
priority -> priority_frame(Frame, State);
@@ -326,7 +328,26 @@ frame(Frame, State=#http2_machine{state=normal}) ->
window_update -> window_update_frame(Frame, State);
continuation -> unexpected_continuation_frame(Frame, State);
_ -> ignored_frame(State)
- end.
+ end,
+ maybe_discard_result(Result).
+
+%% RFC7540 6.9. After sending a GOAWAY frame, the sender can discard frames for
+%% streams initiated by the receiver with identifiers higher than the identified
+%% last stream. However, any frames that alter connection state cannot be
+%% completely ignored. For instance, HEADERS, PUSH_PROMISE, and CONTINUATION
+%% frames MUST be minimally processed to ensure the state maintained for header
+%% compression is consistent.
+maybe_discard_result(FrameResult={ok, Result, State=#http2_machine{mode=Mode,
+ last_remote_streamid=MaxID}})
+ when element(1, Result) =/= goaway ->
+ case element(2, Result) of
+ StreamID when StreamID > MaxID, not ?IS_LOCAL(Mode, StreamID) ->
+ {ok, State};
+ _StreamID ->
+ FrameResult
+ end;
+maybe_discard_result(FrameResult) ->
+ FrameResult.
%% DATA frame.
@@ -1529,6 +1550,14 @@ default_setting_value(enable_connect_protocol) -> false.
get_last_streamid(#http2_machine{remote_streamid=RemoteStreamID}) ->
RemoteStreamID.
+%% Set last accepted streamid to the last known streamid, for the purpose
+%% ignoring frames for remote streams created after sending GOAWAY.
+
+-spec set_last_streamid(http2_machine()) -> {cow_http2:streamid(), http2_machine()}.
+set_last_streamid(State=#http2_machine{remote_streamid=StreamID,
+ last_remote_streamid=LastStreamID}) when StreamID =< LastStreamID->
+ {StreamID, State#http2_machine{last_remote_streamid = StreamID}}.
+
%% Retrieve the local buffer size for a stream.
-spec get_stream_local_buffer_size(cow_http2:streamid(), http2_machine())