0
Fork 0
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:
James Fish 2013-11-18 20:32:47 +00:00
parent 5a25c7f7f2
commit 1c474af8ee
3 changed files with 82 additions and 2 deletions

View file

@ -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.