0
Fork 0
mirror of https://github.com/ninenines/cowboy.git synced 2025-07-14 12:20:24 +00:00

Provide better control over which HTTP protocols are enabled

Over cleartext TCP the `protocols` option lists the enabled
protocols. The default is to allow both HTTP/1.1 and HTTP/2.

Over TLS the default protocol to use when ALPN is not used
can now be configured via the `alpn_default_protocol` option.

Performing an HTTP/1.1 upgrade to HTTP/2 over TLS is now
rejected with an error as connecting to HTTP/2 over TLS
requires the use of ALPN (or that HTTP/2 be the default
when connecting over TLS).
This commit is contained in:
Loïc Hoguin 2025-02-10 15:26:00 +01:00
parent 971684788d
commit 053e233c56
No known key found for this signature in database
GPG key ID: 8A9DF795F6FED764
8 changed files with 160 additions and 28 deletions

View file

@ -35,8 +35,9 @@ all() -> [{group, clear}, {group, tls}].
groups() ->
Tests = ct_helper:all(?MODULE),
Clear = [T || T <- Tests, lists:sublist(atom_to_list(T), 4) =/= "alpn"] -- [prior_knowledge_reject_tls],
TLS = [T || T <- Tests, lists:sublist(atom_to_list(T), 4) =:= "alpn"] ++ [prior_knowledge_reject_tls],
RejectTLS = [http_upgrade_reject_tls, prior_knowledge_reject_tls],
Clear = [T || T <- Tests, lists:sublist(atom_to_list(T), 4) =/= "alpn"] -- RejectTLS,
TLS = [T || T <- Tests, lists:sublist(atom_to_list(T), 4) =:= "alpn"] ++ RejectTLS,
[{clear, [parallel], Clear}, {tls, [parallel], TLS}].
init_per_group(Name = clear, Config) ->
@ -68,6 +69,24 @@ init_routes(_) -> [
%% Starting HTTP/2 for "http" URIs.
http_upgrade_reject_tls(Config) ->
doc("Implementations that support HTTP/2 over TLS must use ALPN. (RFC7540 3.4)"),
TlsOpts = ct_helper:get_certs_from_ets(),
{ok, Socket} = ssl:connect("localhost", config(port, Config),
[binary, {active, false}|TlsOpts]),
%% Send a valid preface.
ok = ssl:send(Socket, [
"GET / HTTP/1.1\r\n"
"Host: localhost\r\n"
"Connection: Upgrade, HTTP2-Settings\r\n"
"Upgrade: h2c\r\n"
"HTTP2-Settings: ", base64:encode(cow_http2:settings_payload(#{})), "\r\n",
"\r\n"]),
%% We expect the server to send an HTTP 400 error
%% when trying to use HTTP/2 without going through ALPN negotiation.
{ok, <<"HTTP/1.1 400">>} = ssl:recv(Socket, 12, 1000),
ok.
http_upgrade_ignore_h2(Config) ->
doc("An h2 token in an Upgrade field must be ignored. (RFC7540 3.2)"),
{ok, Socket} = gen_tcp:connect("localhost", config(port, Config), [binary, {active, false}]),