From d7b7580b3913c17b404319cc4c153748d5e59194 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Fri, 9 Nov 2018 17:42:37 +0100 Subject: 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. --- src/cowboy_req.erl | 22 ++++++++++++++++++---- 1 file changed, 18 insertions(+), 4 deletions(-) (limited to 'src/cowboy_req.erl') 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. -- cgit v1.2.3