From 6f57405b5c775c4b3b60d0fde15c89e52cb91708 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Wed, 14 Nov 2018 17:10:26 +0100 Subject: Allow disabling keep-alive for HTTP/1.0 connections --- doc/src/manual/cowboy_http.asciidoc | 5 +++++ src/cowboy_http.erl | 6 ++++-- test/http_SUITE.erl | 28 ++++++++++++++++++++++++++++ 3 files changed, 37 insertions(+), 2 deletions(-) diff --git a/doc/src/manual/cowboy_http.asciidoc b/doc/src/manual/cowboy_http.asciidoc index e4706af..e735b9a 100644 --- a/doc/src/manual/cowboy_http.asciidoc +++ b/doc/src/manual/cowboy_http.asciidoc @@ -19,6 +19,7 @@ as a Ranch protocol. opts() :: #{ connection_type => worker | supervisor, env => cowboy_middleware:env(), + http10_keepalive => boolean(), idle_timeout => timeout(), inactivity_timeout => timeout(), linger_timeout => timeout(), @@ -58,6 +59,10 @@ env (#{}):: Middleware environment. +http10_keepalive (true):: + +Whether keep-alive is enabled for HTTP/1.0 connections. + idle_timeout (60000):: Time in ms with no data received before Cowboy closes the connection. diff --git a/src/cowboy_http.erl b/src/cowboy_http.erl index c4a4e79..caa4932 100644 --- a/src/cowboy_http.erl +++ b/src/cowboy_http.erl @@ -28,6 +28,7 @@ compress_threshold => non_neg_integer(), connection_type => worker | supervisor, env => cowboy_middleware:env(), + http10_keepalive => boolean(), idle_timeout => timeout(), inactivity_timeout => timeout(), linger_timeout => timeout(), @@ -1233,7 +1234,8 @@ stream_call_terminate(StreamID, Reason, StreamState, #state{opts=Opts}) -> Class, Exception, erlang:get_stacktrace()), Opts) end. -%% @todo max_reqs also +maybe_req_close(#state{opts=#{http10_keepalive := false}}, _, 'HTTP/1.0') -> + close; maybe_req_close(_, #{<<"connection">> := Conn}, 'HTTP/1.0') -> Conns = cow_http_hd:parse_connection(Conn), case lists:member(<<"keep-alive">>, Conns) of @@ -1247,7 +1249,7 @@ maybe_req_close(_, #{<<"connection">> := Conn}, 'HTTP/1.1') -> true -> close; false -> keepalive end; -maybe_req_close(_State, _, _) -> +maybe_req_close(_, _, _) -> keepalive. connection(State=#state{last_streamid=StreamID}, Headers=#{<<"connection">> := Conn}, StreamID, _) -> diff --git a/test/http_SUITE.erl b/test/http_SUITE.erl index a8d3503..b66b641 100644 --- a/test/http_SUITE.erl +++ b/test/http_SUITE.erl @@ -21,6 +21,9 @@ -import(ct_helper, [get_remote_pid_tcp/1]). -import(ct_helper, [name/0]). -import(cowboy_test, [gun_open/1]). +-import(cowboy_test, [raw_open/1]). +-import(cowboy_test, [raw_send/2]). +-import(cowboy_test, [raw_recv_head/1]). all() -> [{group, clear}]. @@ -33,6 +36,31 @@ init_routes(_) -> [ ]} ]. +http10_keepalive_false(Config) -> + doc("Confirm the option {http10_keepalive, false} disables keep-alive " + "completely for HTTP/1.0 connections."), + {ok, _} = cowboy:start_clear(name(), [{port, 0}], #{ + env => #{dispatch => cowboy_router:compile(init_routes(Config))}, + http10_keepalive => false + }), + Port = ranch:get_port(name()), + Keepalive = "GET / HTTP/1.0\r\nhost: localhost\r\nConnection: keep-alive\r\n\r\n", + Client = raw_open([{type, tcp}, {port, Port}, {opts, []}|Config]), + ok = raw_send(Client, Keepalive), + _ = case catch raw_recv_head(Client) of + {'EXIT', _} -> error(closed); + Data -> + %% Cowboy always advertises itself as HTTP/1.1. + {'HTTP/1.1', 200, _, Rest} = cow_http:parse_status_line(Data), + {Headers, _} = cow_http:parse_headers(Rest), + {_, <<"close">>} = lists:keyfind(<<"connection">>, 1, Headers) + end, + ok = raw_send(Client, Keepalive), + case catch raw_recv_head(Client) of + {'EXIT', _} -> closed; + _ -> error(not_closed) + end. + idle_timeout_infinity(Config) -> doc("Ensure the idle_timeout option accepts the infinity value."), {ok, _} = cowboy:start_clear(name(), [{port, 0}], #{ -- cgit v1.2.3