aboutsummaryrefslogtreecommitdiffstats
path: root/test/rfc7540_SUITE.erl
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2019-01-02 15:08:45 +0100
committerLoïc Hoguin <[email protected]>2019-01-02 15:08:45 +0100
commit8a30f96cf19f9104e3ae8df5f85df33b66b5bfc2 (patch)
treed3e88a75756d45ab41bbf78ab8cb909107a55c2e /test/rfc7540_SUITE.erl
parentca0db57a30c4978f0291ef7900962ed9b8de005d (diff)
downloadgun-8a30f96cf19f9104e3ae8df5f85df33b66b5bfc2.tar.gz
gun-8a30f96cf19f9104e3ae8df5f85df33b66b5bfc2.tar.bz2
gun-8a30f96cf19f9104e3ae8df5f85df33b66b5bfc2.zip
Don't send the default port in the host header for HTTP/2
Diffstat (limited to 'test/rfc7540_SUITE.erl')
-rw-r--r--test/rfc7540_SUITE.erl74
1 files changed, 71 insertions, 3 deletions
diff --git a/test/rfc7540_SUITE.erl b/test/rfc7540_SUITE.erl
index 9398318..54667b7 100644
--- a/test/rfc7540_SUITE.erl
+++ b/test/rfc7540_SUITE.erl
@@ -16,6 +16,10 @@
-compile(export_all).
-compile(nowarn_export_all).
+-ifdef(OTP_RELEASE).
+-compile({nowarn_deprecated_function, [{ssl, ssl_accept, 2}]}).
+-endif.
+
-import(ct_helper, [doc/1]).
all() ->
@@ -23,9 +27,16 @@ all() ->
%% Server helpers.
-do_origin_start(Fun) ->
+do_origin_start(Transport, Fun) ->
Self = self(),
- Pid = spawn_link(fun() -> do_origin_init_tcp(Self, Fun) end),
+ Pid = spawn_link(fun() ->
+ case Transport of
+ tcp ->
+ do_origin_init_tcp(Self, Fun);
+ tls ->
+ do_origin_init_tls_h2(Self, Fun)
+ end
+ end),
Port = do_receive(Pid),
{ok, Pid, Port}.
@@ -37,6 +48,18 @@ do_origin_init_tcp(Parent, Fun) ->
do_handshake(ClientSocket, gen_tcp),
Fun(Parent, ClientSocket, gen_tcp).
+do_origin_init_tls_h2(Parent, Fun) ->
+ Opts = ct_helper:get_certs_from_ets(),
+ {ok, ListenSocket} = ssl:listen(0, [binary, {active, false},
+ {alpn_preferred_protocols, [<<"h2">>]}|Opts]),
+ {ok, {_, Port}} = ssl:sockname(ListenSocket),
+ Parent ! {self(), Port},
+ {ok, ClientSocket} = ssl:transport_accept(ListenSocket, 5000),
+ ok = ssl:ssl_accept(ClientSocket, 5000),
+ {ok, <<"h2">>} = ssl:negotiated_protocol(ClientSocket),
+ do_handshake(ClientSocket, ssl),
+ Fun(Parent, ClientSocket, ssl).
+
do_handshake(Socket, Transport) ->
%% Send a valid preface.
ok = Transport:send(Socket, cow_http2:settings(#{})),
@@ -65,10 +88,55 @@ do_receive(Pid, Timeout) ->
%% Tests.
+authority_default_port_http(_) ->
+ doc("The default port for http should not be sent in "
+ "the :authority pseudo-header. (RFC7540 3, RFC7230 2.7.1)"),
+ do_authority_port(tcp, 80, <<>>).
+
+authority_default_port_https(_) ->
+ doc("The default port for https should not be sent in "
+ "the :authority pseudo-header. (RFC7540 3, RFC7230 2.7.2)"),
+ do_authority_port(tls, 443, <<>>).
+
+authority_other_port_http(_) ->
+ doc("Non-default ports for http must be sent in "
+ "the :authority pseudo-header. (RFC7540 3, RFC7230 2.7.1)"),
+ do_authority_port(tcp, 443, <<":443">>).
+
+authority_other_port_https(_) ->
+ doc("Non-default ports for https must be sent in "
+ "the :authority pseudo-header. (RFC7540 3, RFC7230 2.7.2)"),
+ do_authority_port(tls, 80, <<":80">>).
+
+do_authority_port(Transport0, DefaultPort, AuthorityHeaderPort) ->
+ {ok, OriginPid, OriginPort} = do_origin_start(Transport0, fun(Parent, Socket, Transport) ->
+ %% Receive the HEADERS frame and send the headers decoded.
+ {ok, <<Len:24, 1:8, _:8, 1:32>>} = Transport:recv(Socket, 9, 1000),
+ {ok, ReqHeadersBlock} = Transport:recv(Socket, Len, 1000),
+ {ReqHeaders, _} = cow_hpack:decode(ReqHeadersBlock),
+ Parent ! {self(), ReqHeaders}
+ end),
+ {ok, ConnPid} = gun:open("localhost", OriginPort, #{
+ transport => Transport0,
+ protocols => [http2]
+ }),
+ {ok, http2} = gun:await_up(ConnPid),
+ %% Change the origin's port in the state to trigger the default port behavior.
+ _ = sys:replace_state(ConnPid, fun({StateName, StateData}) ->
+ {StateName, setelement(7, StateData, DefaultPort)}
+ end, 5000),
+ %% Confirm the default port is not sent in the request.
+ timer:sleep(100), %% Give enough time for the handshake to fully complete.
+ _ = gun:get(ConnPid, "/"),
+ ReqHeaders = do_receive(OriginPid),
+ {_, <<"localhost", Rest/bits>>} = lists:keyfind(<<":authority">>, 1, ReqHeaders),
+ AuthorityHeaderPort = Rest,
+ gun:close(ConnPid).
+
headers_priority_flag(_) ->
doc("HEADERS frames may include a PRIORITY flag indicating "
"that stream dependency information is attached. (RFC7540 6.2)"),
- {ok, _, Port} = do_origin_start(fun(_, Socket, Transport) ->
+ {ok, _, Port} = do_origin_start(tcp, fun(_, Socket, Transport) ->
%% Receive a HEADERS frame.
{ok, <<_:24, 1:8, _:8, 1:32>>} = Transport:recv(Socket, 9, 1000),
%% Send a HEADERS frame with PRIORITY back.