Browse Source

Make reply functions return Req

Loïc Hoguin 8 years ago
parent
commit
e30d120bd8

+ 2 - 2
examples/chunked_hello_world/src/toppage_handler.erl

@@ -5,8 +5,8 @@
 
 -export([init/2]).
 
-init(Req, Opts) ->
-	cowboy_req:stream_reply(200, Req),
+init(Req0, Opts) ->
+	Req = cowboy_req:stream_reply(200, Req0),
 	cowboy_req:stream_body("Hello\r\n", nofin, Req),
 	timer:sleep(1000),
 	cowboy_req:stream_body("World\r\n", nofin, Req),

+ 3 - 3
examples/compress_response/src/toppage_handler.erl

@@ -5,7 +5,7 @@
 
 -export([init/2]).
 
-init(Req, Opts) ->
+init(Req0, Opts) ->
 	BigBody =
 <<"A cowboy is an animal herder who tends cattle on ranches in North America,
 traditionally on horseback, and often performs a multitude of other ranch-
@@ -19,5 +19,5 @@ have established the ability to work at virtually identical tasks and obtained
 considerable respect for their achievements. There are also cattle handlers
 in many other parts of the world, particularly South America and Australia,
 who perform work similar to the cowboy in their respective nations.\n">>,
-	Req2 = cowboy_req:reply(200, [], BigBody, Req),
-	{ok, Req2, Opts}.
+	Req = cowboy_req:reply(200, [], BigBody, Req0),
+	{ok, Req, Opts}.

+ 6 - 6
examples/cookie/src/toppage_handler.erl

@@ -5,17 +5,17 @@
 
 -export([init/2]).
 
-init(Req, Opts) ->
+init(Req0, Opts) ->
 	NewValue = integer_to_list(rand:uniform(1000000)),
-	Req2 = cowboy_req:set_resp_cookie(<<"server">>, NewValue,
-		#{path => <<"/">>}, Req),
+	Req1 = cowboy_req:set_resp_cookie(<<"server">>, NewValue,
+		#{path => <<"/">>}, Req0),
 	#{client := ClientCookie, server := ServerCookie}
 		= cowboy_req:match_cookies([{client, [], <<>>}, {server, [], <<>>}], Req2),
 	{ok, Body} = toppage_dtl:render([
 		{client, ClientCookie},
 		{server, ServerCookie}
 	]),
-	cowboy_req:reply(200, #{
+	Req = cowboy_req:reply(200, #{
 		<<"content-type">> => <<"text/html">>
-	}, Body, Req2),
-	{ok, Req2, Opts}.
+	}, Body, Req1),
+	{ok, Req1, Opts}.

+ 4 - 4
examples/echo_get/src/toppage_handler.erl

@@ -5,10 +5,10 @@
 
 -export([init/2]).
 
-init(Req, Opts) ->
-	Method = cowboy_req:method(Req),
-	#{echo := Echo} = cowboy_req:match_qs([echo], Req),
-	echo(Method, Echo, Req),
+init(Req0, Opts) ->
+	Method = cowboy_req:method(Req0),
+	#{echo := Echo} = cowboy_req:match_qs([echo], Req0),
+	Req = echo(Method, Echo, Req0),
 	{ok, Req, Opts}.
 
 echo(<<"GET">>, undefined, Req) ->

+ 10 - 13
examples/echo_post/src/toppage_handler.erl

@@ -5,24 +5,21 @@
 
 -export([init/2]).
 
-init(Req, Opts) ->
-	Method = cowboy_req:method(Req),
-	HasBody = cowboy_req:has_body(Req),
-	Req2 = maybe_echo(Method, HasBody, Req),
-	{ok, Req2, Opts}.
+init(Req0, Opts) ->
+	Method = cowboy_req:method(Req0),
+	HasBody = cowboy_req:has_body(Req0),
+	Req = maybe_echo(Method, HasBody, Req0),
+	{ok, Req, Opts}.
 
