aboutsummaryrefslogtreecommitdiffstats
path: root/src/cowboy_req.erl
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2018-11-09 17:42:37 +0100
committerLoïc Hoguin <[email protected]>2018-11-09 17:42:37 +0100
commitd7b7580b3913c17b404319cc4c153748d5e59194 (patch)
tree3026f38e4bcfdcb26d067a4e5aec6d401700c3cc /src/cowboy_req.erl
parent29043aa7b4d11e377bc76d453f592ea5a6df1f43 (diff)
downloadcowboy-d7b7580b3913c17b404319cc4c153748d5e59194.tar.gz
cowboy-d7b7580b3913c17b404319cc4c153748d5e59194.tar.bz2
cowboy-d7b7580b3913c17b404319cc4c153748d5e59194.zip
Add sendfile support to cowboy_req:stream_body
It is now possible to stream one or more sendfile tuples. A simple example of what can now be done would be for example to build a tar file on the fly using the sendfile syscall for sending the files, or to support Range requests with more than one range with the sendfile syscall. When using cowboy_compress_h unfortunately we have to read the file in order to send it. More options will be added at a later time to make sure users don't read too much into memory. This is a new feature however so existing code is not affected. Also rework cowboy_http's data sending to be flatter.
Diffstat (limited to 'src/cowboy_req.erl')
-rw-r--r--src/cowboy_req.erl22
1 files changed, 18 insertions, 4 deletions
diff --git a/src/cowboy_req.erl b/src/cowboy_req.erl
index 46bc62a..2c3de06 100644
--- a/src/cowboy_req.erl
+++ b/src/cowboy_req.erl
@@ -808,21 +808,35 @@ stream_reply(Status, Headers=#{}, Req=#{pid := Pid, streamid := StreamID})
Pid ! {{Pid, StreamID}, {headers, Status, response_headers(Headers, Req)}},
done_replying(Req, headers).
--spec stream_body(iodata(), fin | nofin, req()) -> ok.
+-spec stream_body(resp_body(), fin | nofin, req()) -> ok.
%% Error out if headers were not sent.
%% Don't send any body for HEAD responses.
stream_body(_, _, #{method := <<"HEAD">>, has_sent_resp := headers}) ->
ok;
%% Don't send a message if the data is empty, except for the
-%% very last message with IsFin=fin.
-stream_body(Data, IsFin=nofin, #{pid := Pid, streamid := StreamID, has_sent_resp := headers}) ->
+%% very last message with IsFin=fin. When using sendfile this
+%% is converted to a data tuple, however.
+stream_body({sendfile, _, 0, _}, nofin, _) ->
+ ok;
+stream_body({sendfile, _, 0, _}, IsFin=fin,
+ #{pid := Pid, streamid := StreamID, has_sent_resp := headers}) ->
+ Pid ! {{Pid, StreamID}, {data, IsFin, <<>>}},
+ ok;
+stream_body({sendfile, O, B, P}, IsFin,
+ #{pid := Pid, streamid := StreamID, has_sent_resp := headers})
+ when is_integer(O), O >= 0, is_integer(B), B > 0 ->
+ Pid ! {{Pid, StreamID}, {data, IsFin, {sendfile, O, B, P}}},
+ ok;
+stream_body(Data, IsFin=nofin, #{pid := Pid, streamid := StreamID, has_sent_resp := headers})
+ when not is_tuple(Data) ->
case iolist_size(Data) of
0 -> ok;
_ ->
Pid ! {{Pid, StreamID}, {data, IsFin, Data}},
ok
end;
-stream_body(Data, IsFin, #{pid := Pid, streamid := StreamID, has_sent_resp := headers}) ->
+stream_body(Data, IsFin, #{pid := Pid, streamid := StreamID, has_sent_resp := headers})
+ when not is_tuple(Data) ->
Pid ! {{Pid, StreamID}, {data, IsFin, Data}},
ok.