diff options
author | Loïc Hoguin <[email protected]> | 2020-02-27 12:19:07 +0100 |
---|---|---|
committer | Loïc Hoguin <[email protected]> | 2020-02-27 15:18:02 +0100 |
commit | c236ed09726a4283a597f662307c9ac07e4f3b7a (patch) | |
tree | 2d2cde30817e9b56b41ba3a8e601e991f08f3110 /test | |
parent | 069040a93bb88477dcae197fa14280a10cce72d8 (diff) | |
download | gun-c236ed09726a4283a597f662307c9ac07e4f3b7a.tar.gz gun-c236ed09726a4283a597f662307c9ac07e4f3b7a.tar.bz2 gun-c236ed09726a4283a597f662307c9ac07e4f3b7a.zip |
Detect invalid HTTP/2 preface errors
And make sure all HTTP/2 connection_error(s) result in a
gun_down message containing the error. In the preface case
we do not send a gun_error message (because there's no stream
open yet) and gun_down was always saying normal.
Also make sure the human readable reason is included in the
gun_error message, if any.
Diffstat (limited to 'test')
-rw-r--r-- | test/rfc7540_SUITE.erl | 82 |
1 files changed, 82 insertions, 0 deletions
diff --git a/test/rfc7540_SUITE.erl b/test/rfc7540_SUITE.erl index 9398318..047e4bb 100644 --- a/test/rfc7540_SUITE.erl +++ b/test/rfc7540_SUITE.erl @@ -63,8 +63,90 @@ do_receive(Pid, Timeout) -> error(timeout) end. +do_init_origin(tcp, http, Fun) -> + Self = self(), + Pid = spawn_link(fun() -> do_init_origin_tcp(Self, Fun) end), + Port = do_receive(Pid), + {ok, Pid, Port}. + +do_init_origin_tcp(Parent, Fun) -> + {ok, ListenSocket} = gen_tcp:listen(0, [binary, {active, false}]), + {ok, {_, Port}} = inet:sockname(ListenSocket), + Parent ! {self(), Port}, + {ok, ClientSocket} = gen_tcp:accept(ListenSocket, 5000), + %% No handshake. + Fun(Parent, ClientSocket, gen_tcp). + %% Tests. +prior_knowledge_preface_garbage(_) -> + doc("A PROTOCOL_ERROR connection error must result from the server sending " + "an invalid preface in the form of garbage when connecting " + "using the prior knowledge method. (RFC7540 3.4, RFC7540 3.5)"), + %% We are going to do the handshake manually. + {ok, _, Port} = do_init_origin(tcp, http, fun(_, Socket, Transport) -> + ok = Transport:send(Socket, <<0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15>>), + timer:sleep(100) + end), + {ok, ConnPid} = gun:open("localhost", Port, #{protocols => [http2]}), + {ok, http2} = gun:await_up(ConnPid), + receive + {gun_down, ConnPid, http2, {error, {connection_error, protocol_error, + 'Invalid connection preface received. (RFC7540 3.5)'}}, [], []} -> + gun:close(ConnPid); + Msg -> + error({unexpected_msg, Msg}) + after 1000 -> + error(timeout) + end. + +prior_knowledge_preface_http1(_) -> + doc("A PROTOCOL_ERROR connection error must result from the server sending " + "an invalid preface in the form of an HTTP/1.1 response when connecting " + "using the prior knowledge method. (RFC7540 3.4, RFC7540 3.5)"), + %% We are going to do the handshake manually. + {ok, _, Port} = do_init_origin(tcp, http, fun(_, Socket, Transport) -> + ok = Transport:send(Socket, << + "HTTP/1.1 400 Bad Request\r\n" + "Connection: close\r\n" + "Content-Length: 0\r\n" + "Date: Thu, 27 Feb 2020 09:32:17 GMT\r\n" + "\r\n">>), + timer:sleep(100) + end), + {ok, ConnPid} = gun:open("localhost", Port, #{protocols => [http2]}), + {ok, http2} = gun:await_up(ConnPid), + receive + {gun_down, ConnPid, http2, {error, {connection_error, protocol_error, + 'Invalid connection preface received. (RFC7540 3.5)'}}, [], []} -> + gun:close(ConnPid); + Msg -> + error({unexpected_msg, Msg}) + after 1000 -> + error(timeout) + end. + +prior_knowledge_preface_other_frame(_) -> + doc("A PROTOCOL_ERROR connection error must result from the server sending " + "an invalid preface in the form of a non-SETTINGS frame when connecting " + "using the prior knowledge method. (RFC7540 3.4, RFC7540 3.5)"), + %% We are going to do the handshake manually. + {ok, _, Port} = do_init_origin(tcp, http, fun(_, Socket, Transport) -> + ok = Transport:send(Socket, cow_http2:window_update(1)), + timer:sleep(100) + end), + {ok, ConnPid} = gun:open("localhost", Port, #{protocols => [http2]}), + {ok, http2} = gun:await_up(ConnPid), + receive + {gun_down, ConnPid, http2, {error, {connection_error, protocol_error, + 'Invalid connection preface received. (RFC7540 3.5)'}}, [], []} -> + gun:close(ConnPid); + Msg -> + error({unexpected_msg, Msg}) + after 1000 -> + error(timeout) + end. + headers_priority_flag(_) -> doc("HEADERS frames may include a PRIORITY flag indicating " "that stream dependency information is attached. (RFC7540 6.2)"), |