aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2018-05-16 16:01:30 +0200
committerLoïc Hoguin <[email protected]>2018-05-16 16:01:30 +0200
commit0e629f47990e0d6a87c2f023f01a00bae48406b9 (patch)
treed4492cba3c23edfe6ab775213d6209db41a6e446
parent827bd8c1c96fc022da43fe72d17e96b0610f7d10 (diff)
downloadcowboy-0e629f47990e0d6a87c2f023f01a00bae48406b9.tar.gz
cowboy-0e629f47990e0d6a87c2f023f01a00bae48406b9.tar.bz2
cowboy-0e629f47990e0d6a87c2f023f01a00bae48406b9.zip
Add option linger_timeout to cowboy_http
-rw-r--r--doc/src/manual/cowboy_http.asciidoc7
-rw-r--r--src/cowboy_http.erl42
2 files changed, 48 insertions, 1 deletions
diff --git a/doc/src/manual/cowboy_http.asciidoc b/doc/src/manual/cowboy_http.asciidoc
index e1936fc..21a6d65 100644
--- a/doc/src/manual/cowboy_http.asciidoc
+++ b/doc/src/manual/cowboy_http.asciidoc
@@ -21,6 +21,7 @@ opts() :: #{
env => cowboy_middleware:env(),
idle_timeout => timeout(),
inactivity_timeout => timeout(),
+ linger_timeout => timeout(),
max_empty_lines => non_neg_integer(),
max_header_name_length => non_neg_integer(),
max_header_value_length => non_neg_integer(),
@@ -59,6 +60,11 @@ idle_timeout (60000)::
inactivity_timeout (300000)::
Time in ms with nothing received at all before Cowboy closes the connection.
+linger_timeout (1000)::
+ Time in ms that Cowboy will wait when closing the connection. This is
+ necessary to avoid the TCP reset problem as described in the
+ https://tools.ietf.org/html/rfc7230#section-6.6[section 6.6 of RFC7230].
+
max_empty_lines (5)::
Maximum number of empty lines before a request.
@@ -98,6 +104,7 @@ stream_handlers ([cowboy_stream_h])::
== Changelog
+* *2.5*: The `linger_timeout` option was added.
* *2.2*: The `max_skip_body_length` option was added.
* *2.0*: The `timeout` option was renamed `request_timeout`.
* *2.0*: The `idle_timeout`, `inactivity_timeout` and `shutdown_timeout` options were added.
diff --git a/src/cowboy_http.erl b/src/cowboy_http.erl
index 440aadd..5890037 100644
--- a/src/cowboy_http.erl
+++ b/src/cowboy_http.erl
@@ -25,6 +25,7 @@
env => cowboy_middleware:env(),
idle_timeout => timeout(),
inactivity_timeout => timeout(),
+ linger_timeout => timeout(),
max_empty_lines => non_neg_integer(),
max_header_name_length => non_neg_integer(),
max_header_value_length => non_neg_integer(),
@@ -1236,9 +1237,10 @@ early_error(StatusCode0, #state{socket=Socket, transport=Transport,
-spec terminate(_, _) -> no_return().
terminate(undefined, Reason) ->
exit({shutdown, Reason});
-terminate(#state{streams=Streams, children=Children}, Reason) ->
+terminate(State=#state{streams=Streams, children=Children}, Reason) ->
terminate_all_streams(Streams, Reason),
cowboy_children:terminate(Children),
+ terminate_linger(State),
exit({shutdown, Reason}).
terminate_all_streams([], _) ->
@@ -1247,6 +1249,44 @@ terminate_all_streams([#stream{id=StreamID, state=StreamState}|Tail], Reason) ->
stream_call_terminate(StreamID, Reason, StreamState),
terminate_all_streams(Tail, Reason).
+terminate_linger(State=#state{socket=Socket, transport=Transport, opts=Opts}) ->
+ case Transport:shutdown(Socket, write) of
+ ok ->
+ case maps:get(linger_timeout, Opts, 1000) of
+ 0 ->
+ ok;
+ infinity ->
+ terminate_linger_loop(State, undefined);
+ Timeout ->
+ TimerRef = erlang:start_timer(Timeout, self(), linger_timeout),
+ terminate_linger_loop(State, TimerRef)
+ end;
+ {error, _} ->
+ ok
+ end.
+
+terminate_linger_loop(State=#state{socket=Socket, transport=Transport}, TimerRef) ->
+ {OK, Closed, Error} = Transport:messages(),
+ %% We may already have a message in the mailbox when we do this
+ %% but it's OK because we are shutting down anyway.
+ case Transport:setopts(Socket, [{active, once}]) of
+ ok ->
+ receive
+ {OK, Socket, _} ->
+ terminate_linger_loop(State, TimerRef);
+ {Closed, Socket} ->
+ ok;
+ {Error, Socket, _} ->
+ ok;
+ {timeout, TimerRef, linger_timeout} ->
+ ok;
+ _ ->
+ terminate_linger_loop(State, TimerRef)
+ end;
+ {error, _} ->
+ ok
+ end.
+
%% System callbacks.
-spec system_continue(_, _, {#state{}, binary()}) -> ok.