0
Fork 0
mirror of https://github.com/ninenines/cowboy.git synced 2025-07-14 12:20:24 +00:00

Improve consistency of return types for cowboy_req API

The signature of parse_header, body_qs, multipart_data and
the set_resp_* functions has changed.

See the cowboy_req module edoc for more details.
This commit is contained in:
Loïc Hoguin 2012-09-16 03:51:07 +02:00
parent e13ab806ea
commit 8d5f8db90a
9 changed files with 116 additions and 103 deletions

View file

@ -17,7 +17,7 @@ handle(Req, State) ->
{ok, Req4, State}. {ok, Req4, State}.
maybe_echo('POST', true, Req) -> maybe_echo('POST', true, Req) ->
{PostVals, Req2} = cowboy_req:body_qs(Req), {ok, PostVals, Req2} = cowboy_req:body_qs(Req),
Echo = proplists:get_value(<<"echo">>, PostVals), Echo = proplists:get_value(<<"echo">>, PostVals),
echo(Echo, Req2); echo(Echo, Req2);
maybe_echo('POST', false, Req) -> maybe_echo('POST', false, Req) ->

View file

@ -212,7 +212,7 @@ header({http_header, _I, 'Connection', _R, Connection},
req_keepalive=Keepalive, max_keepalive=MaxKeepalive}) req_keepalive=Keepalive, max_keepalive=MaxKeepalive})
when Keepalive < MaxKeepalive -> when Keepalive < MaxKeepalive ->
Req2 = Req#http_req{headers=[{'Connection', Connection}|Headers]}, Req2 = Req#http_req{headers=[{'Connection', Connection}|Headers]},
{ConnTokens, Req3} {ok, ConnTokens, Req3}
= cowboy_req:parse_header('Connection', Req2), = cowboy_req:parse_header('Connection', Req2),
ConnAtom = cowboy_http:connection_to_atom(ConnTokens), ConnAtom = cowboy_http:connection_to_atom(ConnTokens),
parse_header(Req3#http_req{connection=ConnAtom}, State); parse_header(Req3#http_req{connection=ConnAtom}, State);

View file

@ -15,10 +15,30 @@
%% @doc HTTP request manipulation API. %% @doc HTTP request manipulation API.
%% %%
%% Almost all functions in this module return a new <em>Req</em> variable. %% The functions in this module try to follow this pattern for their
%% It should always be used instead of the one used in your function call %% return types:
%% because it keeps the state of the request. It also allows Cowboy to do %% <dl>
%% some lazy evaluation and cache results where possible. %% <dt>access:</dt>
%% <dd><em>{Value, Req}</em></dd>
%% <dt>action:</dt>
%% <dd><em>{Result, Req} | {Result, Value, Req} | {error, atom()}</em></dd>
%% <dt>modification:</dt>
%% <dd><em>Req</em></dd>
%% <dt>question (<em>has_*</em> or <em>is_*</em>):</dt>
%% <dd><em>boolean()</em></dd>
%% </dl>
%%
%% Exceptions include <em>chunk/2</em> which always returns <em>'ok'</em>,
%% <em>to_list/1</em> which returns a list of key/values,
%% and <em>transport/1</em> which returns <em>{ok, Transport, Socket}</em>.
%%
%% Also note that all body reading functions perform actions, as Cowboy
%% doesn't read the request body until they are called.
%%
%% Whenever <em>Req</em> is returned, it should always be kept in place of
%% the one given as argument in your function call, because it keeps
%% track of the request and response state. Doing so allows Cowboy to do
%% some lazy evaluation and cache results when possible.
-module(cowboy_req). -module(cowboy_req).
%% Request API. %% Request API.
@ -277,12 +297,12 @@ headers(Req) ->
%% returned is used as a return value. %% returned is used as a return value.
%% @see parse_header/3 %% @see parse_header/3
-spec parse_header(cowboy_http:header(), Req) -spec parse_header(cowboy_http:header(), Req)
-> {any(), Req} | {undefined, binary(), Req} -> {ok, any(), Req} | {undefined, binary(), Req}
| {error, badarg} when Req::req(). | {error, badarg} when Req::req().
parse_header(Name, Req=#http_req{p_headers=PHeaders}) -> parse_header(Name, Req=#http_req{p_headers=PHeaders}) ->
case lists:keyfind(Name, 1, PHeaders) of case lists:keyfind(Name, 1, PHeaders) of
false -> parse_header(Name, Req, parse_header_default(Name)); false -> parse_header(Name, Req, parse_header_default(Name));
{Name, Value} -> {Value, Req} {Name, Value} -> {ok, Value, Req}
end. end.
%% @doc Default values for semantic header parsing. %% @doc Default values for semantic header parsing.
@ -295,7 +315,7 @@ parse_header_default(_Name) -> undefined.
%% %%
%% When the header is unknown, the value is returned directly without parsing. %% When the header is unknown, the value is returned directly without parsing.
-spec parse_header(cowboy_http:header(), Req, any()) -spec parse_header(cowboy_http:header(), Req, any())
-> {any(), Req} | {undefined, binary(), Req} -> {ok, any(), Req} | {undefined, binary(), Req}
| {error, badarg} when Req::req(). | {error, badarg} when Req::req().
parse_header(Name, Req, Default) when Name =:= 'Accept' -> parse_header(Name, Req, Default) when Name =:= 'Accept' ->
parse_header(Name, Req, Default, parse_header(Name, Req, Default,
@ -365,23 +385,15 @@ parse_header(Name, Req, Default) ->
{undefined, Value, Req2}. {undefined, Value, Req2}.
parse_header(Name, Req=#http_req{p_headers=PHeaders}, Default, Fun) -> parse_header(Name, Req=#http_req{p_headers=PHeaders}, Default, Fun) ->
case lists:keyfind(Name, 1, PHeaders) of
{Name, P} ->
{P, Req};
false ->
parse_header_no_cache(Name, Req, Default, Fun)
end.
parse_header_no_cache(Name, Req=#http_req{p_headers=PHeaders}, Default, Fun) ->
case header(Name, Req) of case header(Name, Req) of
{undefined, Req2} -> {undefined, Req2} ->
{Default, Req2#http_req{p_headers=[{Name, Default}|PHeaders]}}; {ok, Default, Req2#http_req{p_headers=[{Name, Default}|PHeaders]}};
{Value, Req2} -> {Value, Req2} ->
case Fun(Value) of case Fun(Value) of
{error, badarg} -> {error, badarg} ->
{error, badarg}; {error, badarg};
P -> P ->
{P, Req2#http_req{p_headers=[{Name, P}|PHeaders]}} {ok, P, Req2#http_req{p_headers=[{Name, P}|PHeaders]}}
end end
end. end.
@ -464,8 +476,11 @@ has_body(Req) ->
-spec body_length(Req) -> {undefined | non_neg_integer(), Req} when Req::req(). -spec body_length(Req) -> {undefined | non_neg_integer(), Req} when Req::req().
body_length(Req) -> body_length(Req) ->
case lists:keymember('Transfer-Encoding', 1, Req#http_req.headers) of case lists:keymember('Transfer-Encoding', 1, Req#http_req.headers) of
true -> {undefined, Req}; true ->
false -> parse_header('Content-Length', Req, 0) {undefined, Req};
false ->
{ok, Length, Req2} = parse_header('Content-Length', Req, 0),
{Length, Req2}
end. end.
%% @doc Initialize body streaming and set custom decoding functions. %% @doc Initialize body streaming and set custom decoding functions.
@ -505,21 +520,19 @@ init_stream(TransferDecode, TransferState, ContentDecode, Req) ->
stream_body(Req=#http_req{body_state=waiting, stream_body(Req=#http_req{body_state=waiting,
version=Version, transport=Transport, socket=Socket}) -> version=Version, transport=Transport, socket=Socket}) ->
case parse_header(<<"Expect">>, Req) of case parse_header(<<"Expect">>, Req) of
{[<<"100-continue">>], Req1} -> {ok, [<<"100-continue">>], Req1} ->
HTTPVer = cowboy_http:version_to_binary(Version), HTTPVer = cowboy_http:version_to_binary(Version),
Transport:send(Socket, Transport:send(Socket,
<< HTTPVer/binary, " ", (status(100))/binary, "\r\n\r\n" >>); << HTTPVer/binary, " ", (status(100))/binary, "\r\n\r\n" >>);
{undefined, Req1} -> {ok, undefined, Req1} ->
ok;
{undefined, _, Req1} ->
ok ok
end, end,
case parse_header('Transfer-Encoding', Req1) of case parse_header('Transfer-Encoding', Req1) of
{[<<"chunked">>], Req2} -> {ok, [<<"chunked">>], Req2} ->
stream_body(Req2#http_req{body_state= stream_body(Req2#http_req{body_state=
{stream, fun cowboy_http:te_chunked/2, {0, 0}, {stream, fun cowboy_http:te_chunked/2, {0, 0},
fun cowboy_http:ce_identity/1}}); fun cowboy_http:ce_identity/1}});
{[<<"identity">>], Req2} -> {ok, [<<"identity">>], Req2} ->
{Length, Req3} = body_length(Req2), {Length, Req3} = body_length(Req2),
case Length of case Length of
0 -> 0 ->
@ -635,11 +648,17 @@ skip_body(Req) ->
%% @doc Return the full body sent with the reqest, parsed as an %% @doc Return the full body sent with the reqest, parsed as an
%% application/x-www-form-urlencoded string. Essentially a POST query string. %% application/x-www-form-urlencoded string. Essentially a POST query string.
%% @todo We need an option to limit the size of the body for QS too. %% @todo We need an option to limit the size of the body for QS too.
-spec body_qs(Req) -> {list({binary(), binary() | true}), Req} when Req::req(). -spec body_qs(Req)
-> {ok, [{binary(), binary() | true}], Req} | {error, atom()}
when Req::req().
body_qs(Req=#http_req{urldecode={URLDecFun, URLDecArg}}) -> body_qs(Req=#http_req{urldecode={URLDecFun, URLDecArg}}) ->
{ok, Body, Req2} = body(Req), case body(Req) of
{cowboy_http:x_www_form_urlencoded( {ok, Body, Req2} ->
Body, fun(Bin) -> URLDecFun(Bin, URLDecArg) end), Req2}. {ok, cowboy_http:x_www_form_urlencoded(
Body, fun(Bin) -> URLDecFun(Bin, URLDecArg) end), Req2};
{error, Reason} ->
{error, Reason}
end.
%% Multipart Request API. %% Multipart Request API.
@ -653,13 +672,13 @@ body_qs(Req=#http_req{urldecode={URLDecFun, URLDecArg}}) ->
%% If the request Content-Type is not a multipart one, <em>{error, badarg}</em> %% If the request Content-Type is not a multipart one, <em>{error, badarg}</em>
%% is returned. %% is returned.
-spec multipart_data(Req) -spec multipart_data(Req)
-> {{headers, cowboy_http:headers()} | {body, binary()} -> {headers, cowboy_http:headers(), Req} | {body, binary(), Req}
| end_of_part | eof, Req} when Req::req(). | {end_of_part | eof, Req} when Req::req().
multipart_data(Req=#http_req{body_state=waiting}) -> multipart_data(Req=#http_req{body_state=waiting}) ->
{{<<"multipart">>, _SubType, Params}, Req2} = {ok, {<<"multipart">>, _SubType, Params}, Req2} =
parse_header('Content-Type', Req), parse_header('Content-Type', Req),
{_, Boundary} = lists:keyfind(<<"boundary">>, 1, Params), {_, Boundary} = lists:keyfind(<<"boundary">>, 1, Params),
{Length, Req3} = parse_header('Content-Length', Req2), {ok, Length, Req3} = parse_header('Content-Length', Req2),
multipart_data(Req3, Length, {more, cowboy_multipart:parser(Boundary)}); multipart_data(Req3, Length, {more, cowboy_multipart:parser(Boundary)});
multipart_data(Req=#http_req{multipart={Length, Cont}}) -> multipart_data(Req=#http_req{multipart={Length, Cont}}) ->
multipart_data(Req, Length, Cont()); multipart_data(Req, Length, Cont());
@ -668,9 +687,9 @@ multipart_data(Req=#http_req{body_state=done}) ->
%% @todo Typespecs. %% @todo Typespecs.
multipart_data(Req, Length, {headers, Headers, Cont}) -> multipart_data(Req, Length, {headers, Headers, Cont}) ->
{{headers, Headers}, Req#http_req{multipart={Length, Cont}}}; {headers, Headers, Req#http_req{multipart={Length, Cont}}};
multipart_data(Req, Length, {body, Data, Cont}) -> multipart_data(Req, Length, {body, Data, Cont}) ->
{{body, Data}, Req#http_req{multipart={Length, Cont}}}; {body, Data, Req#http_req{multipart={Length, Cont}}};
multipart_data(Req, Length, {end_of_part, Cont}) -> multipart_data(Req, Length, {end_of_part, Cont}) ->
{end_of_part, Req#http_req{multipart={Length, Cont}}}; {end_of_part, Req#http_req{multipart={Length, Cont}}};
multipart_data(Req, 0, eof) -> multipart_data(Req, 0, eof) ->
@ -697,33 +716,33 @@ multipart_skip(Req) ->
case multipart_data(Req) of case multipart_data(Req) of
{end_of_part, Req2} -> {ok, Req2}; {end_of_part, Req2} -> {ok, Req2};
{eof, Req2} -> {ok, Req2}; {eof, Req2} -> {ok, Req2};
{_Other, Req2} -> multipart_skip(Req2) {_, _, Req2} -> multipart_skip(Req2)
end. end.
%% Response API. %% Response API.
%% @doc Add a cookie header to the response. %% @doc Add a cookie header to the response.
-spec set_resp_cookie(binary(), binary(), -spec set_resp_cookie(binary(), binary(),
[cowboy_cookies:cookie_option()], Req) -> {ok, Req} when Req::req(). [cowboy_cookies:cookie_option()], Req) -> Req when Req::req().
set_resp_cookie(Name, Value, Options, Req) -> set_resp_cookie(Name, Value, Options, Req) ->
{HeaderName, HeaderValue} = cowboy_cookies:cookie(Name, Value, Options), {HeaderName, HeaderValue} = cowboy_cookies:cookie(Name, Value, Options),
set_resp_header(HeaderName, HeaderValue, Req). set_resp_header(HeaderName, HeaderValue, Req).
%% @doc Add a header to the response. %% @doc Add a header to the response.
-spec set_resp_header(cowboy_http:header(), iodata(), Req) -spec set_resp_header(cowboy_http:header(), iodata(), Req)
-> {ok, Req} when Req::req(). -> Req when Req::req().
set_resp_header(Name, Value, Req=#http_req{resp_headers=RespHeaders}) -> set_resp_header(Name, Value, Req=#http_req{resp_headers=RespHeaders}) ->
NameBin = header_to_binary(Name), NameBin = header_to_binary(Name),
{ok, Req#http_req{resp_headers=[{NameBin, Value}|RespHeaders]}}. Req#http_req{resp_headers=[{NameBin, Value}|RespHeaders]}.
%% @doc Add a body to the response. %% @doc Add a body to the response.
%% %%
%% The body set here is ignored if the response is later sent using %% The body set here is ignored if the response is later sent using
%% anything other than reply/2 or reply/3. The response body is expected %% anything other than reply/2 or reply/3. The response body is expected
%% to be a binary or an iolist. %% to be a binary or an iolist.
-spec set_resp_body(iodata(), Req) -> {ok, Req} when Req::req(). -spec set_resp_body(iodata(), Req) -> Req when Req::req().
set_resp_body(Body, Req) -> set_resp_body(Body, Req) ->
{ok, Req#http_req{resp_body=Body}}. Req#http_req{resp_body=Body}.
%% @doc Add a body function to the response. %% @doc Add a body function to the response.
%% %%
@ -740,9 +759,9 @@ set_resp_body(Body, Req) ->
%% %%
%% @see cowboy_req:transport/1. %% @see cowboy_req:transport/1.
-spec set_resp_body_fun(non_neg_integer(), -spec set_resp_body_fun(non_neg_integer(),
fun(() -> {sent, non_neg_integer()}), Req) -> {ok, Req} when Req::req(). fun(() -> {sent, non_neg_integer()}), Req) -> Req when Req::req().
set_resp_body_fun(StreamLen, StreamFun, Req) -> set_resp_body_fun(StreamLen, StreamFun, Req) ->
{ok, Req#http_req{resp_body={StreamLen, StreamFun}}}. Req#http_req{resp_body={StreamLen, StreamFun}}.
%% @doc Return whether the given header has been set for the response. %% @doc Return whether the given header has been set for the response.
-spec has_resp_header(cowboy_http:header(), req()) -> boolean(). -spec has_resp_header(cowboy_http:header(), req()) -> boolean().

View file

@ -126,7 +126,7 @@ allowed_methods(Req, State=#state{method=Method}) ->
end. end.
method_not_allowed(Req, State, Methods) -> method_not_allowed(Req, State, Methods) ->
{ok, Req2} = cowboy_req:set_resp_header( Req2 = cowboy_req:set_resp_header(
<<"Allow">>, method_not_allowed_build(Methods, []), Req), <<"Allow">>, method_not_allowed_build(Methods, []), Req),
respond(Req2, State, 405). respond(Req2, State, 405).
@ -153,7 +153,7 @@ is_authorized(Req, State) ->
{true, Req2, HandlerState} -> {true, Req2, HandlerState} ->
forbidden(Req2, State#state{handler_state=HandlerState}); forbidden(Req2, State#state{handler_state=HandlerState});
{{false, AuthHead}, Req2, HandlerState} -> {{false, AuthHead}, Req2, HandlerState} ->
{ok, Req3} = cowboy_req:set_resp_header( Req3 = cowboy_req:set_resp_header(
<<"Www-Authenticate">>, AuthHead, Req2), <<"Www-Authenticate">>, AuthHead, Req2),
respond(Req3, State#state{handler_state=HandlerState}, 401) respond(Req3, State#state{handler_state=HandlerState}, 401)
end. end.
@ -211,7 +211,7 @@ content_types_provided(Req, State) ->
CTP2 = [normalize_content_types(P) || P <- CTP], CTP2 = [normalize_content_types(P) || P <- CTP],
State2 = State#state{ State2 = State#state{
handler_state=HandlerState, content_types_p=CTP2}, handler_state=HandlerState, content_types_p=CTP2},
{Accept, Req3} = cowboy_req:parse_header('Accept', Req2), {ok, Accept, Req3} = cowboy_req:parse_header('Accept', Req2),
case Accept of case Accept of
undefined -> undefined ->
{PMT, _Fun} = HeadCTP = hd(CTP2), {PMT, _Fun} = HeadCTP = hd(CTP2),
@ -305,7 +305,7 @@ languages_provided(Req, State) ->
not_acceptable(Req2, State#state{handler_state=HandlerState}); not_acceptable(Req2, State#state{handler_state=HandlerState});
{LP, Req2, HandlerState} -> {LP, Req2, HandlerState} ->
State2 = State#state{handler_state=HandlerState, languages_p=LP}, State2 = State#state{handler_state=HandlerState, languages_p=LP},
{AcceptLanguage, Req3} = {ok, AcceptLanguage, Req3} =
cowboy_req:parse_header('Accept-Language', Req2), cowboy_req:parse_header('Accept-Language', Req2),
case AcceptLanguage of case AcceptLanguage of
undefined -> undefined ->
@ -352,8 +352,7 @@ match_language(Req, State, Accept, [Provided|Tail],
end. end.
set_language(Req, State=#state{language_a=Language}) -> set_language(Req, State=#state{language_a=Language}) ->
{ok, Req2} = cowboy_req:set_resp_header( Req2 = cowboy_req:set_resp_header(<<"Content-Language">>, Language, Req),
<<"Content-Language">>, Language, Req),
charsets_provided(cowboy_req:set_meta(language, Language, Req2), State). charsets_provided(cowboy_req:set_meta(language, Language, Req2), State).
%% charsets_provided should return a list of binary values indicating %% charsets_provided should return a list of binary values indicating
@ -368,7 +367,7 @@ charsets_provided(Req, State) ->
not_acceptable(Req2, State#state{handler_state=HandlerState}); not_acceptable(Req2, State#state{handler_state=HandlerState});
{CP, Req2, HandlerState} -> {CP, Req2, HandlerState} ->
State2 = State#state{handler_state=HandlerState, charsets_p=CP}, State2 = State#state{handler_state=HandlerState, charsets_p=CP},
{AcceptCharset, Req3} = {ok, AcceptCharset, Req3} =
cowboy_req:parse_header('Accept-Charset', Req2), cowboy_req:parse_header('Accept-Charset', Req2),
case AcceptCharset of case AcceptCharset of
undefined -> undefined ->
@ -417,8 +416,7 @@ set_content_type(Req, State=#state{
undefined -> ContentType; undefined -> ContentType;
Charset -> [ContentType, <<"; charset=">>, Charset] Charset -> [ContentType, <<"; charset=">>, Charset]
end, end,
{ok, Req2} = cowboy_req:set_resp_header( Req2 = cowboy_req:set_resp_header(<<"Content-Type">>, ContentType2, Req),
<<"Content-Type">>, ContentType2, Req),
encodings_provided(cowboy_req:set_meta(charset, Charset, Req2), State). encodings_provided(cowboy_req:set_meta(charset, Charset, Req2), State).
set_content_type_build_params([], []) -> set_content_type_build_params([], []) ->
@ -472,7 +470,7 @@ variances(Req, State=#state{content_types_p=CTP,
[] -> [] ->
resource_exists(Req3, State2); resource_exists(Req3, State2);
[[<<", ">>, H]|Variances5] -> [[<<", ">>, H]|Variances5] ->
{ok, Req4} = cowboy_req:set_resp_header( Req4 = cowboy_req:set_resp_header(
<<"Variances">>, [H|Variances5], Req3), <<"Variances">>, [H|Variances5], Req3),
resource_exists(Req4, State2) resource_exists(Req4, State2)
end. end.
@ -483,11 +481,11 @@ resource_exists(Req, State) ->
if_match_exists(Req, State) -> if_match_exists(Req, State) ->
case cowboy_req:parse_header('If-Match', Req) of case cowboy_req:parse_header('If-Match', Req) of
{undefined, Req2} -> {ok, undefined, Req2} ->
if_unmodified_since_exists(Req2, State); if_unmodified_since_exists(Req2, State);
{'*', Req2} -> {ok, '*', Req2} ->
if_unmodified_since_exists(Req2, State); if_unmodified_since_exists(Req2, State);
{ETagsList, Req2} -> {ok, ETagsList, Req2} ->
if_match(Req2, State, ETagsList) if_match(Req2, State, ETagsList)
end. end.
@ -507,12 +505,12 @@ if_match_musnt_exist(Req, State) ->
if_unmodified_since_exists(Req, State) -> if_unmodified_since_exists(Req, State) ->
case cowboy_req:parse_header('If-Unmodified-Since', Req) of case cowboy_req:parse_header('If-Unmodified-Since', Req) of
{undefined, Req2} -> {ok, undefined, Req2} ->
if_none_match_exists(Req2, State); if_none_match_exists(Req2, State);
{{error, badarg}, Req2} -> {ok, IfUnmodifiedSince, Req2} ->
if_none_match_exists(Req2, State); if_unmodified_since(Req2, State, IfUnmodifiedSince);
{IfUnmodifiedSince, Req2} -> {error, badarg} ->
if_unmodified_since(Req2, State, IfUnmodifiedSince) if_none_match_exists(Req, State)
end. end.
%% If LastModified is the atom 'no_call', we continue. %% If LastModified is the atom 'no_call', we continue.
@ -525,11 +523,11 @@ if_unmodified_since(Req, State, IfUnmodifiedSince) ->
if_none_match_exists(Req, State) -> if_none_match_exists(Req, State) ->
case cowboy_req:parse_header('If-None-Match', Req) of case cowboy_req:parse_header('If-None-Match', Req) of
{undefined, Req2} -> {ok, undefined, Req2} ->
if_modified_since_exists(Req2, State); if_modified_since_exists(Req2, State);
{'*', Req2} -> {ok, '*', Req2} ->
precondition_is_head_get(Req2, State); precondition_is_head_get(Req2, State);
{EtagsList, Req2} -> {ok, EtagsList, Req2} ->
if_none_match(Req2, State, EtagsList) if_none_match(Req2, State, EtagsList)
end. end.
@ -553,12 +551,12 @@ precondition_is_head_get(Req, State) ->
if_modified_since_exists(Req, State) -> if_modified_since_exists(Req, State) ->
case cowboy_req:parse_header('If-Modified-Since', Req) of case cowboy_req:parse_header('If-Modified-Since', Req) of
{undefined, Req2} -> {ok, undefined, Req2} ->
method(Req2, State); method(Req2, State);
{{error, badarg}, Req2} -> {ok, IfModifiedSince, Req2} ->
method(Req2, State); if_modified_since_now(Req2, State, IfModifiedSince);
{IfModifiedSince, Req2} -> {error, badarg} ->
if_modified_since_now(Req2, State, IfModifiedSince) method(Req, State)
end. end.
if_modified_since_now(Req, State, IfModifiedSince) -> if_modified_since_now(Req, State, IfModifiedSince) ->
@ -598,7 +596,7 @@ is_put_to_missing_resource(Req, State) ->
moved_permanently(Req, State, OnFalse) -> moved_permanently(Req, State, OnFalse) ->
case call(Req, State, moved_permanently) of case call(Req, State, moved_permanently) of
{{true, Location}, Req2, HandlerState} -> {{true, Location}, Req2, HandlerState} ->
{ok, Req3} = cowboy_req:set_resp_header( Req3 = cowboy_req:set_resp_header(
<<"Location">>, Location, Req2), <<"Location">>, Location, Req2),
respond(Req3, State#state{handler_state=HandlerState}, 301); respond(Req3, State#state{handler_state=HandlerState}, 301);
{false, Req2, HandlerState} -> {false, Req2, HandlerState} ->
@ -619,7 +617,7 @@ previously_existed(Req, State) ->
moved_temporarily(Req, State) -> moved_temporarily(Req, State) ->
case call(Req, State, moved_temporarily) of case call(Req, State, moved_temporarily) of
{{true, Location}, Req2, HandlerState} -> {{true, Location}, Req2, HandlerState} ->
{ok, Req3} = cowboy_req:set_resp_header( Req3 = cowboy_req:set_resp_header(
<<"Location">>, Location, Req2), <<"Location">>, Location, Req2),
respond(Req3, State#state{handler_state=HandlerState}, 307); respond(Req3, State#state{handler_state=HandlerState}, 307);
{false, Req2, HandlerState} -> {false, Req2, HandlerState} ->
@ -672,7 +670,7 @@ create_path(Req, State) ->
{Path, Req2, HandlerState} -> {Path, Req2, HandlerState} ->
{HostURL, Req3} = cowboy_req:host_url(Req2), {HostURL, Req3} = cowboy_req:host_url(Req2),
State2 = State#state{handler_state=HandlerState}, State2 = State#state{handler_state=HandlerState},
{ok, Req4} = cowboy_req:set_resp_header( Req4 = cowboy_req:set_resp_header(
<<"Location">>, << HostURL/binary, Path/binary >>, Req3), <<"Location">>, << HostURL/binary, Path/binary >>, Req3),
put_resource(cowboy_req:set_meta(put_path, Path, Req4), put_resource(cowboy_req:set_meta(put_path, Path, Req4),
State2, 303) State2, 303)
@ -716,7 +714,7 @@ put_resource(Req, State, OnTrue) ->
{CTA, Req2, HandlerState} -> {CTA, Req2, HandlerState} ->
CTA2 = [normalize_content_types(P) || P <- CTA], CTA2 = [normalize_content_types(P) || P <- CTA],
State2 = State#state{handler_state=HandlerState}, State2 = State#state{handler_state=HandlerState},
{ContentType, Req3} {ok, ContentType, Req3}
= cowboy_req:parse_header('Content-Type', Req2), = cowboy_req:parse_header('Content-Type', Req2),
choose_content_type(Req3, State2, OnTrue, ContentType, CTA2) choose_content_type(Req3, State2, OnTrue, ContentType, CTA2)
end. end.
@ -768,7 +766,7 @@ set_resp_body(Req, State=#state{content_type_a={_Type, Fun}}) ->
Req4 = Req3; Req4 = Req3;
LastModified -> LastModified ->
LastModifiedStr = httpd_util:rfc1123_date(LastModified), LastModifiedStr = httpd_util:rfc1123_date(LastModified),
{ok, Req4} = cowboy_req:set_resp_header( Req4 = cowboy_req:set_resp_header(
<<"Last-Modified">>, LastModifiedStr, Req3) <<"Last-Modified">>, LastModifiedStr, Req3)
end, end,
{Req5, State4} = set_resp_expires(Req4, State3), {Req5, State4} = set_resp_expires(Req4, State3),
@ -777,7 +775,7 @@ set_resp_body(Req, State=#state{content_type_a={_Type, Fun}}) ->
terminate(Req6, State4#state{handler_state=HandlerState}); terminate(Req6, State4#state{handler_state=HandlerState});
{Body, Req6, HandlerState} -> {Body, Req6, HandlerState} ->
State5 = State4#state{handler_state=HandlerState}, State5 = State4#state{handler_state=HandlerState},
{ok, Req7} = case Body of Req7 = case Body of
{stream, Len, Fun1} -> {stream, Len, Fun1} ->
cowboy_req:set_resp_body_fun(Len, Fun1, Req6); cowboy_req:set_resp_body_fun(Len, Fun1, Req6);
_Contents -> _Contents ->
@ -797,7 +795,7 @@ set_resp_etag(Req, State) ->
undefined -> undefined ->
{Req2, State2}; {Req2, State2};
Etag -> Etag ->
{ok, Req3} = cowboy_req:set_resp_header( Req3 = cowboy_req:set_resp_header(
<<"ETag">>, encode_etag(Etag), Req2), <<"ETag">>, encode_etag(Etag), Req2),
{Req3, State2} {Req3, State2}
end. end.
@ -813,7 +811,7 @@ set_resp_expires(Req, State) ->
{Req2, State2}; {Req2, State2};
Expires -> Expires ->
ExpiresStr = httpd_util:rfc1123_date(Expires), ExpiresStr = httpd_util:rfc1123_date(Expires),
{ok, Req3} = cowboy_req:set_resp_header( Req3 = cowboy_req:set_resp_header(
<<"Expires">>, ExpiresStr, Req2), <<"Expires">>, ExpiresStr, Req2),
{Req3, State2} {Req3, State2}
end. end.

View file

@ -71,11 +71,11 @@ upgrade(ListenerPid, Handler, Opts, Req) ->
-spec websocket_upgrade(#state{}, Req) -spec websocket_upgrade(#state{}, Req)
-> {ok, #state{}, Req} when Req::cowboy_req:req(). -> {ok, #state{}, Req} when Req::cowboy_req:req().
websocket_upgrade(State, Req) -> websocket_upgrade(State, Req) ->
{ConnTokens, Req2} {ok, ConnTokens, Req2}
= cowboy_req:parse_header('Connection', Req), = cowboy_req:parse_header('Connection', Req),
true = lists:member(<<"upgrade">>, ConnTokens), true = lists:member(<<"upgrade">>, ConnTokens),
%% @todo Should probably send a 426 if the Upgrade header is missing. %% @todo Should probably send a 426 if the Upgrade header is missing.
{[<<"websocket">>], Req3} = cowboy_req:parse_header('Upgrade', Req2), {ok, [<<"websocket">>], Req3} = cowboy_req:parse_header('Upgrade', Req2),
{Version, Req4} = cowboy_req:header(<<"Sec-Websocket-Version">>, Req3), {Version, Req4} = cowboy_req:header(<<"Sec-Websocket-Version">>, Req3),
websocket_upgrade(Version, State, Req4). websocket_upgrade(Version, State, Req4).

View file

@ -599,9 +599,7 @@ onrequest_reply(Config) ->
onrequest_hook(Req) -> onrequest_hook(Req) ->
case cowboy_req:qs_val(<<"reply">>, Req) of case cowboy_req:qs_val(<<"reply">>, Req) of
{undefined, Req2} -> {undefined, Req2} ->
{ok, Req3} = cowboy_req:set_resp_header( cowboy_req:set_resp_header('Server', <<"Serenity">>, Req2);
'Server', <<"Serenity">>, Req2),
Req3;
{_, Req2} -> {_, Req2} ->
{ok, Req3} = cowboy_req:reply( {ok, Req3} = cowboy_req:reply(
200, [], <<"replied!">>, Req2), 200, [], <<"replied!">>, Req2),

View file

@ -8,22 +8,22 @@ init({_Transport, http}, Req, []) ->
{ok, Req, {}}. {ok, Req, {}}.
handle(Req, State) -> handle(Req, State) ->
{Result, Req2} = acc_multipart(Req, []), {Result, Req2} = acc_multipart(Req),
{ok, Req3} = cowboy_req:reply(200, [], term_to_binary(Result), Req2), {ok, Req3} = cowboy_req:reply(200, [], term_to_binary(Result), Req2),
{ok, Req3, State}. {ok, Req3, State}.
terminate(_Req, _State) -> terminate(_Req, _State) ->
ok. ok.
acc_multipart(Req, Acc) -> acc_multipart(Req) ->
{Result, Req2} = cowboy_req:multipart_data(Req), acc_multipart(cowboy_req:multipart_data(Req), []).
acc_multipart(Req2, Acc, Result).
acc_multipart(Req, Acc, {headers, Headers}) -> acc_multipart({headers, Headers, Req}, Acc) ->
acc_multipart(Req, [{Headers, []}|Acc]); acc_multipart(cowboy_req:multipart_data(Req), [{Headers, []}|Acc]);
acc_multipart(Req, [{Headers, BodyAcc}|Acc], {body, Data}) -> acc_multipart({body, Data, Req}, [{Headers, BodyAcc}|Acc]) ->
acc_multipart(Req, [{Headers, [Data|BodyAcc]}|Acc]); acc_multipart(cowboy_req:multipart_data(Req), [{Headers, [Data|BodyAcc]}|Acc]);
acc_multipart(Req, [{Headers, BodyAcc}|Acc], end_of_part) -> acc_multipart({end_of_part, Req}, [{Headers, BodyAcc}|Acc]) ->
acc_multipart(Req, [{Headers, list_to_binary(lists:reverse(BodyAcc))}|Acc]); acc_multipart(cowboy_req:multipart_data(Req),
acc_multipart(Req, Acc, eof) -> [{Headers, list_to_binary(lists:reverse(BodyAcc))}|Acc]);
acc_multipart({eof, Req}, Acc) ->
{lists:reverse(Acc), Req}. {lists:reverse(Acc), Req}.

View file

@ -7,14 +7,12 @@
init({_Transport, http}, Req, Opts) -> init({_Transport, http}, Req, Opts) ->
Headers = proplists:get_value(headers, Opts, []), Headers = proplists:get_value(headers, Opts, []),
Body = proplists:get_value(body, Opts, <<"http_handler_set_resp">>), Body = proplists:get_value(body, Opts, <<"http_handler_set_resp">>),
{ok, Req2} = lists:foldl(fun({Name, Value}, {ok, R}) -> Req2 = lists:foldl(fun({Name, Value}, R) ->
cowboy_req:set_resp_header(Name, Value, R) cowboy_req:set_resp_header(Name, Value, R)
end, {ok, Req}, Headers), end, Req, Headers),
{ok, Req3} = cowboy_req:set_resp_body(Body, Req2), Req3 = cowboy_req:set_resp_body(Body, Req2),
{ok, Req4} = cowboy_req:set_resp_header( Req4 = cowboy_req:set_resp_header(<<"X-Cowboy-Test">>, <<"ok">>, Req3),
<<"X-Cowboy-Test">>, <<"ok">>, Req3), Req5 = cowboy_req:set_resp_cookie(<<"cake">>, <<"lie">>, [], Req4),
{ok, Req5} = cowboy_req:set_resp_cookie(
<<"cake">>, <<"lie">>, [], Req4),
{ok, Req5, undefined}. {ok, Req5, undefined}.
handle(Req, State) -> handle(Req, State) ->

View file

@ -16,7 +16,7 @@ handle(Req, State=#state{headers=_Headers, body=Body, reply=set_resp}) ->
{ok, Transport, Socket} = cowboy_req:transport(Req), {ok, Transport, Socket} = cowboy_req:transport(Req),
SFun = fun() -> Transport:send(Socket, Body), sent end, SFun = fun() -> Transport:send(Socket, Body), sent end,
SLen = iolist_size(Body), SLen = iolist_size(Body),
{ok, Req2} = cowboy_req:set_resp_body_fun(SLen, SFun, Req), Req2 = cowboy_req:set_resp_body_fun(SLen, SFun, Req),
{ok, Req3} = cowboy_req:reply(200, Req2), {ok, Req3} = cowboy_req:reply(200, Req2),
{ok, Req3, State}. {ok, Req3, State}.