aboutsummaryrefslogtreecommitdiffstats
path: root/src/cowboy_http.erl
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2017-11-15 14:58:49 +0100
committerLoïc Hoguin <[email protected]>2017-11-15 14:58:49 +0100
commit39baed6c800fa9e756f7491063ead399a23083f4 (patch)
tree7c54a8b83b5957438e76c3a56996af4e4ca02c18 /src/cowboy_http.erl
parenta1ad482eb442ea2bd54866656b7a7dc453e4bd8e (diff)
downloadcowboy-39baed6c800fa9e756f7491063ead399a23083f4.tar.gz
cowboy-39baed6c800fa9e756f7491063ead399a23083f4.tar.bz2
cowboy-39baed6c800fa9e756f7491063ead399a23083f4.zip
Add preliminary support for trailers in responses
This depends on changes in Cowlib that are only available on master.
Diffstat (limited to 'src/cowboy_http.erl')
-rw-r--r--src/cowboy_http.erl37
1 files changed, 36 insertions, 1 deletions
diff --git a/src/cowboy_http.erl b/src/cowboy_http.erl
index e287edc..62454ac 100644
--- a/src/cowboy_http.erl
+++ b/src/cowboy_http.erl
@@ -69,6 +69,8 @@
state = undefined :: {module(), any()},
%% Client HTTP version for this stream.
version = undefined :: cowboy:http_version(),
+ %% Unparsed te header. Used to know if we can send trailers.
+ te :: undefined | binary(),
%% Commands queued.
queue = [] :: cowboy_stream:commands()
}).
@@ -267,7 +269,9 @@ after_parse({request, Req=#{streamid := StreamID, headers := Headers, version :=
State0=#state{opts=Opts, streams=Streams0}, Buffer}) ->
try cowboy_stream:init(StreamID, Req, Opts) of
{Commands, StreamState} ->
- Streams = [#stream{id=StreamID, state=StreamState, version=Version}|Streams0],
+ TE = maps:get(<<"te">>, Headers, undefined),
+ Streams = [#stream{id=StreamID, state=StreamState,
+ version=Version, te=TE}|Streams0],
State1 = case maybe_req_close(State0, Headers, Version) of
close -> State0#state{streams=Streams, last_streamid=StreamID};
keepalive -> State0#state{streams=Streams}
@@ -900,6 +904,37 @@ commands(State0=#state{socket=Socket, transport=Transport, streams=Streams}, Str
nofin -> State0
end,
commands(State, StreamID, Tail);
+%% Send trailers.
+commands(State=#state{socket=Socket, transport=Transport, streams=Streams}, StreamID,
+ [{trailers, Trailers}|Tail]) ->
+ TE = case lists:keyfind(StreamID, #stream.id, Streams) of
+ %% HTTP/1.0 doesn't support chunked transfer-encoding.
+ #stream{version='HTTP/1.0'} ->
+ not_chunked;
+ %% No TE header was sent.
+ #stream{te=undefined} ->
+ no_trailers;
+ #stream{te=TE0} ->
+ try cow_http_hd:parse_te(TE0) of
+ {TE1, _} -> TE1
+ catch _:_ ->
+ %% If we can't parse the TE header, assume we can't send trailers.
+ no_trailers
+ end
+ end,
+ case TE of
+ trailers ->
+ Transport:send(Socket, [
+ <<"0\r\n">>,
+ cow_http:headers(maps:to_list(Trailers)),
+ <<"\r\n">>
+ ]);
+ no_trailers ->
+ Transport:send(Socket, <<"0\r\n\r\n">>);
+ not_chunked ->
+ ok
+ end,
+ commands(State#state{out_state=done}, StreamID, Tail);
%% Send a file.
commands(State0=#state{socket=Socket, transport=Transport}, StreamID,
[{sendfile, IsFin, Offset, Bytes, Path}|Tail]) ->