aboutsummaryrefslogtreecommitdiffstats
path: root/src/cowboy_handler.erl
diff options
context:
space:
mode:
authorJames Fish <[email protected]>2013-11-18 20:32:47 +0000
committerJames Fish <[email protected]>2013-11-18 23:19:37 +0000
commit1c474af8ee4c61c9cbbf6ef4e121d1d82af75151 (patch)
treef13c6bf6ccefe64d8f913a8c566a560edbf7a21d /src/cowboy_handler.erl
parent5a25c7f7f2167b8cef03129553e56f422a9890f2 (diff)
downloadcowboy-1c474af8ee4c61c9cbbf6ef4e121d1d82af75151.tar.gz
cowboy-1c474af8ee4c61c9cbbf6ef4e121d1d82af75151.tar.bz2
cowboy-1c474af8ee4c61c9cbbf6ef4e121d1d82af75151.zip
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.
Diffstat (limited to 'src/cowboy_handler.erl')
-rw-r--r--src/cowboy_handler.erl19
1 files changed, 17 insertions, 2 deletions
diff --git a/src/cowboy_handler.erl b/src/cowboy_handler.erl
index fcbfe55..e431ba8 100644
--- a/src/cowboy_handler.erl
+++ b/src/cowboy_handler.erl
@@ -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.