-maybe_echo(<<"POST">>, true, Req) ->
-	{ok, PostVals, Req2} = cowboy_req:read_urlencoded_body(Req),
+maybe_echo(<<"POST">>, true, Req0) ->
+	{ok, PostVals, Req} = cowboy_req:read_urlencoded_body(Req0),
 	Echo = proplists:get_value(<<"echo">>, PostVals),
-	echo(Echo, Req2),
-	Req2;
+	echo(Echo, Req);
 maybe_echo(<<"POST">>, false, Req) ->
-	cowboy_req:reply(400, [], <<"Missing body.">>, Req),
-	Req;
+	cowboy_req:reply(400, [], <<"Missing body.">>, Req);
 maybe_echo(_, _, Req) ->
 	%% Method not allowed.
-	cowboy_req:reply(405, Req),
-	Req.
+	cowboy_req:reply(405, Req).
 
 echo(undefined, Req) ->
 	cowboy_req:reply(400, [], <<"Missing echo parameter.">>, Req);

+ 3 - 3
examples/eventsource/src/eventsource_handler.erl

@@ -6,10 +6,10 @@
 -export([init/2]).
 -export([info/3]).
 
-init(Req, Opts) ->
-	cowboy_req:stream_reply(200, #{
+init(Req0, Opts) ->
+	Req = cowboy_req:stream_reply(200, #{
 		<<"content-type">> => <<"text/event-stream">>
-	}, Req),
+	}, Req0),
 	erlang:send_after(1000, self(), {message, "Tick"}),
 	{cowboy_loop, Req, Opts, 5000}.
 

+ 3 - 3
examples/hello_world/src/toppage_handler.erl

@@ -5,8 +5,8 @@
 
 -export([init/2]).
 
-init(Req, Opts) ->
-	cowboy_req:reply(200, #{
+init(Req0, Opts) ->
+	Req = cowboy_req:reply(200, #{
 		<<"content-type">> => <<"text/plain">>
-	}, <<"Hello world!">>, Req),
+	}, <<"Hello world!">>, Req0),
 	{ok, Req, Opts}.

+ 3 - 3
examples/ssl_hello_world/src/toppage_handler.erl

@@ -5,8 +5,8 @@
 
 -export([init/2]).
 
-init(Req, Opts) ->
-	cowboy_req:reply(200, #{
+init(Req0, Opts) ->
+	Req = cowboy_req:reply(200, #{
 		<<"content-type">> => <<"text/plain">>
-	}, <<"Hello world!">>, Req),
+	}, <<"Hello world!">>, Req0),
 	{ok, Req, Opts}.

+ 5 - 0
src/cowboy_http.erl

@@ -805,6 +805,11 @@ commands(State, StreamID, [{flow, _Length}|Tail]) ->
 	%% @todo Set the body reading length to min(Length, BodyLength)
 
 	commands(State, StreamID, Tail);
+%% Error responses are sent only if a response wasn't sent already.
+commands(State=#state{out_state=wait}, StreamID, [{error_response, StatusCode, Headers, Body}|Tail]) ->
+	commands(State, StreamID, [{response, StatusCode, Headers, Body}|Tail]);
+commands(State, StreamID, [{error_response, _, _, _}|Tail]) ->
+	commands(State, StreamID, Tail);
 %% Send a full response.
 %%
 %% @todo Kill the stream if it sent a response when one has already been sent.

+ 5 - 0
src/cowboy_http2.erl

@@ -369,6 +369,11 @@ info(State=#state{handler=Handler, streams=Streams}, StreamID, Msg) ->
 
 commands(State, Stream, []) ->
 	after_commands(State, Stream);
+%% Error responses are sent only if a response wasn't sent already.
+commands(State, Stream=#stream{local=idle}, [{error_response, StatusCode, Headers, Body}|Tail]) ->
+	commands(State, Stream, [{response, StatusCode, Headers, Body}|Tail]);
+commands(State, Stream, [{error_response, _, _, _}|Tail]) ->
+	commands(State, Stream, Tail);
 %% Send response headers.
 %%
 %% @todo Kill the stream if it sent a response when one has already been sent.

+ 14 - 6
src/cowboy_req.erl

@@ -592,6 +592,8 @@ reply(Status, Headers, Req) ->
 
 -spec reply(cowboy:http_status(), cowboy:http_headers(), resp_body(), Req)
 	-> Req when Req::req().
+reply(_, _, _, #{has_sent_resp := _}) ->
+	error(function_clause);
 reply(Status, Headers, SendFile = {sendfile, _, Len, _}, Req)
 		when is_integer(Status); is_binary(Status) ->
 	do_reply(Status, Headers#{
@@ -608,10 +610,13 @@ reply(Status, Headers, Body, Req)
 %% data around if we can avoid it.
 do_reply(Status, Headers, _, Req=#{pid := Pid, streamid := StreamID, method := <<"HEAD">>}) ->
 	Pid ! {{Pid, StreamID}, {response, Status, response_headers(Headers, Req), <<>>}},
-	ok;
+	done_replying(Req, true);
 do_reply(Status, Headers, Body, Req=#{pid := Pid, streamid := StreamID}) ->
 	Pid ! {{Pid, StreamID}, {response, Status, response_headers(Headers, Req), Body}},
-	ok.
+	done_replying(Req, true).
+
+done_replying(Req, HasSentResp) ->
+	maps:without([resp_cookies, resp_headers, resp_body], Req#{has_sent_resp => HasSentResp}).
 
 -spec stream_reply(cowboy:http_status(), Req) -> Req when Req::req().
 stream_reply(Status, Req) ->
@@ -619,25 +624,28 @@ stream_reply(Status, Req) ->
 
 -spec stream_reply(cowboy:http_status(), cowboy:http_headers(), Req)
 	-> Req when Req::req().
+stream_reply(_, _, #{has_sent_resp := _}) ->
+	error(function_clause);
 stream_reply(Status, Headers=#{}, Req=#{pid := Pid, streamid := StreamID})
 		when is_integer(Status); is_binary(Status) ->
 	Pid ! {{Pid, StreamID}, {headers, Status, response_headers(Headers, Req)}},
-	ok.
+	done_replying(Req, headers).
 
 -spec stream_body(iodata(), fin | nofin, req()) -> ok.
+%% Error out if headers were not sent.
 %% Don't send any body for HEAD responses.
-stream_body(_, _, #{method := <<"HEAD">>}) ->
+stream_body(_, _, #{method := <<"HEAD">>, has_sent_resp := headers}) ->
 	ok;
 %% Don't send a message if the data is empty, except for the
 %% very last message with IsFin=fin.
-stream_body(Data, IsFin=nofin, #{pid := Pid, streamid := StreamID}) ->
+stream_body(Data, IsFin=nofin, #{pid := Pid, streamid := StreamID, has_sent_resp := headers}) ->
 	case iolist_size(Data) of
 		0 -> ok;
 		_ ->
 			Pid ! {{Pid, StreamID}, {data, IsFin, Data}},
 			ok
 	end;
-stream_body(Data, IsFin, #{pid := Pid, streamid := StreamID}) ->
+stream_body(Data, IsFin, #{pid := Pid, streamid := StreamID, has_sent_resp := headers}) ->
 	Pid ! {{Pid, StreamID}, {data, IsFin, Data}},
 	ok.
 

+ 3 - 3
src/cowboy_stream_h.erl

@@ -78,18 +78,18 @@ info(_StreamID, {'EXIT', Pid, normal}, State=#state{pid=Pid}) ->
 info(_StreamID, Exit = {'EXIT', Pid, {cowboy_handler, _}}, State=#state{pid=Pid}) ->
 	%% No crash report; one has already been sent.
 	{[
-		{response, 500, #{<<"content-length">> => <<"0">>}, <<>>},
+		{error_response, 500, #{<<"content-length">> => <<"0">>}, <<>>},
 		{internal_error, Exit, 'Stream process crashed.'}
 	], State};
 info(_StreamID, {'EXIT', Pid, {_Reason, [_, {cow_http_hd, _, _, _}|_]}}, State=#state{pid=Pid}) ->
 	%% @todo Have an option to enable/disable this specific crash report?
 	%%report_crash(Ref, StreamID, Pid, Reason, Stacktrace),
 	%% @todo Headers? Details in body? More stuff in debug only?
-	{[{response, 400, #{}, <<>>}, stop], State};
+	{[{error_response, 400, #{}, <<>>}, stop], State};
 info(StreamID, Exit = {'EXIT', Pid, {Reason, Stacktrace}}, State=#state{ref=Ref, pid=Pid}) ->
 	report_crash(Ref, StreamID, Pid, Reason, Stacktrace),
 	{[
-		{response, 500, #{<<"content-length">> => <<"0">>}, <<>>},
+		{error_response, 500, #{<<"content-length">> => <<"0">>}, <<>>},
 		{internal_error, Exit, 'Stream process crashed.'}
 	], State};
 %% Request body, no body buffer but IsFin=fin.

+ 2 - 2
src/cowboy_websocket.erl

@@ -79,8 +79,8 @@ upgrade(Req, Env, Handler, HandlerState, Timeout, Hibernate) ->
 			websocket_handshake(State2, Req2, HandlerState, Env)
 	catch _:_ ->
 		%% @todo Test that we can have 2 /ws 400 status code in a row on the same connection.
-		cowboy_req:reply(400, Req),
-		{ok, Req, Env}
+		%% @todo Does this even work?
+		{ok, cowboy_req:reply(400, Req), Env}
 	end.
 
 -spec websocket_upgrade(#state{}, Req)

+ 6 - 12
test/handlers/echo_h.erl

@@ -22,8 +22,7 @@ echo(<<"read_body">>, Req0, Opts) ->
 		<<"/opts", _/bits>> -> cowboy_req:read_body(Req0, Opts);
 		_ -> cowboy_req:read_body(Req0)
 	end,
-	cowboy_req:reply(200, #{}, Body, Req),
-	{ok, Req, Opts};
+	{ok, cowboy_req:reply(200, #{}, Body, Req), Opts};
 echo(<<"read_urlencoded_body">>, Req0, Opts) ->
 	Path = cowboy_req:path(Req0),
 	case {Path, Opts} of
@@ -36,8 +35,7 @@ echo(<<"read_urlencoded_body">>, Req0, Opts) ->
 		<<"/crash", _/bits>> -> cowboy_req:read_urlencoded_body(Req0, Opts);
 		_ -> cowboy_req:read_urlencoded_body(Req0)
 	end,
-	cowboy_req:reply(200, #{}, value_to_iodata(Body), Req),
-	{ok, Req, Opts};
+	{ok, cowboy_req:reply(200, #{}, value_to_iodata(Body), Req), Opts};
 echo(<<"uri">>, Req, Opts) ->
 	Value = case cowboy_req:path_info(Req) of
 		[<<"origin">>] -> cowboy_req:uri(Req, #{host => undefined});
@@ -47,8 +45,7 @@ echo(<<"uri">>, Req, Opts) ->
 		[<<"set-port">>] -> cowboy_req:uri(Req, #{port => 123});
 		[] -> cowboy_req:uri(Req)
 	end,
-	cowboy_req:reply(200, #{}, Value, Req),
-	{ok, Req, Opts};
+	{ok, cowboy_req:reply(200, #{}, Value, Req), Opts};
 echo(<<"match">>, Req, Opts) ->
 	[Type|Fields0] = cowboy_req:path_info(Req),
 	Fields = [binary_to_atom(F, latin1) || F <- Fields0],
@@ -56,13 +53,11 @@ echo(<<"match">>, Req, Opts) ->
 		<<"qs">> -> cowboy_req:match_qs(Fields, Req);
 		<<"cookies">> -> cowboy_req:match_cookies(Fields, Req)
 	end,
-	cowboy_req:reply(200, #{}, value_to_iodata(Value), Req),
-	{ok, Req, Opts};
+	{ok, cowboy_req:reply(200, #{}, value_to_iodata(Value), Req), Opts};
 echo(What, Req, Opts) ->
 	F = binary_to_atom(What, latin1),
 	Value = cowboy_req:F(Req),
-	cowboy_req:reply(200, #{}, value_to_iodata(Value), Req),
-	{ok, Req, Opts}.
+	{ok, cowboy_req:reply(200, #{}, value_to_iodata(Value), Req), Opts}.
 
 echo_arg(Arg0, Req, Opts) ->
 	F = binary_to_atom(cowboy_req:binding(key, Req), latin1),
@@ -74,8 +69,7 @@ echo_arg(Arg0, Req, Opts) ->
 		undefined -> cowboy_req:F(Arg, Req);
 		Default -> cowboy_req:F(Arg, Req, Default)
 	end,
-	cowboy_req:reply(200, #{}, value_to_iodata(Value), Req),
-	{ok, Req, Opts}.
+	{ok, cowboy_req:reply(200, #{}, value_to_iodata(Value), Req), Opts}.
 
 read_body(Req0, Acc) ->
 	case cowboy_req:read_body(Req0) of

+ 3 - 4
test/handlers/loop_handler_body_h.erl

@@ -13,11 +13,10 @@ init(Req, _) ->
 	self() ! timeout,
 	{cowboy_loop, Req, undefined, 5000, hibernate}.
 
-info(timeout, Req, State) ->
-	{ok, Body, Req2} = cowboy_req:read_body(Req),
+info(timeout, Req0, State) ->
+	{ok, Body, Req} = cowboy_req:read_body(Req0),
 	100000 = byte_size(Body),
-	cowboy_req:reply(200, Req2),
-	{stop, Req, State}.
+	{stop, cowboy_req:reply(200, Req), State}.
 
 terminate(stop, _, _) ->
 	ok.

+ 37 - 44
test/handlers/resp_h.erl

@@ -18,38 +18,34 @@ do(<<"set_resp_cookie3">>, Req0, Opts) ->
 			Req1 = cowboy_req:set_resp_cookie(<<"mycookie">>, "myvalue", Req0),
 			cowboy_req:set_resp_cookie(<<"mycookie">>, <<"overwrite">>, Req1)
 	end,
-	cowboy_req:reply(200, #{}, "OK", Req),
-	{ok, Req, Opts};
+	{ok, cowboy_req:reply(200, #{}, "OK", Req), Opts};
 do(<<"set_resp_cookie4">>, Req0, Opts) ->
 	Req = cowboy_req:set_resp_cookie(<<"mycookie">>, "myvalue", #{path => cowboy_req:path(Req0)}, Req0),
-	cowboy_req:reply(200, #{}, "OK", Req),
-	{ok, Req, Opts};
+	{ok, cowboy_req:reply(200, #{}, "OK", Req), Opts};
 do(<<"set_resp_header">>, Req0, Opts) ->
 	Req = cowboy_req:set_resp_header(<<"content-type">>, <<"text/plain">>, Req0),
-	cowboy_req:reply(200, #{}, "OK", Req),
-	{ok, Req, Opts};
+	{ok, cowboy_req:reply(200, #{}, "OK", Req), Opts};
 do(<<"set_resp_body">>, Req0, Opts) ->
 	Arg = cowboy_req:binding(arg, Req0),
-	Req = case Arg of
+	Req1 = case Arg of
 		<<"sendfile">> ->
 			AppFile = code:where_is_file("cowboy.app"),
 			cowboy_req:set_resp_body({sendfile, 0, filelib:file_size(AppFile), AppFile}, Req0);
 		_ ->
 			cowboy_req:set_resp_body(<<"OK">>, Req0)
 	end,
-	case Arg of
+	Req = case Arg of
 		<<"override">> ->
-			cowboy_req:reply(200, #{}, <<"OVERRIDE">>, Req);
+			cowboy_req:reply(200, #{}, <<"OVERRIDE">>, Req1);
 		_ ->
-			cowboy_req:reply(200, Req)
+			cowboy_req:reply(200, Req1)
 	end,
 	{ok, Req, Opts};
 do(<<"has_resp_header">>, Req0, Opts) ->
 	false = cowboy_req:has_resp_header(<<"content-type">>, Req0),
 	Req = cowboy_req:set_resp_header(<<"content-type">>, <<"text/plain">>, Req0),
 	true = cowboy_req:has_resp_header(<<"content-type">>, Req),
-	cowboy_req:reply(200, #{}, "OK", Req),
-	{ok, Req, Opts};
+	{ok, cowboy_req:reply(200, #{}, "OK", Req), Opts};
 do(<<"has_resp_body">>, Req0, Opts) ->
 	case cowboy_req:binding(arg, Req0) of
 		<<"sendfile">> ->
@@ -57,14 +53,12 @@ do(<<"has_resp_body">>, Req0, Opts) ->
 			false = cowboy_req:has_resp_body(Req0),
 			Req = cowboy_req:set_resp_body({sendfile, 0, 10, code:where_is_file("cowboy.app")}, Req0),
 			true = cowboy_req:has_resp_body(Req),
-			cowboy_req:reply(200, #{}, <<"OK">>, Req),
-			{ok, Req, Opts};
+			{ok, cowboy_req:reply(200, #{}, <<"OK">>, Req), Opts};
 		undefined ->
 			false = cowboy_req:has_resp_body(Req0),
 			Req = cowboy_req:set_resp_body(<<"OK">>, Req0),
 			true = cowboy_req:has_resp_body(Req),
-			cowboy_req:reply(200, #{}, Req),
-			{ok, Req, Opts}
+			{ok, cowboy_req:reply(200, #{}, Req), Opts}
 	end;
 do(<<"delete_resp_header">>, Req0, Opts) ->
 	false = cowboy_req:has_resp_header(<<"content-type">>, Req0),
@@ -72,61 +66,61 @@ do(<<"delete_resp_header">>, Req0, Opts) ->
 	true = cowboy_req:has_resp_header(<<"content-type">>, Req1),
 	Req = cowboy_req:delete_resp_header(<<"content-type">>, Req1),
 	false = cowboy_req:has_resp_header(<<"content-type">>, Req),
-	cowboy_req:reply(200, #{}, "OK", Req),
-	{ok, Req, Opts};
-do(<<"reply2">>, Req, Opts) ->
-	case cowboy_req:binding(arg, Req) of
+	{ok, cowboy_req:reply(200, #{}, "OK", Req), Opts};
+do(<<"reply2">>, Req0, Opts) ->
+	Req = case cowboy_req:binding(arg, Req0) of
 		<<"binary">> ->
-			cowboy_req:reply(<<"200 GOOD">>, Req);
+			cowboy_req:reply(<<"200 GOOD">>, Req0);
 		<<"error">> ->
 			ct_helper:ignore(cowboy_req, reply, 4),
-			cowboy_req:reply(ok, Req);
+			cowboy_req:reply(ok, Req0);
 		<<"twice">> ->
-			cowboy_req:reply(200, Req),
-			cowboy_req:reply(200, Req);
+			ct_helper:ignore(cowboy_req, reply, 4),
+			Req1 = cowboy_req:reply(200, Req0),
+			cowboy_req:reply(200, Req1);
 		Status ->
-			cowboy_req:reply(binary_to_integer(Status), Req)
+			cowboy_req:reply(binary_to_integer(Status), Req0)
 	end,
 	{ok, Req, Opts};
-do(<<"reply3">>, Req, Opts) ->
-	case cowboy_req:binding(arg, Req) of
+do(<<"reply3">>, Req0, Opts) ->
+	Req = case cowboy_req:binding(arg, Req0) of
 		<<"error">> ->
 			ct_helper:ignore(cowboy_req, reply, 4),
-			cowboy_req:reply(200, ok, Req);
+			cowboy_req:reply(200, ok, Req0);
 		Status ->
 			cowboy_req:reply(binary_to_integer(Status),
-				#{<<"content-type">> => <<"text/plain">>}, Req)
+				#{<<"content-type">> => <<"text/plain">>}, Req0)
 	end,
 	{ok, Req, Opts};
-do(<<"reply4">>, Req, Opts) ->
-	case cowboy_req:binding(arg, Req) of
+do(<<"reply4">>, Req0, Opts) ->
+	Req = case cowboy_req:binding(arg, Req0) of
 		<<"error">> ->
 			ct_helper:ignore(erlang, iolist_size, 1),
-			cowboy_req:reply(200, #{}, ok, Req);
+			cowboy_req:reply(200, #{}, ok, Req0);
 		Status ->
-			cowboy_req:reply(binary_to_integer(Status), #{}, <<"OK">>, Req)
+			cowboy_req:reply(binary_to_integer(Status), #{}, <<"OK">>, Req0)
 	end,
 	{ok, Req, Opts};
-do(<<"stream_reply2">>, Req, Opts) ->
-	case cowboy_req:binding(arg, Req) of
+do(<<"stream_reply2">>, Req0, Opts) ->
+	Req = case cowboy_req:binding(arg, Req0) of
 		<<"binary">> ->
-			cowboy_req:stream_reply(<<"200 GOOD">>, Req);
+			cowboy_req:stream_reply(<<"200 GOOD">>, Req0);
 		<<"error">> ->
 			ct_helper:ignore(cowboy_req, stream_reply, 3),
-			cowboy_req:stream_reply(ok, Req);
+			cowboy_req:stream_reply(ok, Req0);
 		Status ->
-			cowboy_req:stream_reply(binary_to_integer(Status), Req)
+			cowboy_req:stream_reply(binary_to_integer(Status), Req0)
 	end,
 	stream_body(Req),
 	{ok, Req, Opts};
-do(<<"stream_reply3">>, Req, Opts) ->
-	case cowboy_req:binding(arg, Req) of
+do(<<"stream_reply3">>, Req0, Opts) ->
+	Req = case cowboy_req:binding(arg, Req0) of
 		<<"error">> ->
 			ct_helper:ignore(cowboy_req, stream_reply, 3),
-			cowboy_req:stream_reply(200, ok, Req);
+			cowboy_req:stream_reply(200, ok, Req0);
 		Status ->
 			cowboy_req:stream_reply(binary_to_integer(Status),
-				#{<<"content-type">> => <<"text/plain">>}, Req)
+				#{<<"content-type">> => <<"text/plain">>}, Req0)
 	end,
 	stream_body(Req),
 	{ok, Req, Opts};
@@ -150,8 +144,7 @@ do(<<"push">>, Req, Opts) ->
 			%% The text/plain mime is not defined by default, so a 406 will be returned.
 			cowboy_req:push("/static/plain.txt", #{<<"accept">> => <<"text/plain">>}, Req)
 	end,
-	cowboy_req:reply(200, Req),
-	{ok, Req, Opts}.
+	{ok, cowboy_req:reply(200, Req), Opts}.
 
 stream_body(Req) ->
 	_ = [cowboy_req:stream_body(<<0:800000>>, nofin, Req) || _ <- lists:seq(1,9)],