Skip to content

Instantly share code, notes, and snippets.

@asabil
Created January 24, 2014 15:01
Show Gist options
  • Save asabil/8598892 to your computer and use it in GitHub Desktop.
Save asabil/8598892 to your computer and use it in GitHub Desktop.
Add lingering close to cowboy
diff --git a/Makefile b/Makefile
index 6d98abb..b003965 100644
--- a/Makefile
+++ b/Makefile
@@ -12,7 +12,7 @@ PLT_APPS = crypto public_key ssl
DEPS = cowlib ranch
dep_cowlib = pkg://cowlib 0.4.0
-dep_ranch = pkg://ranch 0.9.0
+dep_ranch = pkg://ranch 723f1b1883e7834784eab772d74d9ede299f145b
TEST_DEPS = ct_helper gun
dep_ct_helper = https://github.com/extend/ct_helper.git master
diff --git a/src/cowboy_protocol.erl b/src/cowboy_protocol.erl
index fdc1126..d4015c0 100644
--- a/src/cowboy_protocol.erl
+++ b/src/cowboy_protocol.erl
@@ -166,8 +166,8 @@ wait_request(Buffer, State=#state{socket=Socket, transport=Transport,
case recv(Socket, Transport, Until) of
{ok, Data} ->
parse_request(<< Buffer/binary, Data/binary >>, State, ReqEmpty);
- {error, _} ->
- terminate(State)
+ {error, Reason} ->
+ terminate(Reason, State)
end.
%% @private
@@ -268,8 +268,8 @@ wait_header(Buffer, State=#state{socket=Socket, transport=Transport,
State, M, P, Q, V, H);
{error, timeout} ->
error_terminate(408, State);
- {error, _} ->
- terminate(State)
+ {error, Reason} ->
+ terminate(Reason, State)
end.
parse_header(<< $\r, $\n, Rest/bits >>, S, M, P, Q, V, Headers) ->
@@ -348,8 +348,8 @@ wait_hd_before_value(Buffer, State=#state{
State, M, P, Q, V, H, N);
{error, timeout} ->
error_terminate(408, State);
- {error, _} ->
- terminate(State)
+ {error, Reason} ->
+ terminate(Reason, State)
end.
parse_hd_before_value(<< $\s, Rest/bits >>, S, M, P, Q, V, H, N) ->
@@ -379,8 +379,8 @@ wait_hd_value(_, State=#state{
parse_hd_value(Data, State, M, P, Q, V, H, N, SoFar);
{error, timeout} ->
error_terminate(408, State);
- {error, _} ->
- terminate(State)
+ {error, Reason} ->
+ terminate(Reason, State)
end.
%% Pushing back as much as we could the retrieval of new data
@@ -396,8 +396,8 @@ wait_hd_value_nl(_, State=#state{
parse_header(Data, State, M, P, Q, V, [{Name, SoFar}|Headers]);
{error, timeout} ->
error_terminate(408, State);
- {error, _} ->
- terminate(State)
+ {error, Reason} ->
+ terminate(Reason, State)
end.
parse_hd_value(<< $\r, Rest/bits >>, S, M, P, Q, V, Headers, Name, SoFar) ->
@@ -498,9 +498,9 @@ request(Buffer, State=#state{socket=Socket, transport=Transport,
Query, Version, Headers, Host, Port, Buffer,
ReqKeepalive < MaxKeepalive, Compress, OnResponse),
onrequest(Req, State);
- {error, _} ->
+ {error, Reason} ->
%% Couldn't read the peer address; connection is gone.
- terminate(State)
+ terminate(Reason, State)
end.
%% Call the global onrequest callback. The callback can send a reply,
@@ -562,7 +562,7 @@ next_request(Req, State=#state{req_keepalive=Keepalive, timeout=Timeout},
%% we do not want to attempt to skip the body.
case cowboy_req:get(connection, Req) of
close ->
- terminate(State);
+ terminate(normal, State);
_ ->
Buffer = case cowboy_req:skip_body(Req) of
{ok, Req2} -> cowboy_req:get(buffer, Req2);
@@ -575,7 +575,7 @@ next_request(Req, State=#state{req_keepalive=Keepalive, timeout=Timeout},
State#state{req_keepalive=Keepalive + 1,
until=until(Timeout)}, 0);
true ->
- terminate(State)
+ terminate(normal, State)
end
end.
@@ -589,9 +589,31 @@ error_terminate(Status, State=#state{socket=Socket, transport=Transport,
-spec error_terminate(cowboy:http_status(), cowboy_req:req(), #state{}) -> ok.
error_terminate(Status, Req, State) ->
cowboy_req:maybe_reply(Status, Req),
- terminate(State).
+ terminate(case Status of
+ 408 -> timeout;
+ _ -> normal
+ end, State).
--spec terminate(#state{}) -> ok.
-terminate(#state{socket=Socket, transport=Transport}) ->
+-spec terminate(term(), #state{}) -> ok.
+terminate(Reason, #state{socket=Socket, transport=Transport}) when
+ Reason =:= closed; Reason =:= timeout ->
Transport:close(Socket),
- ok.
+ ok;
+terminate(_Reason, #state{socket=Socket, transport=Transport}) ->
+ Transport:shutdown(Socket, write),
+ lingering_close(Transport, Socket, until(30000)).
+
+lingering_close(Transport, Socket, Until) ->
+ {Me, S, Mi} = os:timestamp(),
+ Now = Me * 1000000000 + S * 1000 + Mi div 1000,
+ if Until - Now < 0 ->
+ Transport:close(Socket),
+ ok;
+ true ->
+ case Transport:recv(Socket, 0, 5000) of
+ {ok, _} ->
+ lingering_close(Transport, Socket, Until);
+ _ ->
+ ok
+ end
+ end.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment