From 1fc69977da8f57d5d3fa48cd68280aa2c0b1d78b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lo=C3=AFc=20Hoguin?= Date: Mon, 3 Jun 2013 19:10:03 +0200 Subject: Add sendfile support to SPDY, enabling cowboy_static use --- src/cowboy_spdy.erl | 38 +++++++++++++++++++++++++++++++++++++- test/spdy_SUITE.erl | 14 +++++++++++--- 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"} -- cgit v1.2.3