mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-14 20:30:23 +00:00
Add hibernate option to cowboy_http and cowboy_http2
When enabled the connection process will automatically hibernate. Because hibernation triggers GC, this can be used as a way to keep memory usage lower, at the cost of performance.
This commit is contained in:
parent
d3f6bda38b
commit
bf2aa3cbe0
6 changed files with 99 additions and 33 deletions
|
@ -21,6 +21,7 @@ opts() :: #{
|
||||||
chunked => boolean(),
|
chunked => boolean(),
|
||||||
connection_type => worker | supervisor,
|
connection_type => worker | supervisor,
|
||||||
dynamic_buffer => false | {pos_integer(), pos_integer()},
|
dynamic_buffer => false | {pos_integer(), pos_integer()},
|
||||||
|
hibernate => boolean(),
|
||||||
http10_keepalive => boolean(),
|
http10_keepalive => boolean(),
|
||||||
idle_timeout => timeout(),
|
idle_timeout => timeout(),
|
||||||
inactivity_timeout => timeout(),
|
inactivity_timeout => timeout(),
|
||||||
|
@ -87,6 +88,10 @@ The dynamic buffer size functionality can be disabled by
|
||||||
setting this option to `false`. Cowboy will also disable
|
setting this option to `false`. Cowboy will also disable
|
||||||
it by default when the `buffer` transport option is configured.
|
it by default when the `buffer` transport option is configured.
|
||||||
|
|
||||||
|
hibernate (false)::
|
||||||
|
|
||||||
|
Whether the connection process will hibernate automatically.
|
||||||
|
|
||||||
http10_keepalive (true)::
|
http10_keepalive (true)::
|
||||||
|
|
||||||
Whether keep-alive is enabled for HTTP/1.0 connections.
|
Whether keep-alive is enabled for HTTP/1.0 connections.
|
||||||
|
@ -179,7 +184,7 @@ Ordered list of stream handlers that will handle all stream events.
|
||||||
== Changelog
|
== Changelog
|
||||||
|
|
||||||
* *2.13*: The `active_n` default value was changed to `1`.
|
* *2.13*: The `active_n` default value was changed to `1`.
|
||||||
* *2.13*: The `dynamic_buffer` option was added.
|
* *2.13*: The `dynamic_buffer` and `hibernate` options were added.
|
||||||
* *2.11*: The `reset_idle_timeout_on_send` option was added.
|
* *2.11*: The `reset_idle_timeout_on_send` option was added.
|
||||||
* *2.8*: The `active_n` option was added.
|
* *2.8*: The `active_n` option was added.
|
||||||
* *2.7*: The `initial_stream_flow_size` and `logger` options were added.
|
* *2.7*: The `initial_stream_flow_size` and `logger` options were added.
|
||||||
|
|
|
@ -25,6 +25,7 @@ opts() :: #{
|
||||||
enable_connect_protocol => boolean(),
|
enable_connect_protocol => boolean(),
|
||||||
goaway_initial_timeout => timeout(),
|
goaway_initial_timeout => timeout(),
|
||||||
goaway_complete_timeout => timeout(),
|
goaway_complete_timeout => timeout(),
|
||||||
|
hibernate => boolean(),
|
||||||
idle_timeout => timeout(),
|
idle_timeout => timeout(),
|
||||||
inactivity_timeout => timeout(),
|
inactivity_timeout => timeout(),
|
||||||
initial_connection_window_size => 65535..16#7fffffff,
|
initial_connection_window_size => 65535..16#7fffffff,
|
||||||
|
@ -122,6 +123,10 @@ goaway_complete_timeout (3000)::
|
||||||
Time in ms to wait for ongoing streams to complete before closing the connection
|
Time in ms to wait for ongoing streams to complete before closing the connection
|
||||||
during a graceful shutdown.
|
during a graceful shutdown.
|
||||||
|
|
||||||
|
hibernate (false)::
|
||||||
|
|
||||||
|
Whether the connection process will hibernate automatically.
|
||||||
|
|
||||||
idle_timeout (60000)::
|
idle_timeout (60000)::
|
||||||
|
|
||||||
Time in ms with no data received before Cowboy closes the connection.
|
Time in ms with no data received before Cowboy closes the connection.
|
||||||
|
@ -302,7 +307,7 @@ too many `WINDOW_UPDATE` frames.
|
||||||
== Changelog
|
== Changelog
|
||||||
|
|
||||||
* *2.13*: The `active_n` default value was changed to `1`.
|
* *2.13*: The `active_n` default value was changed to `1`.
|
||||||
* *2.13*: The `dynamic_buffer` option was added.
|
* *2.13*: The `dynamic_buffer` and `hibernate` options were added.
|
||||||
* *2.11*: Websocket over HTTP/2 is now considered stable.
|
* *2.11*: Websocket over HTTP/2 is now considered stable.
|
||||||
* *2.11*: The `reset_idle_timeout_on_send` option was added.
|
* *2.11*: The `reset_idle_timeout_on_send` option was added.
|
||||||
* *2.11*: Add the option `max_cancel_stream_rate` to protect
|
* *2.11*: Add the option `max_cancel_stream_rate` to protect
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
-module(cowboy_http).
|
-module(cowboy_http).
|
||||||
|
|
||||||
-export([init/6]).
|
-export([init/6]).
|
||||||
|
-export([loop/1]).
|
||||||
|
|
||||||
-export([system_continue/3]).
|
-export([system_continue/3]).
|
||||||
-export([system_terminate/4]).
|
-export([system_terminate/4]).
|
||||||
|
@ -32,6 +33,7 @@
|
||||||
dynamic_buffer_initial_average => non_neg_integer(),
|
dynamic_buffer_initial_average => non_neg_integer(),
|
||||||
dynamic_buffer_initial_size => pos_integer(),
|
dynamic_buffer_initial_size => pos_integer(),
|
||||||
env => cowboy_middleware:env(),
|
env => cowboy_middleware:env(),
|
||||||
|
hibernate => boolean(),
|
||||||
http10_keepalive => boolean(),
|
http10_keepalive => boolean(),
|
||||||
idle_timeout => timeout(),
|
idle_timeout => timeout(),
|
||||||
inactivity_timeout => timeout(),
|
inactivity_timeout => timeout(),
|
||||||
|
@ -192,7 +194,7 @@ init(Parent, Ref, Socket, Transport, ProxyHeader, Opts) ->
|
||||||
dynamic_buffer_moving_average=maps:get(dynamic_buffer_initial_average, Opts, 0),
|
dynamic_buffer_moving_average=maps:get(dynamic_buffer_initial_average, Opts, 0),
|
||||||
last_streamid=maps:get(max_keepalive, Opts, 1000)},
|
last_streamid=maps:get(max_keepalive, Opts, 1000)},
|
||||||
safe_setopts_active(State),
|
safe_setopts_active(State),
|
||||||
loop(set_timeout(State, request_timeout)).
|
before_loop(set_timeout(State, request_timeout)).
|
||||||
|
|
||||||
-include("cowboy_dynamic_buffer.hrl").
|
-include("cowboy_dynamic_buffer.hrl").
|
||||||
|
|
||||||
|
@ -223,6 +225,11 @@ flush_passive(Socket, Messages) ->
|
||||||
ok
|
ok
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
before_loop(State=#state{opts=#{hibernate := true}}) ->
|
||||||
|
proc_lib:hibernate(?MODULE, loop, [State]);
|
||||||
|
before_loop(State) ->
|
||||||
|
loop(State).
|
||||||
|
|
||||||
loop(State=#state{parent=Parent, socket=Socket, transport=Transport, opts=Opts,
|
loop(State=#state{parent=Parent, socket=Socket, transport=Transport, opts=Opts,
|
||||||
buffer=Buffer, timer=TimerRef, children=Children, in_streamid=InStreamID,
|
buffer=Buffer, timer=TimerRef, children=Children, in_streamid=InStreamID,
|
||||||
last_streamid=LastStreamID}) ->
|
last_streamid=LastStreamID}) ->
|
||||||
|
@ -233,7 +240,7 @@ loop(State=#state{parent=Parent, socket=Socket, transport=Transport, opts=Opts,
|
||||||
%% we want to process was received fully.
|
%% we want to process was received fully.
|
||||||
{OK, Socket, Data} when OK =:= element(1, Messages), InStreamID > LastStreamID ->
|
{OK, Socket, Data} when OK =:= element(1, Messages), InStreamID > LastStreamID ->
|
||||||
State1 = maybe_resize_buffer(State, Data),
|
State1 = maybe_resize_buffer(State, Data),
|
||||||
loop(State1);
|
before_loop(State1);
|
||||||
%% Socket messages.
|
%% Socket messages.
|
||||||
{OK, Socket, Data} when OK =:= element(1, Messages) ->
|
{OK, Socket, Data} when OK =:= element(1, Messages) ->
|
||||||
State1 = maybe_resize_buffer(State, Data),
|
State1 = maybe_resize_buffer(State, Data),
|
||||||
|
@ -246,37 +253,37 @@ loop(State=#state{parent=Parent, socket=Socket, transport=Transport, opts=Opts,
|
||||||
%% Hardcoded for compatibility with Ranch 1.x.
|
%% Hardcoded for compatibility with Ranch 1.x.
|
||||||
Passive =:= tcp_passive; Passive =:= ssl_passive ->
|
Passive =:= tcp_passive; Passive =:= ssl_passive ->
|
||||||
safe_setopts_active(State),
|
safe_setopts_active(State),
|
||||||
loop(State);
|
before_loop(State);
|
||||||
%% Timeouts.
|
%% Timeouts.
|
||||||
{timeout, Ref, {shutdown, Pid}} ->
|
{timeout, Ref, {shutdown, Pid}} ->
|
||||||
cowboy_children:shutdown_timeout(Children, Ref, Pid),
|
cowboy_children:shutdown_timeout(Children, Ref, Pid),
|
||||||
loop(State);
|
before_loop(State);
|
||||||
{timeout, TimerRef, Reason} ->
|
{timeout, TimerRef, Reason} ->
|
||||||
timeout(State, Reason);
|
timeout(State, Reason);
|
||||||
{timeout, _, _} ->
|
{timeout, _, _} ->
|
||||||
loop(State);
|
before_loop(State);
|
||||||
%% System messages.
|
%% System messages.
|
||||||
{'EXIT', Parent, shutdown} ->
|
{'EXIT', Parent, shutdown} ->
|
||||||
Reason = {stop, {exit, shutdown}, 'Parent process requested shutdown.'},
|
Reason = {stop, {exit, shutdown}, 'Parent process requested shutdown.'},
|
||||||
loop(initiate_closing(State, Reason));
|
before_loop(initiate_closing(State, Reason));
|
||||||
{'EXIT', Parent, Reason} ->
|
{'EXIT', Parent, Reason} ->
|
||||||
terminate(State, {stop, {exit, Reason}, 'Parent process terminated.'});
|
terminate(State, {stop, {exit, Reason}, 'Parent process terminated.'});
|
||||||
{system, From, Request} ->
|
{system, From, Request} ->
|
||||||
sys:handle_system_msg(Request, From, Parent, ?MODULE, [], State);
|
sys:handle_system_msg(Request, From, Parent, ?MODULE, [], State);
|
||||||
%% Messages pertaining to a stream.
|
%% Messages pertaining to a stream.
|
||||||
{{Pid, StreamID}, Msg} when Pid =:= self() ->
|
{{Pid, StreamID}, Msg} when Pid =:= self() ->
|
||||||
loop(info(State, StreamID, Msg));
|
before_loop(info(State, StreamID, Msg));
|
||||||
%% Exit signal from children.
|
%% Exit signal from children.
|
||||||
Msg = {'EXIT', Pid, _} ->
|
Msg = {'EXIT', Pid, _} ->
|
||||||
loop(down(State, Pid, Msg));
|
before_loop(down(State, Pid, Msg));
|
||||||
%% Calls from supervisor module.
|
%% Calls from supervisor module.
|
||||||
{'$gen_call', From, Call} ->
|
{'$gen_call', From, Call} ->
|
||||||
cowboy_children:handle_supervisor_call(Call, From, Children, ?MODULE),
|
cowboy_children:handle_supervisor_call(Call, From, Children, ?MODULE),
|
||||||
loop(State);
|
before_loop(State);
|
||||||
%% Unknown messages.
|
%% Unknown messages.
|
||||||
Msg ->
|
Msg ->
|
||||||
cowboy:log(warning, "Received stray message ~p.~n", [Msg], Opts),
|
cowboy:log(warning, "Received stray message ~p.~n", [Msg], Opts),
|
||||||
loop(State)
|
before_loop(State)
|
||||||
after InactivityTimeout ->
|
after InactivityTimeout ->
|
||||||
terminate(State, {internal_error, timeout, 'No message or data received before timeout.'})
|
terminate(State, {internal_error, timeout, 'No message or data received before timeout.'})
|
||||||
end.
|
end.
|
||||||
|
@ -362,12 +369,12 @@ timeout(State, idle_timeout) ->
|
||||||
'Connection idle longer than configuration allows.'}).
|
'Connection idle longer than configuration allows.'}).
|
||||||
|
|
||||||
parse(<<>>, State) ->
|
parse(<<>>, State) ->
|
||||||
loop(State#state{buffer= <<>>});
|
before_loop(State#state{buffer= <<>>});
|
||||||
%% Do not process requests that come in after the last request
|
%% Do not process requests that come in after the last request
|
||||||
%% and discard the buffer if any to save memory.
|
%% and discard the buffer if any to save memory.
|
||||||
parse(_, State=#state{in_streamid=InStreamID, in_state=#ps_request_line{},
|
parse(_, State=#state{in_streamid=InStreamID, in_state=#ps_request_line{},
|
||||||
last_streamid=LastStreamID}) when InStreamID > LastStreamID ->
|
last_streamid=LastStreamID}) when InStreamID > LastStreamID ->
|
||||||
loop(State#state{buffer= <<>>});
|
before_loop(State#state{buffer= <<>>});
|
||||||
parse(Buffer, State=#state{in_state=#ps_request_line{empty_lines=EmptyLines}}) ->
|
parse(Buffer, State=#state{in_state=#ps_request_line{empty_lines=EmptyLines}}) ->
|
||||||
after_parse(parse_request(Buffer, State, EmptyLines));
|
after_parse(parse_request(Buffer, State, EmptyLines));
|
||||||
parse(Buffer, State=#state{in_state=PS=#ps_header{headers=Headers, name=undefined}}) ->
|
parse(Buffer, State=#state{in_state=PS=#ps_header{headers=Headers, name=undefined}}) ->
|
||||||
|
@ -442,7 +449,7 @@ after_parse({data, _, IsFin, _, State=#state{buffer=Buffer}}) ->
|
||||||
nofin -> idle_timeout
|
nofin -> idle_timeout
|
||||||
end));
|
end));
|
||||||
after_parse({more, State}) ->
|
after_parse({more, State}) ->
|
||||||
loop(set_timeout(State, idle_timeout)).
|
before_loop(set_timeout(State, idle_timeout)).
|
||||||
|
|
||||||
update_flow(fin, _, State) ->
|
update_flow(fin, _, State) ->
|
||||||
%% This function is only called after parsing, therefore we
|
%% This function is only called after parsing, therefore we
|
||||||
|
@ -1622,12 +1629,12 @@ terminate_linger_loop(State=#state{socket=Socket}, TimerRef, Messages) ->
|
||||||
|
|
||||||
-spec system_continue(_, _, #state{}) -> ok.
|
-spec system_continue(_, _, #state{}) -> ok.
|
||||||
system_continue(_, _, State) ->
|
system_continue(_, _, State) ->
|
||||||
loop(State).
|
before_loop(State).
|
||||||
|
|
||||||
-spec system_terminate(any(), _, _, #state{}) -> no_return().
|
-spec system_terminate(any(), _, _, #state{}) -> no_return().
|
||||||
system_terminate(Reason0, _, _, State) ->
|
system_terminate(Reason0, _, _, State) ->
|
||||||
Reason = {stop, {exit, Reason0}, 'sys:terminate/2,3 was called.'},
|
Reason = {stop, {exit, Reason0}, 'sys:terminate/2,3 was called.'},
|
||||||
loop(initiate_closing(State, Reason)).
|
before_loop(initiate_closing(State, Reason)).
|
||||||
|
|
||||||
-spec system_code_change(Misc, _, _, _) -> {ok, Misc} when Misc::{#state{}, binary()}.
|
-spec system_code_change(Misc, _, _, _) -> {ok, Misc} when Misc::{#state{}, binary()}.
|
||||||
system_code_change(Misc, _, _, _) ->
|
system_code_change(Misc, _, _, _) ->
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
-export([init/6]).
|
-export([init/6]).
|
||||||
-export([init/10]).
|
-export([init/10]).
|
||||||
-export([init/12]).
|
-export([init/12]).
|
||||||
|
-export([loop/2]).
|
||||||
|
|
||||||
-export([system_continue/3]).
|
-export([system_continue/3]).
|
||||||
-export([system_terminate/4]).
|
-export([system_terminate/4]).
|
||||||
|
@ -36,6 +37,7 @@
|
||||||
env => cowboy_middleware:env(),
|
env => cowboy_middleware:env(),
|
||||||
goaway_initial_timeout => timeout(),
|
goaway_initial_timeout => timeout(),
|
||||||
goaway_complete_timeout => timeout(),
|
goaway_complete_timeout => timeout(),
|
||||||
|
hibernate => boolean(),
|
||||||
idle_timeout => timeout(),
|
idle_timeout => timeout(),
|
||||||
inactivity_timeout => timeout(),
|
inactivity_timeout => timeout(),
|
||||||
initial_connection_window_size => 65535..16#7fffffff,
|
initial_connection_window_size => 65535..16#7fffffff,
|
||||||
|
@ -188,7 +190,7 @@ init(Parent, Ref, Socket, Transport, ProxyHeader, Opts, Peer, Sock, Cert, Buffer
|
||||||
http2_status=sequence, http2_machine=HTTP2Machine}), 0),
|
http2_status=sequence, http2_machine=HTTP2Machine}), 0),
|
||||||
safe_setopts_active(State),
|
safe_setopts_active(State),
|
||||||
case Buffer of
|
case Buffer of
|
||||||
<<>> -> loop(State, Buffer);
|
<<>> -> before_loop(State, Buffer);
|
||||||
_ -> parse(State, Buffer)
|
_ -> parse(State, Buffer)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -250,7 +252,7 @@ init(Parent, Ref, Socket, Transport, ProxyHeader, Opts, Peer, Sock, Cert, Buffer
|
||||||
ok = maybe_socket_error(State, Transport:send(Socket, Preface)),
|
ok = maybe_socket_error(State, Transport:send(Socket, Preface)),
|
||||||
safe_setopts_active(State),
|
safe_setopts_active(State),
|
||||||
case Buffer of
|
case Buffer of
|
||||||
<<>> -> loop(State, Buffer);
|
<<>> -> before_loop(State, Buffer);
|
||||||
_ -> parse(State, Buffer)
|
_ -> parse(State, Buffer)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
@ -267,6 +269,11 @@ setopts_active(#state{socket=Socket, transport=Transport, opts=Opts}) ->
|
||||||
safe_setopts_active(State) ->
|
safe_setopts_active(State) ->
|
||||||
ok = maybe_socket_error(State, setopts_active(State)).
|
ok = maybe_socket_error(State, setopts_active(State)).
|
||||||
|
|
||||||
|
before_loop(State=#state{opts=#{hibernate := true}}, Buffer) ->
|
||||||
|
proc_lib:hibernate(?MODULE, loop, [State, Buffer]);
|
||||||
|
before_loop(State, Buffer) ->
|
||||||
|
loop(State, Buffer).
|
||||||
|
|
||||||
loop(State=#state{parent=Parent, socket=Socket, transport=Transport,
|
loop(State=#state{parent=Parent, socket=Socket, transport=Transport,
|
||||||
opts=Opts, timer=TimerRef, children=Children}, Buffer) ->
|
opts=Opts, timer=TimerRef, children=Children}, Buffer) ->
|
||||||
Messages = Transport:messages(),
|
Messages = Transport:messages(),
|
||||||
|
@ -288,11 +295,11 @@ loop(State=#state{parent=Parent, socket=Socket, transport=Transport,
|
||||||
%% Hardcoded for compatibility with Ranch 1.x.
|
%% Hardcoded for compatibility with Ranch 1.x.
|
||||||
Passive =:= tcp_passive; Passive =:= ssl_passive ->
|
Passive =:= tcp_passive; Passive =:= ssl_passive ->
|
||||||
safe_setopts_active(State),
|
safe_setopts_active(State),
|
||||||
loop(State, Buffer);
|
before_loop(State, Buffer);
|
||||||
%% System messages.
|
%% System messages.
|
||||||
{'EXIT', Parent, shutdown} ->
|
{'EXIT', Parent, shutdown} ->
|
||||||
Reason = {stop, {exit, shutdown}, 'Parent process requested shutdown.'},
|
Reason = {stop, {exit, shutdown}, 'Parent process requested shutdown.'},
|
||||||
loop(initiate_closing(State, Reason), Buffer);
|
before_loop(initiate_closing(State, Reason), Buffer);
|
||||||
{'EXIT', Parent, Reason} ->
|
{'EXIT', Parent, Reason} ->
|
||||||
terminate(State, {stop, {exit, Reason}, 'Parent process terminated.'});
|
terminate(State, {stop, {exit, Reason}, 'Parent process terminated.'});
|
||||||
{system, From, Request} ->
|
{system, From, Request} ->
|
||||||
|
@ -302,27 +309,27 @@ loop(State=#state{parent=Parent, socket=Socket, transport=Transport,
|
||||||
tick_idle_timeout(State, Buffer);
|
tick_idle_timeout(State, Buffer);
|
||||||
{timeout, Ref, {shutdown, Pid}} ->
|
{timeout, Ref, {shutdown, Pid}} ->
|
||||||
cowboy_children:shutdown_timeout(Children, Ref, Pid),
|
cowboy_children:shutdown_timeout(Children, Ref, Pid),
|
||||||
loop(State, Buffer);
|
before_loop(State, Buffer);
|
||||||
{timeout, TRef, {cow_http2_machine, Name}} ->
|
{timeout, TRef, {cow_http2_machine, Name}} ->
|
||||||
loop(timeout(State, Name, TRef), Buffer);
|
before_loop(timeout(State, Name, TRef), Buffer);
|
||||||
{timeout, TimerRef, {goaway_initial_timeout, Reason}} ->
|
{timeout, TimerRef, {goaway_initial_timeout, Reason}} ->
|
||||||
loop(closing(State, Reason), Buffer);
|
before_loop(closing(State, Reason), Buffer);
|
||||||
{timeout, TimerRef, {goaway_complete_timeout, Reason}} ->
|
{timeout, TimerRef, {goaway_complete_timeout, Reason}} ->
|
||||||
terminate(State, {stop, stop_reason(Reason),
|
terminate(State, {stop, stop_reason(Reason),
|
||||||
'Graceful shutdown timed out.'});
|
'Graceful shutdown timed out.'});
|
||||||
%% Messages pertaining to a stream.
|
%% Messages pertaining to a stream.
|
||||||
{{Pid, StreamID}, Msg} when Pid =:= self() ->
|
{{Pid, StreamID}, Msg} when Pid =:= self() ->
|
||||||
loop(info(State, StreamID, Msg), Buffer);
|
before_loop(info(State, StreamID, Msg), Buffer);
|
||||||
%% Exit signal from children.
|
%% Exit signal from children.
|
||||||
Msg = {'EXIT', Pid, _} ->
|
Msg = {'EXIT', Pid, _} ->
|
||||||
loop(down(State, Pid, Msg), Buffer);
|
before_loop(down(State, Pid, Msg), Buffer);
|
||||||
%% Calls from supervisor module.
|
%% Calls from supervisor module.
|
||||||
{'$gen_call', From, Call} ->
|
{'$gen_call', From, Call} ->
|
||||||
cowboy_children:handle_supervisor_call(Call, From, Children, ?MODULE),
|
cowboy_children:handle_supervisor_call(Call, From, Children, ?MODULE),
|
||||||
loop(State, Buffer);
|
before_loop(State, Buffer);
|
||||||
Msg ->
|
Msg ->
|
||||||
cowboy:log(warning, "Received stray message ~p.", [Msg], Opts),
|
cowboy:log(warning, "Received stray message ~p.", [Msg], Opts),
|
||||||
loop(State, Buffer)
|
before_loop(State, Buffer)
|
||||||
after InactivityTimeout ->
|
after InactivityTimeout ->
|
||||||
terminate(State, {internal_error, timeout, 'No message or data received before timeout.'})
|
terminate(State, {internal_error, timeout, 'No message or data received before timeout.'})
|
||||||
end.
|
end.
|
||||||
|
@ -331,7 +338,7 @@ tick_idle_timeout(State=#state{idle_timeout_num=?IDLE_TIMEOUT_TICKS}, _) ->
|
||||||
terminate(State, {stop, timeout,
|
terminate(State, {stop, timeout,
|
||||||
'Connection idle longer than configuration allows.'});
|
'Connection idle longer than configuration allows.'});
|
||||||
tick_idle_timeout(State=#state{idle_timeout_num=TimeoutNum}, Buffer) ->
|
tick_idle_timeout(State=#state{idle_timeout_num=TimeoutNum}, Buffer) ->
|
||||||
loop(set_idle_timeout(State, TimeoutNum + 1), Buffer).
|
before_loop(set_idle_timeout(State, TimeoutNum + 1), Buffer).
|
||||||
|
|
||||||
set_idle_timeout(State=#state{http2_status=Status, timer=TimerRef}, _)
|
set_idle_timeout(State=#state{http2_status=Status, timer=TimerRef}, _)
|
||||||
when Status =:= closing_initiated orelse Status =:= closing,
|
when Status =:= closing_initiated orelse Status =:= closing,
|
||||||
|
@ -372,7 +379,7 @@ parse(State=#state{http2_status=sequence}, Data) ->
|
||||||
{ok, Rest} ->
|
{ok, Rest} ->
|
||||||
parse(State#state{http2_status=settings}, Rest);
|
parse(State#state{http2_status=settings}, Rest);
|
||||||
more ->
|
more ->
|
||||||
loop(State, Data);
|
before_loop(State, Data);
|
||||||
Error = {connection_error, _, _} ->
|
Error = {connection_error, _, _} ->
|
||||||
terminate(State, Error)
|
terminate(State, Error)
|
||||||
end;
|
end;
|
||||||
|
@ -391,7 +398,7 @@ parse(State=#state{http2_status=Status, http2_machine=HTTP2Machine, streams=Stre
|
||||||
more when Status =:= closing, Streams =:= #{} ->
|
more when Status =:= closing, Streams =:= #{} ->
|
||||||
terminate(State, {stop, normal, 'The connection is going away.'});
|
terminate(State, {stop, normal, 'The connection is going away.'});
|
||||||
more ->
|
more ->
|
||||||
loop(State, Data)
|
before_loop(State, Data)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
%% Frame rate flood protection.
|
%% Frame rate flood protection.
|
||||||
|
@ -1379,12 +1386,12 @@ terminate_stream_handler(#state{opts=Opts}, StreamID, Reason, StreamState) ->
|
||||||
|
|
||||||
-spec system_continue(_, _, {#state{}, binary()}) -> ok.
|
-spec system_continue(_, _, {#state{}, binary()}) -> ok.
|
||||||
system_continue(_, _, {State, Buffer}) ->
|
system_continue(_, _, {State, Buffer}) ->
|
||||||
loop(State, Buffer).
|
before_loop(State, Buffer).
|
||||||
|
|
||||||
-spec system_terminate(any(), _, _, {#state{}, binary()}) -> no_return().
|
-spec system_terminate(any(), _, _, {#state{}, binary()}) -> no_return().
|
||||||
system_terminate(Reason0, _, _, {State, Buffer}) ->
|
system_terminate(Reason0, _, _, {State, Buffer}) ->
|
||||||
Reason = {stop, {exit, Reason0}, 'sys:terminate/2,3 was called.'},
|
Reason = {stop, {exit, Reason0}, 'sys:terminate/2,3 was called.'},
|
||||||
loop(initiate_closing(State, Reason), Buffer).
|
before_loop(initiate_closing(State, Reason), Buffer).
|
||||||
|
|
||||||
-spec system_code_change(Misc, _, _, _) -> {ok, Misc} when Misc::{#state{}, binary()}.
|
-spec system_code_change(Misc, _, _, _) -> {ok, Misc} when Misc::{#state{}, binary()}.
|
||||||
system_code_change(Misc, _, _, _) ->
|
system_code_change(Misc, _, _, _) ->
|
||||||
|
|
|
@ -51,6 +51,27 @@ do_handshake(Settings, Config) ->
|
||||||
{ok, << 0:24, 4:8, 1:8, 0:32 >>} = gen_tcp:recv(Socket, 9, 1000),
|
{ok, << 0:24, 4:8, 1:8, 0:32 >>} = gen_tcp:recv(Socket, 9, 1000),
|
||||||
{ok, Socket}.
|
{ok, Socket}.
|
||||||
|
|
||||||
|
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, http2}, {port, Port}|Config]),
|
||||||
|
{ok, http2} = 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.
|
||||||
|
|
||||||
idle_timeout(Config) ->
|
idle_timeout(Config) ->
|
||||||
doc("Terminate when the idle timeout is reached."),
|
doc("Terminate when the idle timeout is reached."),
|
||||||
ProtoOpts = #{
|
ProtoOpts = #{
|
||||||
|
|
|
@ -199,6 +199,27 @@ do_chunked_body(ChunkSize0, Data, Acc) ->
|
||||||
do_chunked_body(ChunkSize, Rest,
|
do_chunked_body(ChunkSize, Rest,
|
||||||
[iolist_to_binary(cow_http_te:chunk(Chunk))|Acc]).
|
[iolist_to_binary(cow_http_te:chunk(Chunk))|Acc]).
|
||||||
|
|
||||||
|
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) ->
|
http10_keepalive_false(Config) ->
|
||||||
doc("Confirm the option http10_keepalive => false disables keep-alive "
|
doc("Confirm the option http10_keepalive => false disables keep-alive "
|
||||||
"completely for HTTP/1.0 connections."),
|
"completely for HTTP/1.0 connections."),
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue