Browse Source

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.
Loïc Hoguin 12 years ago
parent
commit
8d5f8db90a

+ 1 - 1
examples/echo_post/src/toppage_handler.erl

@@ -17,7 +17,7 @@ handle(Req, State) ->
 	{ok, Req4, State}.
 
 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(Echo, Req2);
 maybe_echo('POST', false, Req) ->

+ 1 - 1
src/cowboy_protocol.erl

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

+ 62 - 43
src/cowboy_req.erl

@@ -15,10 +15,30 @@
 
 %% @doc HTTP request manipulation API.
 %%
-%% Almost all functions in this module return a new <em>Req</em> variable.
-%% It should always be used instead of the one used in your function call
-%% because it keeps the state of the request. It also allows Cowboy to do
-%% some lazy evaluation and cache results where possible.
+%% The functions in this module try to follow this pattern for their
+%% return types:
+%% <dl>
+%% <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).
 
 %% Request API.
@@ -277,12 +297,12 @@ headers(Req) ->
 %% returned is used as a return value.
 %% @see parse_header/3
 -spec parse_header(cowboy_http:header(), Req)
-	-> {any(), Req} | {undefined, binary(), Req}
+	-> {ok, any(), Req} | {undefined, binary(), Req}
 	| {error, badarg} when Req::req().
 parse_header(Name, Req=#http_req{p_headers=PHeaders}) ->
 	case lists:keyfind(Name, 1, PHeaders) of
 		false -> parse_header(Name, Req, parse_header_default(Name));
-		{Name, Value} -> {Value, Req}
+		{Name, Value} -> {ok, Value, Req}
 	end.
 
 %% @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.
 -spec parse_header(cowboy_http:header(), Req, any())
-	-> {any(), Req} | {undefined, binary(), Req}
+	-> {ok, any(), Req} | {undefined, binary(), Req}
 	| {error, badarg} when Req::req().
 parse_header(Name, Req, Default) when Name =:= 'Accept' ->
 	parse_header(Name, Req, Default,
@@ -365,23 +385,15 @@ parse_header(Name, Req, Default) ->
 	{undefined, Value, Req2}.
 
 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
 		{undefined, Req2} ->
-			{Default, Req2#http_req{p_headers=[{Name, Default}|PHeaders]}};
+			{ok, Default, Req2#http_req{p_headers=[{Name, Default}|PHeaders]}};
 		{Value, Req2} ->
 			case Fun(Value) of
 				{error, badarg} ->
 					{error, badarg};
 				P ->
-					{P, Req2#http_req{p_headers=[{Name, P}|PHeaders]}}
+					{ok, P, Req2#http_req{p_headers=[{Name, P}|PHeaders]}}
 			end
 	end.
 
@@ -464,8 +476,11 @@ has_body(Req) ->
 -spec body_length(Req) -> {undefined | non_neg_integer(), Req} when Req::req().
 body_length(Req) ->
 	case lists:keymember('Transfer-Encoding', 1, Req#http_req.headers) of
-		true -> {undefined, Req};
-		false -> parse_header('Content-Length', Req, 0)
+		true ->
+			{undefined, Req};
+		false ->
+			{ok, Length, Req2} = parse_header('Content-Length', Req, 0),
+			{Length, Req2}
 	end.
 
 %% @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,
 		version=Version, transport=Transport, socket=Socket}) ->
 	case parse_header(<<"Expect">>, Req) of
-		{[<<"100-continue">>], Req1} ->
+		{ok, [<<"100-continue">>], Req1} ->
 			HTTPVer = cowboy_http:version_to_binary(Version),
 			Transport:send(Socket,
 				<< HTTPVer/binary, " ", (status(100))/binary, "\r\n\r\n" >>);
-		{undefined, Req1} ->
-			ok;
-		{undefined, _, Req1} ->
+		{ok, undefined, Req1} ->
 			ok
 	end,
 	case parse_header('Transfer-Encoding', Req1) of
-		{[<<"chunked">>], Req2} ->
+		{ok, [<<"chunked">>], Req2} ->
 			stream_body(Req2#http_req{body_state=
 				{stream, fun cowboy_http:te_chunked/2, {0, 0},
 				 fun cowboy_http:ce_identity/1}});
-		{[<<"identity">>], Req2} ->
+		{ok, [<<"identity">>], Req2} ->
 			{Length, Req3} = body_length(Req2),
 			case Length of
 				0 ->
@@ -635,11 +648,17 @@ skip_body(Req) ->
 %% @doc Return the full body sent with the reqest, parsed as an
 %% 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.
--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}}) ->
-	{ok, Body, Req2} = body(Req),
-	{cowboy_http:x_www_form_urlencoded(
-		Body, fun(Bin) -> URLDecFun(Bin, URLDecArg) end), Req2}.
+	case body(Req) of
+		{ok, Body, Req2} ->
+			{ok, cowboy_http:x_www_form_urlencoded(
+				Body, fun(Bin) -> URLDecFun(Bin, URLDecArg) end), Req2};
+		{error, Reason} ->
+			{error, Reason}
+	end.
 
 %% 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>
 %% is returned.
 -spec multipart_data(Req)
-	-> {{headers, cowboy_http:headers()} | {body, binary()}
-		| end_of_part | eof, Req} when Req::req().
+	-> {headers, cowboy_http:headers(), Req} | {body, binary(), Req}
+		| {end_of_part | eof, Req} when Req::req().
 multipart_data(Req=#http_req{body_state=waiting}) ->
-	{{<<"multipart">>, _SubType, Params}, Req2} =
+	{ok, {<<"multipart">>, _SubType, Params}, Req2} =
 		parse_header('Content-Type', Req),
 	{_, 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(Req=#http_req{multipart={Length, Cont}}) ->
 	multipart_data(Req, Length, Cont());
@@ -668,9 +687,9 @@ multipart_data(Req=#http_req{body_state=done}) ->
 
 %% @todo Typespecs.
 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}) ->
-	{{body, Data}, Req#http_req{multipart={Length, Cont}}};
+	{body, Data, Req#http_req{multipart={Length, Cont}}};
 multipart_data(Req, Length, {end_of_part, Cont}) ->
 	{end_of_part, Req#http_req{multipart={Length, Cont}}};
 multipart_data(Req, 0, eof) ->
@@ -697,33 +716,33 @@ multipart_skip(Req) ->
 	case multipart_data(Req) of
 		{end_of_part, Req2} -> {ok, Req2};
 		{eof, Req2} -> {ok, Req2};
-		{_Other, Req2} -> multipart_skip(Req2)
+		{_, _, Req2} -> multipart_skip(Req2)
 	end.
 
 %% Response API.
 
 %% @doc Add a cookie header to the response.
 -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) ->
 	{HeaderName, HeaderValue} = cowboy_cookies:cookie(Name, Value, Options),
 	set_resp_header(HeaderName, HeaderValue, Req).
 
 %% @doc Add a header to the response.
 -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}) ->
 	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.
 %%
 %% 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
 %% 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) ->
-	{ok, Req#http_req{resp_body=Body}}.
+	Req#http_req{resp_body=Body}.
 
 %% @doc Add a body function to the response.
 %%
@@ -740,9 +759,9 @@ set_resp_body(Body, Req) ->
 %%
 %% @see cowboy_req:transport/1.
 -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) ->
-	{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.
 -spec has_resp_header(cowboy_http:header(), req()) -> boolean().

+ 32 - 34
src/cowboy_rest.erl

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

+ 2 - 2
src/cowboy_websocket.erl

@@ -71,11 +71,11 @@ upgrade(ListenerPid, Handler, Opts, Req) ->
 -spec websocket_upgrade(#state{}, Req)
 	-> {ok, #state{}, Req} when Req::cowboy_req:req().
 websocket_upgrade(State, Req) ->
-	{ConnTokens, Req2}
+	{ok, ConnTokens, Req2}
 		= cowboy_req:parse_header('Connection', Req),
 	true = lists:member(<<"upgrade">>, ConnTokens),
 	%% @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),
 	websocket_upgrade(Version, State, Req4).
 

+ 1 - 3
test/http_SUITE.erl

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

+ 11 - 11
test/http_handler_multipart.erl

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

+ 5 - 7
test/http_handler_set_resp.erl

@@ -7,14 +7,12 @@
 init({_Transport, http}, Req, Opts) ->
 	Headers = proplists:get_value(headers, Opts, []),
 	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)
-	end, {ok, Req}, Headers),
-	{ok, Req3} = cowboy_req:set_resp_body(Body, Req2),
-	{ok, Req4} = cowboy_req:set_resp_header(
-		<<"X-Cowboy-Test">>, <<"ok">>, Req3),
-	{ok, Req5} = cowboy_req:set_resp_cookie(
-		<<"cake">>, <<"lie">>, [], Req4),
+	end, Req, Headers),
+	Req3 = cowboy_req:set_resp_body(Body, Req2),
+	Req4 = cowboy_req:set_resp_header(<<"X-Cowboy-Test">>, <<"ok">>, Req3),
+	Req5 = cowboy_req:set_resp_cookie(<<"cake">>, <<"lie">>, [], Req4),
 	{ok, Req5, undefined}.
 
 handle(Req, State) ->

+ 1 - 1
test/http_handler_stream_body.erl

@@ -16,7 +16,7 @@ handle(Req, State=#state{headers=_Headers, body=Body, reply=set_resp}) ->
 	{ok, Transport, Socket} = cowboy_req:transport(Req),
 	SFun = fun() -> Transport:send(Socket, Body), sent end,
 	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, State}.