From 7373822b8645f34c03a7bf522ea170c62817d8e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Wed, 25 Apr 2018 21:32:58 +0200 Subject: Add the max_concurrent_streams h2 option --- test/h2spec_SUITE.erl | 3 +- test/rfc7540_SUITE.erl | 116 ++++++++++++++++++++++++++++++++----------------- 2 files changed, 77 insertions(+), 42 deletions(-) (limited to 'test') diff --git a/test/h2spec_SUITE.erl b/test/h2spec_SUITE.erl index 3429bb3..1eb18ee 100644 --- a/test/h2spec_SUITE.erl +++ b/test/h2spec_SUITE.erl @@ -30,7 +30,8 @@ init_per_suite(Config) -> skip; _ -> cowboy_test:init_http2(h2spec, #{ - env => #{dispatch => init_dispatch()} + env => #{dispatch => init_dispatch()}, + max_concurrent_streams => 100 }, Config) end. diff --git a/test/rfc7540_SUITE.erl b/test/rfc7540_SUITE.erl index c125f17..14e38fd 100644 --- a/test/rfc7540_SUITE.erl +++ b/test/rfc7540_SUITE.erl @@ -49,6 +49,7 @@ init_routes(_) -> [ {"localhost", [ {"/", hello_h, []}, {"/echo/:key", echo_h, []}, + {"/long_polling", long_polling_h, []}, {"/resp/:key[/:arg]", resp_h, []} ]} ]. @@ -2263,34 +2264,6 @@ reject_streamid_lower(Config) -> % frame so that the client is forced to open a new connection for new % streams. -%% @todo We need this option too. (RFC7540 5.1.2) -% A peer can limit the number of concurrently active streams using the -% SETTINGS_MAX_CONCURRENT_STREAMS parameter (see Section 6.5.2) within -% a SETTINGS frame. The maximum concurrent streams setting is specific -% to each endpoint and applies only to the peer that receives the -% setting. That is, clients specify the maximum number of concurrent -% streams the server can initiate, and servers specify the maximum -% number of concurrent streams the client can initiate. -% -% Streams that are in the "open" state or in either of the "half- -% closed" states count toward the maximum number of streams that an -% endpoint is permitted to open. Streams in any of these three states -% count toward the limit advertised in the -% SETTINGS_MAX_CONCURRENT_STREAMS setting. Streams in either of the -% "reserved" states do not count toward the stream limit. -% -% Endpoints MUST NOT exceed the limit set by their peer. An endpoint -% that receives a HEADERS frame that causes its advertised concurrent -% stream limit to be exceeded MUST treat this as a stream error -% (Section 5.4.2) of type PROTOCOL_ERROR or REFUSED_STREAM. The choice -% of error code determines whether the endpoint wishes to enable -% automatic retry (see Section 8.1.4) for details). -% -% An endpoint that wishes to reduce the value of -% SETTINGS_MAX_CONCURRENT_STREAMS to a value that is below the current -% number of open streams can either close streams that exceed the new -% value or allow streams to complete. - %% (RFC7540 5.2.1) % 3. Flow control is directional with overall control provided by the % receiver. A receiver MAY choose to set any window size that it @@ -2539,21 +2512,72 @@ settings_header_table_size_server(Config0) -> % 0. An endpoint that has both set this parameter to 0 and had it % acknowledged MUST treat the receipt of a PUSH_PROMISE frame as a % connection error (Section 5.4.1) of type PROTOCOL_ERROR. +%% @todo settings_disable_push + +settings_max_concurrent_streams(Config0) -> + doc("The SETTINGS_MAX_CONCURRENT_STREAMS setting can be used to " + "restrict the number of concurrent streams. (RFC7540 5.1.2, RFC7540 6.5.2)"), + %% Create a new listener that allows only a single concurrent stream. + Config = cowboy_test:init_http(name(), #{ + env => #{dispatch => cowboy_router:compile(init_routes(Config0))}, + max_concurrent_streams => 1 + }, Config0), + {ok, Socket} = do_handshake(Config), + %% Send two HEADERS frames as two separate streams. + Headers = [ + {<<":method">>, <<"GET">>}, + {<<":scheme">>, <<"http">>}, + {<<":authority">>, <<"localhost">>}, %% @todo Correct port number. + {<<":path">>, <<"/long_polling">>} + ], + {ReqHeadersBlock1, EncodeState} = cow_hpack:encode(Headers), + {ReqHeadersBlock2, _} = cow_hpack:encode(Headers, EncodeState), + ok = gen_tcp:send(Socket, [ + cow_http2:headers(1, fin, ReqHeadersBlock1), + cow_http2:headers(3, fin, ReqHeadersBlock2) + ]), + %% Receive a REFUSED_STREAM stream error. + {ok, << _:24, 3:8, _:8, 3:32, 7:32 >>} = gen_tcp:recv(Socket, 13, 6000), + ok. + +settings_max_concurrent_streams_0(Config0) -> + doc("The SETTINGS_MAX_CONCURRENT_STREAMS setting can be set to " + "0 to refuse all incoming streams. (RFC7540 5.1.2, RFC7540 6.5.2)"), + %% Create a new listener that allows only a single concurrent stream. + Config = cowboy_test:init_http(name(), #{ + env => #{dispatch => cowboy_router:compile(init_routes(Config0))}, + max_concurrent_streams => 0 + }, Config0), + {ok, Socket} = do_handshake(Config), + %% Send a HEADERS frame. + {HeadersBlock, _} = cow_hpack:encode([ + {<<":method">>, <<"GET">>}, + {<<":scheme">>, <<"http">>}, + {<<":authority">>, <<"localhost">>}, %% @todo Correct port number. + {<<":path">>, <<"/long_polling">>} + ]), + ok = gen_tcp:send(Socket, cow_http2:headers(1, fin, HeadersBlock)), + %% Receive a REFUSED_STREAM stream error. + {ok, << _:24, 3:8, _:8, 1:32, 7:32 >>} = gen_tcp:recv(Socket, 13, 6000), + ok. + +%% @todo The client can limit the number of concurrent streams too. (RFC7540 5.1.2) % -% SETTINGS_MAX_CONCURRENT_STREAMS (0x3): Indicates the maximum number -% of concurrent streams that the sender will allow. This limit is -% directional: it applies to the number of streams that the sender -% permits the receiver to create. Initially, there is no limit to -% this value. It is recommended that this value be no smaller than -% 100, so as to not unnecessarily limit parallelism. -% -% A value of 0 for SETTINGS_MAX_CONCURRENT_STREAMS SHOULD NOT be -% treated as special by endpoints. A zero value does prevent the -% creation of new streams; however, this can also happen for any -% limit that is exhausted with active streams. Servers SHOULD only -% set a zero value for short durations; if a server does not wish to -% accept requests, closing the connection is more appropriate. +% A peer can limit the number of concurrently active streams using the +% SETTINGS_MAX_CONCURRENT_STREAMS parameter (see Section 6.5.2) within +% a SETTINGS frame. The maximum concurrent streams setting is specific +% to each endpoint and applies only to the peer that receives the +% setting. That is, clients specify the maximum number of concurrent +% streams the server can initiate, and servers specify the maximum +% number of concurrent streams the client can initiate. % +% Endpoints MUST NOT exceed the limit set by their peer. An endpoint +% that receives a HEADERS frame that causes its advertised concurrent +% stream limit to be exceeded MUST treat this as a stream error +% (Section 5.4.2) of type PROTOCOL_ERROR or REFUSED_STREAM. The choice +% of error code determines whether the endpoint wishes to enable +% automatic retry (see Section 8.1.4) for details). + % SETTINGS_INITIAL_WINDOW_SIZE (0x4): % Values above the maximum flow-control window size of 2^31-1 MUST % be treated as a connection error (Section 5.4.1) of type @@ -2566,6 +2590,16 @@ settings_header_table_size_server(Config0) -> % Values outside this range MUST be treated as a connection error % (Section 5.4.1) of type PROTOCOL_ERROR. % +% SETTINGS_MAX_HEADER_LIST_SIZE (0x6): This advisory setting informs a +% peer of the maximum size of header list that the sender is +% prepared to accept, in octets. The value is based on the +% uncompressed size of header fields, including the length of the +% name and value in octets plus an overhead of 32 octets for each +% header field. +% +% For any given request, a lower limit than what is advertised MAY +% be enforced. The initial value of this setting is unlimited. +% % An endpoint that receives a SETTINGS frame with any unknown or % unsupported identifier MUST ignore that setting. (6.5.2 and 6.5.3) -- cgit v1.2.3