aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKirilll Zaborsky <[email protected]>2015-01-20 21:06:13 +0300
committerHenrik Nord <[email protected]>2015-10-27 15:06:04 +0100
commitf4b02cf574552f40ff354261b4c7cf02cb568212 (patch)
treeb948511e61a644c248907c05363d140403dcd3d6
parent7dc9eefa341fbfae0ebc55a88b96a375c611e3a4 (diff)
downloadotp-f4b02cf574552f40ff354261b4c7cf02cb568212.tar.gz
otp-f4b02cf574552f40ff354261b4c7cf02cb568212.tar.bz2
otp-f4b02cf574552f40ff354261b4c7cf02cb568212.zip
inets: send correct nonstreamed response with streaming
httpc_handler should respond with correct and complete responses seeing non-streamed status codes i.e. codes other than 200 or 206.
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl28
-rw-r--r--lib/inets/test/httpc_SUITE.erl32
2 files changed, 46 insertions, 14 deletions
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index 6e6cc38c06..0300a80b03 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -163,7 +163,7 @@ info(Pid) ->
%% Request should not be streamed
stream(BodyPart, #request{stream = none} = Request, _) ->
?hcrt("stream - none", []),
- {BodyPart, Request};
+ {false, BodyPart, Request};
%% Stream to caller
stream(BodyPart, #request{stream = Self} = Request, Code)
@@ -172,7 +172,7 @@ stream(BodyPart, #request{stream = Self} = Request, Code)
?hcrt("stream - self", [{stream, Self}, {code, Code}]),
httpc_response:send(Request#request.from,
{Request#request.id, stream, BodyPart}),
- {<<>>, Request};
+ {true, <<>>, Request};
%% Stream to file
%% This has been moved to start_stream/3
@@ -194,14 +194,14 @@ stream(BodyPart, #request{stream = Fd} = Request, Code)
?hcrt("stream to file", [{stream, Fd}, {code, Code}]),
case file:write(Fd, BodyPart) of
ok ->
- {<<>>, Request};
+ {true, <<>>, Request};
{error, Reason} ->
exit({stream_to_file_failed, Reason})
end;
stream(BodyPart, Request,_) -> % only 200 and 206 responses can be streamed
?hcrt("stream - ignore", [{request, Request}]),
- {BodyPart, Request}.
+ {false, BodyPart, Request}.
%%====================================================================
@@ -474,14 +474,14 @@ handle_info({Proto, _Socket, Data},
{Module, whole_body, [Body, Length]} ->
?hcrd("data processed - whole body", [{length, Length}]),
{_, Code, _} = StatusLine,
- {NewBody, NewRequest} = stream(Body, Request, Code),
+ {Streamed, NewBody, NewRequest} = stream(Body, Request, Code),
%% When we stream we will not keep the already
%% streamed data, that would be a waste of memory.
NewLength =
- case Stream of
- none ->
+ case Streamed of
+ false ->
Length;
- _ ->
+ true ->
Length - size(Body)
end,
@@ -497,7 +497,7 @@ handle_info({Proto, _Socket, Data},
%% The response body is chunk-encoded. Steal decoded
%% chunks as much as possible to stream.
{_, Code, _} = StatusLine,
- {NewBody, NewRequest} = stream(BodySoFar, Request, Code),
+ {_, NewBody, NewRequest} = stream(BodySoFar, Request, Code),
NewState = next_body_chunk(State),
NewMFA = {Module, decode_size,
[TotalChunk, HexList,
@@ -517,7 +517,7 @@ handle_info({Proto, _Socket, Data},
NewChunkSize = ChunkSize - ChunkSizeToSteal,
{_, Code, _} = StatusLine,
- {NewBody, NewRequest} = stream(StolenBody, Request, Code),
+ {_, NewBody, NewRequest} = stream(StolenBody, Request, Code),
NewState = next_body_chunk(State),
NewMFA = {Module, decode_data,
[NewChunkSize, NewTotalChunk,
@@ -1071,13 +1071,13 @@ handle_http_msg({ChunkedHeaders, Body},
?hcrt("handle_http_msg",
[{chunked_headers, ChunkedHeaders}, {headers, Headers}]),
NewHeaders = http_chunk:handle_headers(Headers, ChunkedHeaders),
- {NewBody, NewRequest} = stream(Body, State#state.request, Code),
+ {_, NewBody, NewRequest} = stream(Body, State#state.request, Code),
handle_response(State#state{headers = NewHeaders,
body = NewBody,
request = NewRequest});
handle_http_msg(Body, #state{status_line = {_,Code, _}} = State) ->
?hcrt("handle_http_msg", [{code, Code}]),
- {NewBody, NewRequest} = stream(Body, State#state.request, Code),
+ {_, NewBody, NewRequest} = stream(Body, State#state.request, Code),
handle_response(State#state{body = NewBody, request = NewRequest}).
handle_http_body(_, #state{status = {ssl_tunnel, _},
@@ -1133,7 +1133,7 @@ handle_http_body(Body, #state{headers = Headers,
handle_response(State#state{headers = NewHeaders,
body = NewBody});
_ ->
- {NewBody2, _NewRequest} =
+ {_, NewBody2, _} =
stream(NewBody, Request, Code),
handle_response(State#state{headers = NewHeaders,
body = NewBody2})
@@ -1147,7 +1147,7 @@ handle_http_body(Body, #state{headers = Headers,
true ->
case httpc_response:whole_body(Body, Length) of
{ok, Body} ->
- {NewBody, NewRequest} =
+ {_, NewBody, NewRequest} =
stream(Body, Request, Code),
handle_response(State#state{body = NewBody,
request = NewRequest});
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 2ad00bdf76..cc0fa5d4d9 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -98,6 +98,7 @@ only_simulated() ->
stream_once,
stream_single_chunk,
stream_no_length,
+ stream_large_not_200_or_206,
no_content_204,
tolerate_missing_CR,
userinfo,
@@ -408,6 +409,13 @@ stream_no_length(Config) when is_list(Config) ->
stream_test(Request1, {stream, self}),
Request2 = {url(group_name(Config), "/http_1_0_no_length_multiple.html", Config), []},
stream_test(Request2, {stream, self}).
+%%-------------------------------------------------------------------------
+stream_large_not_200_or_206() ->
+ [{doc, "Test the option stream for large responses with status codes "
+ "other than 200 or 206" }].
+stream_large_not_200_or_206(Config) when is_list(Config) ->
+ Request = {url(group_name(Config), "/large_404_response.html", Config), []},
+ {{_,404,_}, _, _} = non_streamed_async_test(Request, {stream, self}).
%%-------------------------------------------------------------------------
@@ -1117,6 +1125,19 @@ stream_test(Request, To) ->
Body = binary_to_list(StreamedBody).
+non_streamed_async_test(Request, To) ->
+ {ok, Response} =
+ httpc:request(get, Request, [], [{body_format, binary}]),
+ {ok, RequestId} =
+ httpc:request(get, Request, [], [{sync, false}, To]),
+
+ receive
+ {http, {RequestId, Response}} ->
+ Response;
+ {http, Msg} ->
+ ct:fail(Msg)
+ end.
+
url(http, End, Config) ->
Port = ?config(port, Config),
{ok,Host} = inet:gethostname(),
@@ -1807,6 +1828,17 @@ handle_uri(_,"/http_1_0_no_length_multiple.html",_,_,Socket,_) ->
send(Socket, string:copies("other multiple packets ", 200)),
close(Socket);
+handle_uri(_,"/large_404_response.html",_,_,Socket,_) ->
+ %% long body to make sure it will be sent in multiple tcp packets
+ Body = string:copies("other multiple packets ", 200),
+ Head = io_lib:format("HTTP/1.1 404 not found\r\n"
+ "Content-length: ~B\r\n"
+ "Content-type: text/plain\r\n\r\n",
+ [length(Body)]),
+ send(Socket, Head),
+ send(Socket, Body),
+ close(Socket);
+
handle_uri(_,"/once.html",_,_,Socket,_) ->
Head = "HTTP/1.1 200 ok\r\n" ++
"Content-Length:32\r\n\r\n",