diff options
author | Loïc Hoguin <[email protected]> | 2018-05-16 11:00:25 +0200 |
---|---|---|
committer | Loïc Hoguin <[email protected]> | 2018-05-16 11:00:25 +0200 |
commit | ae6c787062e4cf834f6c71674fc6aebdb0b23ffa (patch) | |
tree | 337afec058e5c03add00651d48afed71d7e7b040 | |
parent | 204fa12df877c3657e0a6e3322d1453f83d09202 (diff) | |
download | cowboy-ae6c787062e4cf834f6c71674fc6aebdb0b23ffa.tar.gz cowboy-ae6c787062e4cf834f6c71674fc6aebdb0b23ffa.tar.bz2 cowboy-ae6c787062e4cf834f6c71674fc6aebdb0b23ffa.zip |
Honor the SETTINGS_ENABLE_PUSH from clients
This fixes curl when fetching resources that use push.
-rw-r--r-- | src/cowboy_http2.erl | 4 | ||||
-rw-r--r-- | test/rfc7540_SUITE.erl | 44 |
2 files changed, 33 insertions, 15 deletions
diff --git a/src/cowboy_http2.erl b/src/cowboy_http2.erl index d40046e..8a235af 100644 --- a/src/cowboy_http2.erl +++ b/src/cowboy_http2.erl @@ -706,6 +706,10 @@ commands(State0, Stream0=#stream{local=nofin, te=TE0}, [{trailers, Trailers}|Tai % [{sendfile, IsFin, Offset, Bytes, Path}|Tail]) -> % {State, Stream} = send_data(State0, Stream0, IsFin, {sendfile, Offset, Bytes, Path}), % commands(State, Stream, Tail); +%% Push promises are not sent to clients who disabled them. +commands(State=#state{remote_settings=#{enable_push := false}}, Stream, + [{push, _, _, _, _, _, _, _}|Tail]) -> + commands(State, Stream, Tail); %% Send a push promise. %% %% @todo We need to keep track of what promises we made so that we don't diff --git a/test/rfc7540_SUITE.erl b/test/rfc7540_SUITE.erl index dd67057..dcff787 100644 --- a/test/rfc7540_SUITE.erl +++ b/test/rfc7540_SUITE.erl @@ -2591,14 +2591,6 @@ settings_header_table_size_server(Config0) -> %% the table size was updated to HeaderTableSize. ok. -% SETTINGS_ENABLE_PUSH (0x2): This setting can be used to disable -% server push (Section 8.2). An endpoint MUST NOT send a -% PUSH_PROMISE frame if it receives this parameter set to a value of -% 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)"), @@ -2882,13 +2874,35 @@ settings_max_frame_size_reject_too_large(Config) -> % associated with. If the stream identifier field specifies the value % 0x0, a recipient MUST respond with a connection error (Section 5.4.1) % of type PROTOCOL_ERROR. -% -% PUSH_PROMISE MUST NOT be sent if the SETTINGS_ENABLE_PUSH setting of -% the peer endpoint is set to 0. An endpoint that has set this setting -% and has received acknowledgement MUST treat the receipt of a -% PUSH_PROMISE frame as a connection error (Section 5.4.1) of type -% PROTOCOL_ERROR. -% + +client_settings_disable_push(Config) -> + doc("PUSH_PROMISE frames must not be sent when the setting " + "SETTINGS_ENABLE_PUSH is disabled. (RFC7540 6.5.2, RFC7540 6.6, RFC7540 8.2)"), + %% Do a prior knowledge handshake. + {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(#{ + enable_push => false + })]), + %% Receive the server preface. + {ok, << Len:24 >>} = gen_tcp:recv(Socket, 3, 1000), + {ok, << 4:8, 0:40, _:Len/binary >>} = gen_tcp:recv(Socket, 6 + Len, 1000), + %% Send the SETTINGS ack. + ok = gen_tcp:send(Socket, cow_http2:settings_ack()), + %% Receive the SETTINGS ack. + {ok, << 0:24, 4:8, 1:8, 0:32 >>} = gen_tcp:recv(Socket, 9, 1000), + %% Send a HEADERS frame on a resource that sends PUSH_PROMISE frames. + {HeadersBlock, _} = cow_hpack:encode([ + {<<":method">>, <<"GET">>}, + {<<":scheme">>, <<"http">>}, + {<<":authority">>, <<"localhost">>}, %% @todo Correct port number. + {<<":path">>, <<"/resp/push">>} + ]), + ok = gen_tcp:send(Socket, cow_http2:headers(1, fin, HeadersBlock)), + %% Receive a HEADERS frame as a response, no PUSH_PROMISE frames. + {ok, << _:24, 1:8, _:40 >>} = gen_tcp:recv(Socket, 9, 6000), + ok. + % Since PUSH_PROMISE reserves a stream, ignoring a PUSH_PROMISE frame % causes the stream state to become indeterminate. A receiver MUST % treat the receipt of a PUSH_PROMISE on a stream that is neither |