diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cowboy_http.erl | 20 | ||||
-rw-r--r-- | src/cowboy_req.erl | 10 | ||||
-rw-r--r-- | src/cowboy_rest.erl | 6 | ||||
-rw-r--r-- | src/cowboy_spdy.erl | 46 |
4 files changed, 72 insertions, 10 deletions
diff --git a/src/cowboy_http.erl b/src/cowboy_http.erl index af60dd9..d2bdf3b 100644 --- a/src/cowboy_http.erl +++ b/src/cowboy_http.erl @@ -162,14 +162,26 @@ cookie_value(<< C, Rest/binary >>, Fun, Acc) -> cookie_value(Rest, Fun, << Acc/binary, C >>). %% @doc Parse a content type. +%% +%% We lowercase the charset header as we know it's case insensitive. -spec content_type(binary()) -> any(). content_type(Data) -> media_type(Data, fun (Rest, Type, SubType) -> - params(Rest, - fun (<<>>, Params) -> {Type, SubType, Params}; - (_Rest2, _) -> {error, badarg} - end) + params(Rest, + fun (<<>>, Params) -> + case lists:keyfind(<<"charset">>, 1, Params) of + false -> + {Type, SubType, Params}; + {_, Charset} -> + Charset2 = cowboy_bstr:to_lower(Charset), + Params2 = lists:keyreplace(<<"charset">>, + 1, Params, {<<"charset">>, Charset2}), + {Type, SubType, Params2} + end; + (_Rest2, _) -> + {error, badarg} + end) end). %% @doc Parse a media range. diff --git a/src/cowboy_req.erl b/src/cowboy_req.erl index 093663c..0e1c8a7 100644 --- a/src/cowboy_req.erl +++ b/src/cowboy_req.erl @@ -492,7 +492,10 @@ cookie(Name, Req=#http_req{cookies=undefined}, Default) when is_binary(Name) -> {ok, undefined, Req2} -> {Default, Req2#http_req{cookies=[]}}; {ok, Cookies, Req2} -> - cookie(Name, Req2#http_req{cookies=Cookies}, Default) + cookie(Name, Req2#http_req{cookies=Cookies}, Default); + %% Flash player incorrectly sends an empty Cookie header. + {error, badarg} -> + {Default, Req#http_req{cookies=[]}} end; cookie(Name, Req, Default) -> case lists:keyfind(Name, 1, Req#http_req.cookies) of @@ -507,7 +510,10 @@ cookies(Req=#http_req{cookies=undefined}) -> {ok, undefined, Req2} -> {[], Req2#http_req{cookies=[]}}; {ok, Cookies, Req2} -> - cookies(Req2#http_req{cookies=Cookies}) + cookies(Req2#http_req{cookies=Cookies}); + %% Flash player incorrectly sends an empty Cookie header. + {error, badarg} -> + {[], Req#http_req{cookies=[]}} end; cookies(Req=#http_req{cookies=Cookies}) -> {Cookies, Req}. diff --git a/src/cowboy_rest.erl b/src/cowboy_rest.erl index b87c7df..ecbe7bc 100644 --- a/src/cowboy_rest.erl +++ b/src/cowboy_rest.erl @@ -145,6 +145,9 @@ allowed_methods(Req, State=#state{method=Method}) -> end end. +method_not_allowed(Req, State, []) -> + Req2 = cowboy_req:set_resp_header(<<"allow">>, <<>>, Req), + respond(Req2, State, 405); method_not_allowed(Req, State, Methods) -> << ", ", Allow/binary >> = << << ", ", M/binary >> || M <- Methods >>, Req2 = cowboy_req:set_resp_header(<<"allow">>, Allow, Req), @@ -186,6 +189,9 @@ valid_entity_length(Req, State) -> %% you should do it directly in the options/2 call using set_resp_headers. options(Req, State=#state{allowed_methods=Methods, method= <<"OPTIONS">>}) -> case call(Req, State, options) of + no_call when Methods =:= [] -> + Req2 = cowboy_req:set_resp_header(<<"allow">>, <<>>, Req), + respond(Req2, State, 200); no_call -> << ", ", Allow/binary >> = << << ", ", M/binary >> || M <- Methods >>, diff --git a/src/cowboy_spdy.erl b/src/cowboy_spdy.erl index 3fe477b..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 @@ -435,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, @@ -540,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}. |