mirror of
https://github.com/ninenines/cowboy.git
synced 2025-07-16 05:00:24 +00:00
Fix loop handler keepalive race condition
Previously if a loop handler received the timeout message from a previous request on the same connection the socket would be set to {active, once} incorrectly - when a socket packet was already in the message queue. This second packet would not be added to the buffer before a Handler:info/3 call if a user message was in the message queue before both socket packets.
This commit is contained in:
parent
5a25c7f7f2
commit
1c474af8ee
3 changed files with 82 additions and 2 deletions
|
@ -211,7 +211,7 @@ handler_loop(Req, State=#state{loop_buffer_size=NbBytes,
|
|||
handler_after_loop(Req, State, Handler, HandlerState,
|
||||
{normal, timeout});
|
||||
{timeout, OlderTRef, ?MODULE} when is_reference(OlderTRef) ->
|
||||
handler_before_loop(Req, State, Handler, HandlerState);
|
||||
handler_loop(Req, State, Handler, HandlerState);
|
||||
Message ->
|
||||
%% We set the socket back to {active, false} mode in case
|
||||
%% the handler is going to call recv. We also flush any
|
||||
|
@ -280,8 +280,14 @@ handler_after_loop(Req, State, Handler, HandlerState, Reason) ->
|
|||
-spec terminate_request(Req, #state{}, module(), any(),
|
||||
{normal, timeout | shutdown} | {error, atom()}) ->
|
||||
{ok, Req, cowboy_middleware:env()} when Req::cowboy_req:req().
|
||||
terminate_request(Req, #state{env=Env}, Handler, HandlerState, Reason) ->
|
||||
terminate_request(Req, #state{env=Env, loop_timeout_ref=TRef},
|
||||
Handler, HandlerState, Reason) ->
|
||||
HandlerRes = handler_terminate(Req, Handler, HandlerState, Reason),
|
||||
_ = case TRef of
|
||||
undefined -> ignore;
|
||||
TRef -> erlang:cancel_timer(TRef)
|
||||
end,
|
||||
flush_timeouts(),
|
||||
{ok, Req, [{result, HandlerRes}|Env]}.
|
||||
|
||||
-spec handler_terminate(cowboy_req:req(), module(), any(),
|
||||
|
@ -299,3 +305,12 @@ handler_terminate(Req, Handler, HandlerState, Reason) ->
|
|||
{terminate_reason, Reason}
|
||||
])
|
||||
end.
|
||||
|
||||
-spec flush_timeouts() -> ok.
|
||||
flush_timeouts() ->
|
||||
receive
|
||||
{timeout, TRef, ?MODULE} when is_reference(TRef) ->
|
||||
flush_timeouts()
|
||||
after 0 ->
|
||||
ok
|
||||
end.
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue