mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-14 12:20:24 +00:00
Add option linger_timeout to cowboy_http
This commit is contained in:
parent
827bd8c1c9
commit
0e629f4799
2 changed files with 48 additions and 1 deletions
|
@ -21,6 +21,7 @@ opts() :: #{
|
||||||
env => cowboy_middleware:env(),
|
env => cowboy_middleware:env(),
|
||||||
idle_timeout => timeout(),
|
idle_timeout => timeout(),
|
||||||
inactivity_timeout => timeout(),
|
inactivity_timeout => timeout(),
|
||||||
|
linger_timeout => timeout(),
|
||||||
max_empty_lines => non_neg_integer(),
|
max_empty_lines => non_neg_integer(),
|
||||||
max_header_name_length => non_neg_integer(),
|
max_header_name_length => non_neg_integer(),
|
||||||
max_header_value_length => non_neg_integer(),
|
max_header_value_length => non_neg_integer(),
|
||||||
|
@ -59,6 +60,11 @@ idle_timeout (60000)::
|
||||||
inactivity_timeout (300000)::
|
inactivity_timeout (300000)::
|
||||||
Time in ms with nothing received at all before Cowboy closes the connection.
|
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)::
|
max_empty_lines (5)::
|
||||||
Maximum number of empty lines before a request.
|
Maximum number of empty lines before a request.
|
||||||
|
|
||||||
|
@ -98,6 +104,7 @@ stream_handlers ([cowboy_stream_h])::
|
||||||
|
|
||||||
== Changelog
|
== Changelog
|
||||||
|
|
||||||
|
* *2.5*: The `linger_timeout` option was added.
|
||||||
* *2.2*: The `max_skip_body_length` 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 `timeout` option was renamed `request_timeout`.
|
||||||
* *2.0*: The `idle_timeout`, `inactivity_timeout` and `shutdown_timeout` options were added.
|
* *2.0*: The `idle_timeout`, `inactivity_timeout` and `shutdown_timeout` options were added.
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
env => cowboy_middleware:env(),
|
env => cowboy_middleware:env(),
|
||||||
idle_timeout => timeout(),
|
idle_timeout => timeout(),
|
||||||
inactivity_timeout => timeout(),
|
inactivity_timeout => timeout(),
|
||||||
|
linger_timeout => timeout(),
|
||||||
max_empty_lines => non_neg_integer(),
|
max_empty_lines => non_neg_integer(),
|
||||||
max_header_name_length => non_neg_integer(),
|
max_header_name_length => non_neg_integer(),
|
||||||
max_header_value_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().
|
-spec terminate(_, _) -> no_return().
|
||||||
terminate(undefined, Reason) ->
|
terminate(undefined, Reason) ->
|
||||||
exit({shutdown, Reason});
|
exit({shutdown, Reason});
|
||||||
terminate(#state{streams=Streams, children=Children}, Reason) ->
|
terminate(State=#state{streams=Streams, children=Children}, Reason) ->
|
||||||
terminate_all_streams(Streams, Reason),
|
terminate_all_streams(Streams, Reason),
|
||||||
cowboy_children:terminate(Children),
|
cowboy_children:terminate(Children),
|
||||||
|
terminate_linger(State),
|
||||||
exit({shutdown, Reason}).
|
exit({shutdown, Reason}).
|
||||||
|
|
||||||
terminate_all_streams([], _) ->
|
terminate_all_streams([], _) ->
|
||||||
|
@ -1247,6 +1249,44 @@ terminate_all_streams([#stream{id=StreamID, state=StreamState}|Tail], Reason) ->
|
||||||
stream_call_terminate(StreamID, Reason, StreamState),
|
stream_call_terminate(StreamID, Reason, StreamState),
|
||||||
terminate_all_streams(Tail, Reason).
|
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.
|
%% System callbacks.
|
||||||
|
|
||||||
-spec system_continue(_, _, {#state{}, binary()}) -> ok.
|
-spec system_continue(_, _, {#state{}, binary()}) -> ok.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue