aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/cowboy_spdy.erl51
1 files changed, 47 insertions, 4 deletions
diff --git a/src/cowboy_spdy.erl b/src/cowboy_spdy.erl
index ba02706..182e6da 100644
--- a/src/cowboy_spdy.erl
+++ b/src/cowboy_spdy.erl
@@ -42,6 +42,7 @@
%% Internal transport functions.
-export([name/0]).
-export([send/2]).
+-export([sendfile/2]).
-record(child, {
streamid :: non_neg_integer(),
@@ -174,6 +175,14 @@ loop(State=#state{parent=Parent, socket=Socket, transport=Transport,
Children2 = lists:keyreplace(StreamID,
#child.streamid, Children, Child#child{output=fin}),
loop(State#state{children=Children2});
+ {sendfile, {Pid, StreamID}, Filepath}
+ when Pid =:= self() ->
+ Child = #child{output=nofin} = lists:keyfind(StreamID,
+ #child.streamid, Children),
+ data_from_file(State, StreamID, Filepath),
+ Children2 = lists:keyreplace(StreamID,
+ #child.streamid, Children, Child#child{output=fin}),
+ loop(State#state{children=Children2});
{'EXIT', Parent, Reason} ->
exit(Reason);
{'EXIT', Pid, _} ->
@@ -212,12 +221,14 @@ system_code_change(Misc, _, _, _) ->
{ok, Misc}.
%% We do not support SYN_STREAM with FLAG_UNIDIRECTIONAL set.
-control_frame(State, << _:38, 1:1, _:26, StreamID:31, _/bits >>) ->
+control_frame(State, << 1:1, 3:15, 1:16, _:6, 1:1, _:26,
+ StreamID:31, _/bits >>) ->
rst_stream(State, StreamID, internal_error),
loop(State);
%% We do not support Associated-To-Stream-ID and CREDENTIAL Slot.
-control_frame(State, << _:65, StreamID:31, _:1, AssocToStreamID:31,
- _:8, Slot:8, _/bits >>) when AssocToStreamID =/= 0; Slot =/= 0 ->
+control_frame(State, << 1:1, 3:15, 1:16, _:33, StreamID:31, _:1,
+ AssocToStreamID:31, _:8, Slot:8, _/bits >>)
+ when AssocToStreamID =/= 0; Slot =/= 0 ->
rst_stream(State, StreamID, internal_error),
loop(State);
%% SYN_STREAM
@@ -247,6 +258,9 @@ control_frame(State=#state{middlewares=Middlewares, env=Env,
loop(State#state{last_streamid=StreamID,
children=[#child{streamid=StreamID, pid=Pid,
input=IsFin, output=nofin}|Children]});
+ {error, badname} ->
+ rst_stream(State, StreamID, protocol_error),
+ loop(State#state{last_streamid=StreamID});
{error, special} ->
rst_stream(State, StreamID, protocol_error),
loop(State#state{last_streamid=StreamID})
@@ -344,6 +358,8 @@ syn_stream_headers(<<>>, 0, Acc, Special=#special_headers{
true ->
{ok, lists:reverse(Acc), Special}
end;
+syn_stream_headers(<< 0:32, _Rest/bits >>, _NbHeaders, _Acc, _Special) ->
+ {error, badname};
syn_stream_headers(<< NameLen:32, Rest/bits >>, NbHeaders, Acc, Special) ->
<< Name:NameLen/binary, ValueLen:32, Rest2/bits >> = Rest,
<< Value:ValueLen/binary, Rest3/bits >> = Rest2,
@@ -430,6 +446,27 @@ data(#state{socket=Socket, transport=Transport}, IsFin, StreamID, Data) ->
<< 0:1, StreamID:31, Flags:8, Len:24 >>,
Data]).
+data_from_file(#state{socket=Socket, transport=Transport},
+ StreamID, Filepath) ->
+ {ok, IoDevice} = file:open(Filepath, [read, binary, raw]),
+ data_from_file(Socket, Transport, StreamID, IoDevice).
+
+data_from_file(Socket, Transport, StreamID, IoDevice) ->
+ case file:read(IoDevice, 16#1fff) of
+ eof ->
+ _ = Transport:send(Socket, << 0:1, StreamID:31, 1:8, 0:24 >>),
+ ok;
+ {ok, Data} ->
+ Len = byte_size(Data),
+ Data2 = [<< 0:1, StreamID:31, 0:8, Len:24 >>, Data],
+ case Transport:send(Socket, Data2) of
+ ok ->
+ data_from_file(Socket, Transport, StreamID, IoDevice);
+ {error, _} ->
+ ok
+ end
+ end.
+
%% Request process.
request_init(Parent, StreamID, Peer,
@@ -535,10 +572,16 @@ stream_close(Socket = {Pid, _}) ->
ok.
%% Internal transport functions.
-%% @todo recv, sendfile
+%% @todo recv
name() ->
spdy.
send(Socket, Data) ->
stream_data(Socket, Data).
+
+%% We don't wait for the result of the actual sendfile call,
+%% therefore we can't know how much was actually sent.
+sendfile(Socket = {Pid, _}, Filepath) ->
+ _ = Pid ! {sendfile, Socket, Filepath},
+ {ok, undefined}.