diff options
author | Loïc Hoguin <[email protected]> | 2019-09-02 14:48:28 +0200 |
---|---|---|
committer | Loïc Hoguin <[email protected]> | 2019-09-05 14:07:38 +0200 |
commit | 48f417ac8f3d00039e2dc674e312d982336dcfea (patch) | |
tree | 232092a3fcbe0364a92c10f074faccdaf389c6da /test/rfc7540_SUITE.erl | |
parent | aedf6379cc769ce2be1e040de3fe631e6539f442 (diff) | |
download | cowboy-48f417ac8f3d00039e2dc674e312d982336dcfea.tar.gz cowboy-48f417ac8f3d00039e2dc674e312d982336dcfea.tar.bz2 cowboy-48f417ac8f3d00039e2dc674e312d982336dcfea.zip |
Fix and optimize sending of WINDOW_UPDATE frames
For long-running connections it was possible for the connection
window to become larger than allowed by the protocol because the
window increases claimed by stream handlers were never reclaimed
even if no data was consumed.
The new code applies heuristics to fix this and reduce the number
of WINDOW_UPDATE frames that are sent. It includes six new options
to control that behavior: margin, max and threshold for both the
connection and stream windows. The margin is some extra space
added on top of the requested read size. The max is the maximum
window size at any given time. The threshold is a minimum window
size that must be reached before we even consider sending more
WINDOW_UPDATE frames. We also avoid sending WINDOW_UPDATE frames
when there is already enough space in the window, or when the
read size is 0.
Cowlib is set to master until a new tag is done.
Diffstat (limited to 'test/rfc7540_SUITE.erl')
-rw-r--r-- | test/rfc7540_SUITE.erl | 50 |
1 files changed, 0 insertions, 50 deletions
diff --git a/test/rfc7540_SUITE.erl b/test/rfc7540_SUITE.erl index fe0c4ef..4f27dfa 100644 --- a/test/rfc7540_SUITE.erl +++ b/test/rfc7540_SUITE.erl @@ -3117,56 +3117,6 @@ data_reject_overflow_stream(Config0) -> cowboy:stop_listener(?FUNCTION_NAME) end. -lingering_data_counts_toward_connection_window(Config0) -> - doc("DATA frames received after sending RST_STREAM must be counted " - "toward the connection flow-control window. (RFC7540 5.1)"), - Config = cowboy_test:init_http(?FUNCTION_NAME, #{ - env => #{dispatch => cowboy_router:compile(init_routes(Config0))}, - initial_connection_window_size => 100000 - }, Config0), - try - %% We need to do the handshake manually because a WINDOW_UPDATE - %% frame will be sent to update the connection window. - {ok, Socket} = gen_tcp:connect("localhost", config(port, Config), [binary, {active, false}]), - %% Send a valid preface. - ok = gen_tcp:send(Socket, ["PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n", cow_http2:settings(#{})]), - %% Receive the server preface. - {ok, << Len1:24 >>} = gen_tcp:recv(Socket, 3, 1000), - {ok, << 4:8, 0:40, _:Len1/binary >>} = gen_tcp:recv(Socket, 6 + Len1, 1000), - %% Send the SETTINGS ack. - ok = gen_tcp:send(Socket, cow_http2:settings_ack()), - %% Receive the WINDOW_UPDATE for the connection. - {ok, << 4:24, 8:8, 0:40, _:32 >>} = gen_tcp:recv(Socket, 13, 1000), - %% Receive the SETTINGS ack. - {ok, << 0:24, 4:8, 1:8, 0:32 >>} = gen_tcp:recv(Socket, 9, 1000), - Headers = [ - {<<":method">>, <<"POST">>}, - {<<":scheme">>, <<"http">>}, - {<<":authority">>, <<"localhost">>}, %% @todo Correct port number. - {<<":path">>, <<"/loop_handler_abort">>} - ], - {HeadersBlock, _} = cow_hpack:encode(Headers), - ok = gen_tcp:send(Socket, [ - cow_http2:headers(1, nofin, HeadersBlock), - cow_http2:data(1, nofin, <<0:1000/unit:8>>) - ]), - % Make sure server send RST_STREAM. - timer:sleep(100), - ok = gen_tcp:send(Socket, [ - cow_http2:data(1, nofin, <<0:0/unit:8>>), - cow_http2:data(1, fin, <<0:1000/unit:8>>) - ]), - {ok, << SkipLen:24, 1:8, _:8, 1:32 >>} = gen_tcp:recv(Socket, 9, 1000), - % Skip the header. - {ok, _} = gen_tcp:recv(Socket, SkipLen, 1000), - % Skip RST_STREAM. - {ok, << 4:24, 3:8, 1:40, _:32 >>} = gen_tcp:recv(Socket, 13, 1000), - % Received a WINDOW_UPDATE frame after we got RST_STREAM. - {ok, << 4:24, 8:8, 0:40, 1000:32 >>} = gen_tcp:recv(Socket, 13, 1000) - after - cowboy:stop_listener(?FUNCTION_NAME) - end. - %% (RFC7540 6.9.1) % Frames with zero length with the END_STREAM flag set (that % is, an empty DATA frame) MAY be sent if there is no available space |