aboutsummaryrefslogtreecommitdiffstats
path: root/test
diff options
context:
space:
mode:
authorTony Han <[email protected]>2019-04-28 10:46:17 +0800
committerLoïc Hoguin <[email protected]>2019-07-16 15:32:58 +0200
commit7708fc77cd95768aef65bd0eb366ee300cc0515f (patch)
tree82be19d508355a71d0cc4a697a23c80edf2e0ab0 /test
parent504c7c55f7962474c3d6251172810c7731f8d7b0 (diff)
downloadcowboy-7708fc77cd95768aef65bd0eb366ee300cc0515f.tar.gz
cowboy-7708fc77cd95768aef65bd0eb366ee300cc0515f.tar.bz2
cowboy-7708fc77cd95768aef65bd0eb366ee300cc0515f.zip
Data received after RST_STREAM counts toward window
Diffstat (limited to 'test')
-rw-r--r--test/handlers/loop_handler_abort_h.erl21
-rw-r--r--test/rfc7540_SUITE.erl50
2 files changed, 71 insertions, 0 deletions
diff --git a/test/handlers/loop_handler_abort_h.erl b/test/handlers/loop_handler_abort_h.erl
new file mode 100644
index 0000000..759ca98
--- /dev/null
+++ b/test/handlers/loop_handler_abort_h.erl
@@ -0,0 +1,21 @@
+%% This module implements a loop handler that reads
+%% 1000 bytes of the request body after sending itself
+%% a message, then terminates the stream.
+
+-module(loop_handler_abort_h).
+
+-export([init/2]).
+-export([info/3]).
+-export([terminate/3]).
+
+init(Req, _) ->
+ self() ! timeout,
+ {cowboy_loop, Req, undefined, hibernate}.
+
+info(timeout, Req0, State) ->
+ {_Status, Body, Req} = cowboy_req:read_body(Req0, #{length => 1000}),
+ 1000 = byte_size(Body),
+ {stop, cowboy_req:reply(200, Req), State}.
+
+terminate(stop, _, _) ->
+ ok.
diff --git a/test/rfc7540_SUITE.erl b/test/rfc7540_SUITE.erl
index 47c213d..9f36b5b 100644
--- a/test/rfc7540_SUITE.erl
+++ b/test/rfc7540_SUITE.erl
@@ -49,6 +49,7 @@ init_routes(_) -> [
{"/", hello_h, []},
{"/echo/:key", echo_h, []},
{"/long_polling", long_polling_h, []},
+ {"/loop_handler_abort", loop_handler_abort_h, []},
{"/resp/:key[/:arg]", resp_h, []}
]}
].
@@ -3116,6 +3117,55 @@ 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, 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