aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2013-06-03 19:10:03 +0200
committerLoïc Hoguin <[email protected]>2013-06-03 19:10:03 +0200
commit1fc69977da8f57d5d3fa48cd68280aa2c0b1d78b (patch)
tree4498bedb4f940a83a8f9b04dfb539efcc1115f43
parente50f7e40862e42feee227acbd3135657d2ea8ee2 (diff)
downloadcowboy-1fc69977da8f57d5d3fa48cd68280aa2c0b1d78b.tar.gz
cowboy-1fc69977da8f57d5d3fa48cd68280aa2c0b1d78b.tar.bz2
cowboy-1fc69977da8f57d5d3fa48cd68280aa2c0b1d78b.zip
Add sendfile support to SPDY, enabling cowboy_static use
-rw-r--r--src/cowboy_spdy.erl38
-rw-r--r--test/spdy_SUITE.erl14
2 files changed, 48 insertions, 4 deletions
diff --git a/src/cowboy_spdy.erl b/src/cowboy_spdy.erl
index ba02706..d605331 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, _} ->
@@ -430,6 +439,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 +565,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}.
diff --git a/test/spdy_SUITE.erl b/test/spdy_SUITE.erl
index df29281..1089991 100644
--- a/test/spdy_SUITE.erl
+++ b/test/spdy_SUITE.erl
@@ -44,9 +44,13 @@ init_per_suite(Config) ->
application:start(cowboy),
application:start(public_key),
application:start(ssl),
- Config.
+ Dir = ?config(priv_dir, Config) ++ "/static",
+ ct_helper:create_static_dir(Dir),
+ [{static_dir, Dir}|Config].
-end_per_suite(_Config) ->
+end_per_suite(Config) ->
+ Dir = ?config(static_dir, Config),
+ ct_helper:delete_static_dir(Dir),
application:stop(ssl),
application:stop(public_key),
application:stop(cowboy),
@@ -69,9 +73,12 @@ end_per_group(Name, _) ->
%% Dispatch configuration.
-init_dispatch(_) ->
+init_dispatch(Config) ->
cowboy_router:compile([
{"localhost", [
+ {"/static/[...]", cowboy_static,
+ [{directory, ?config(static_dir, Config)},
+ {mimetypes, [{<<".css">>, [<<"text/css">>]}]}]},
{"/chunked", http_chunked, []},
{"/", http_handler, []}
]}
@@ -152,6 +159,7 @@ check_status(Config) ->
Tests = [
{200, nofin, "localhost", "/"},
{200, nofin, "localhost", "/chunked"},
+ {200, nofin, "localhost", "/static/style.css"},
{400, fin, "bad-host", "/"},
{400, fin, "localhost", "bad-path"},
{404, fin, "localhost", "/this/path/does/not/exist"}