diff options
Diffstat (limited to 'test/http_SUITE.erl')
-rw-r--r-- | test/http_SUITE.erl | 124 |
1 files changed, 120 insertions, 4 deletions
diff --git a/test/http_SUITE.erl b/test/http_SUITE.erl index 0325279..9928136 100644 --- a/test/http_SUITE.erl +++ b/test/http_SUITE.erl @@ -1,4 +1,4 @@ -%% Copyright (c) 2018-2024, Loïc Hoguin <[email protected]> +%% Copyright (c) Loïc Hoguin <[email protected]> %% %% Permission to use, copy, modify, and/or distribute this software for any %% purpose with or without fee is hereby granted, provided that the above @@ -28,9 +28,16 @@ -import(cowboy_test, [raw_recv/3]). -import(cowboy_test, [raw_expect_recv/2]). -all() -> [{group, clear}]. +all() -> + [{group, clear_no_parallel}, {group, clear}]. -groups() -> [{clear, [parallel], ct_helper:all(?MODULE)}]. +groups() -> + [ + %% cowboy:stop_listener can be slow when called many times + %% in parallel so we must run this test separately from the others. + {clear_no_parallel, [], [graceful_shutdown_listener]}, + {clear, [parallel], ct_helper:all(?MODULE) -- [graceful_shutdown_listener]} + ]. init_per_group(Name, Config) -> cowboy_test:init_http(Name, #{ @@ -43,6 +50,7 @@ end_per_group(Name, _) -> init_dispatch(_) -> cowboy_router:compile([{"localhost", [ {"/", hello_h, []}, + {"/delay_hello", delay_hello_h, #{delay => 1000, notify_received => self()}}, {"/echo/:key", echo_h, []}, {"/resp/:key[/:arg]", resp_h, []}, {"/set_options/:key", set_options_h, []}, @@ -198,6 +206,94 @@ do_chunked_body(ChunkSize0, Data, Acc) -> do_chunked_body(ChunkSize, Rest, [iolist_to_binary(cow_http_te:chunk(Chunk))|Acc]). +disable_http1_tls(Config) -> + doc("Ensure that we can disable HTTP/1.1 over TLS (force HTTP/2)."), + TlsOpts = ct_helper:get_certs_from_ets(), + {ok, _} = cowboy:start_tls(?FUNCTION_NAME, TlsOpts ++ [{port, 0}], #{ + env => #{dispatch => init_dispatch(Config)}, + alpn_default_protocol => http2 + }), + Port = ranch:get_port(?FUNCTION_NAME), + try + {ok, Socket} = ssl:connect("localhost", Port, + [binary, {active, false}|TlsOpts]), + %% ALPN was not negotiated but we're still over HTTP/2. + {error, protocol_not_negotiated} = ssl:negotiated_protocol(Socket), + %% Send a valid preface. + ok = ssl:send(Socket, [ + "PRI * HTTP/2.0\r\n\r\nSM\r\n\r\n", + cow_http2:settings(#{})]), + %% Receive the server preface. + {ok, << Len:24 >>} = ssl:recv(Socket, 3, 1000), + {ok, << 4:8, 0:40, _:Len/binary >>} = ssl:recv(Socket, 6 + Len, 1000), + ok + after + cowboy:stop_listener(?FUNCTION_NAME) + end. + +disable_http2_prior_knowledge(Config) -> + doc("Ensure that we can disable prior knowledge HTTP/2 upgrade."), + {ok, _} = cowboy:start_clear(?FUNCTION_NAME, [{port, 0}], #{ + env => #{dispatch => init_dispatch(Config)}, + protocols => [http] + }), + Port = ranch:get_port(?FUNCTION_NAME), + try + {ok, Socket} = gen_tcp:connect("localhost", Port, [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(#{})]), + {ok, <<"HTTP/1.1 501">>} = gen_tcp:recv(Socket, 12, 1000), + ok + after + cowboy:stop_listener(?FUNCTION_NAME) + end. + +disable_http2_upgrade(Config) -> + doc("Ensure that we can disable HTTP/1.1 upgrade to HTTP/2."), + {ok, _} = cowboy:start_clear(?FUNCTION_NAME, [{port, 0}], #{ + env => #{dispatch => init_dispatch(Config)}, + protocols => [http] + }), + Port = ranch:get_port(?FUNCTION_NAME), + try + {ok, Socket} = gen_tcp:connect("localhost", Port, [binary, {active, false}]), + %% Send a valid preface. + ok = gen_tcp: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"]), + {ok, <<"HTTP/1.1 200">>} = gen_tcp:recv(Socket, 12, 1000), + ok + after + cowboy:stop_listener(?FUNCTION_NAME) + end. + +hibernate(Config) -> + doc("Ensure that we can enable hibernation for HTTP/1.1 connections."), + {ok, _} = cowboy:start_clear(?FUNCTION_NAME, [{port, 0}], #{ + env => #{dispatch => init_dispatch(Config)}, + hibernate => true + }), + Port = ranch:get_port(?FUNCTION_NAME), + try + ConnPid = gun_open([{type, tcp}, {protocol, http}, {port, Port}|Config]), + {ok, http} = gun:await_up(ConnPid), + StreamRef1 = gun:get(ConnPid, "/"), + StreamRef2 = gun:get(ConnPid, "/"), + StreamRef3 = gun:get(ConnPid, "/"), + {response, nofin, 200, _} = gun:await(ConnPid, StreamRef1), + {response, nofin, 200, _} = gun:await(ConnPid, StreamRef2), + {response, nofin, 200, _} = gun:await(ConnPid, StreamRef3), + gun:close(ConnPid) + after + cowboy:stop_listener(?FUNCTION_NAME) + end. + http10_keepalive_false(Config) -> doc("Confirm the option http10_keepalive => false disables keep-alive " "completely for HTTP/1.0 connections."), @@ -454,6 +550,26 @@ request_timeout_pipeline(Config) -> cowboy:stop_listener(?FUNCTION_NAME) end. +request_timeout_pipeline_delay(Config) -> + doc("Ensure the request_timeout does not trigger on requests " + "coming in after a large request body."), + {ok, _} = cowboy:start_clear(?FUNCTION_NAME, [{port, 0}], #{ + env => #{dispatch => init_dispatch(Config)}, + request_timeout => 500 + }), + Port = ranch:get_port(?FUNCTION_NAME), + try + ConnPid = gun_open([{type, tcp}, {protocol, http}, {port, Port}|Config]), + {ok, http} = gun:await_up(ConnPid), + StreamRef1 = gun:post(ConnPid, "/", #{}, <<0:8000000>>), + StreamRef2 = gun:get(ConnPid, "/delay_hello"), + {response, nofin, 200, _} = gun:await(ConnPid, StreamRef1), + {response, nofin, 200, _} = gun:await(ConnPid, StreamRef2), + {error, {down, {shutdown, closed}}} = gun:await(ConnPid, undefined, 1000) + after + cowboy:stop_listener(?FUNCTION_NAME) + end. + request_timeout_skip_body(Config) -> doc("Ensure the request_timeout drops connections when requests " "fail to come in fast enough after skipping a request body."), @@ -779,8 +895,8 @@ graceful_shutdown_listener(Config) -> send_timeout_close(_Config) -> doc("Check that connections are closed on send timeout."), TransOpts = #{ - port => 0, socket_opts => [ + {port, 0}, {send_timeout, 100}, {send_timeout_close, true}, {sndbuf, 10} |