Skip to content

Commit

Permalink
Check a return value of Transport:send/2 in cowboy_http
Browse files Browse the repository at this point in the history
  • Loading branch information
Yozhig committed Dec 6, 2023
1 parent e612cbb commit f07e8ec
Showing 1 changed file with 23 additions and 10 deletions.
33 changes: 23 additions & 10 deletions src/cowboy_http.erl
Original file line number Diff line number Diff line change
Expand Up @@ -254,7 +254,12 @@ loop(State=#state{parent=Parent, socket=Socket, transport=Transport, opts=Opts,
sys:handle_system_msg(Request, From, Parent, ?MODULE, [], State);
%% Messages pertaining to a stream.
{{Pid, StreamID}, Msg} when Pid =:= self() ->
loop(info(State, StreamID, Msg));
try info(State, StreamID, Msg) of
NewState ->
loop(NewState)
catch throw:{send, Error} ->
terminate(State, Error)
end;
%% Exit signal from children.
Msg = {'EXIT', Pid, _} ->
loop(down(State, Pid, Msg));
Expand Down Expand Up @@ -1037,10 +1042,10 @@ commands(State0=#state{socket=Socket, transport=Transport, out_state=wait, strea
%% @todo 204 and 304 responses must not include a response body. (RFC7230 3.3.1, RFC7230 3.3.2)
case Body of
{sendfile, _, _, _} ->
Transport:send(Socket, Response),
send(Transport, Socket, Response),
sendfile(State, Body);
_ ->
Transport:send(Socket, [Response, Body])
send(Transport, Socket, [Response, Body])
end,
commands(State, StreamID, Tail);
%% Send response headers and initiate chunked encoding or streaming.
Expand Down Expand Up @@ -1098,21 +1103,21 @@ commands(State0=#state{socket=Socket, transport=Transport, streams=Streams0, out
Stream0=#stream{method= <<"HEAD">>} ->
Stream0;
Stream0 when Size =:= 0, IsFin =:= fin, OutState =:= chunked ->
Transport:send(Socket, <<"0\r\n\r\n">>),
send(Transport, Socket, <<"0\r\n\r\n">>),
Stream0;
Stream0 when Size =:= 0 ->
Stream0;
Stream0 when is_tuple(Data), OutState =:= chunked ->
Transport:send(Socket, [integer_to_binary(Size, 16), <<"\r\n">>]),
send(Transport, Socket, [integer_to_binary(Size, 16), <<"\r\n">>]),
sendfile(State0, Data),
Transport:send(Socket,
send(Transport, Socket,
case IsFin of
fin -> <<"\r\n0\r\n\r\n">>;
nofin -> <<"\r\n">>
end),
Stream0;
Stream0 when OutState =:= chunked ->
Transport:send(Socket, [
send(Transport, Socket, [
integer_to_binary(Size, 16), <<"\r\n">>, Data,
case IsFin of
fin -> <<"\r\n0\r\n\r\n">>;
Expand All @@ -1130,7 +1135,7 @@ commands(State0=#state{socket=Socket, transport=Transport, streams=Streams0, out
is_tuple(Data) ->
sendfile(State0, Data);
true ->
Transport:send(Socket, Data)
send(Transport, Socket, Data)
end,
Stream0#stream{local_sent_size=SentSize}
end,
Expand All @@ -1144,13 +1149,13 @@ commands(State=#state{socket=Socket, transport=Transport, streams=Streams, out_s
StreamID, [{trailers, Trailers}|Tail]) ->
case stream_te(OutState, lists:keyfind(StreamID, #stream.id, Streams)) of
trailers ->
Transport:send(Socket, [
send(Transport, Socket, [
<<"0\r\n">>,
cow_http:headers(maps:to_list(Trailers)),
<<"\r\n">>
]);
no_trailers ->
Transport:send(Socket, <<"0\r\n\r\n">>);
send(Transport, Socket, <<"0\r\n\r\n">>);
not_chunked ->
ok
end,
Expand Down Expand Up @@ -1222,6 +1227,14 @@ headers_to_list(Headers0=#{<<"set-cookie">> := SetCookies}) ->
headers_to_list(Headers) ->
maps:to_list(Headers).

send(Transport, Socket, Data) ->
case Transport:send(Socket, Data) of
ok ->
ok;
{error, _Reason} = Error -> % handle 'timeout' as unrecoverable error too
erlang:throw({send, Error})
end.

%% We wrap the sendfile call into a try/catch because on OTP-20
%% and earlier a few different crashes could occur for sockets
%% that were closing or closed. For example a badarg in
Expand Down

0 comments on commit f07e8ec

Please sign in to comment.