summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPéter Dimitrov <peterdmv@erlang.org>2019-11-15 15:28:02 +0100
committerPéter Dimitrov <peterdmv@erlang.org>2019-11-21 17:00:24 +0100
commit04c35a6c7b8ff89a0973fdb8cc7deadeb900dc86 (patch)
treefd8818358ccab7cc993ac2a4a808a6aab1f5fdfb
parent0a1b3d9c1dff82d82ce78e4b4cd01acd1bbf2924 (diff)
downloaderlang-04c35a6c7b8ff89a0973fdb8cc7deadeb900dc86.tar.gz
inets: Fix handling of HTTP HEAD requests in httpc
httpc could not handle HEAD requests when the response contained the header 'Transfer-Encoding: chunked' and no message-body. According to RFC2616 a server MUST NOT return a message-body in the response. This commit fixes httpc while preserving its robust behavior to gracefully handle a faulty response with chunked-encoded empty message-body.
-rw-r--r--lib/inets/src/http_client/httpc_handler.erl6
-rw-r--r--lib/inets/test/httpc_SUITE.erl58
2 files changed, 58 insertions, 6 deletions
diff --git a/lib/inets/src/http_client/httpc_handler.erl b/lib/inets/src/http_client/httpc_handler.erl
index 8d443a1477..b1c5cf13bb 100644
--- a/lib/inets/src/http_client/httpc_handler.erl
+++ b/lib/inets/src/http_client/httpc_handler.erl
@@ -598,7 +598,7 @@ do_handle_info({Proto, Socket, Data},
"~n",
[Proto, Socket, Data, MFA,
Request, Session, Status, StatusLine, Profile]),
-
+ activate_once(Session),
{noreply, State};
%% The Server may close the connection to indicate that the
@@ -975,9 +975,7 @@ handle_http_body(<<>>, #state{headers = Headers,
handle_response(State#state{body = <<>>});
-handle_http_body(<<>>, #state{headers = Headers,
- request = #request{method = head}} = State)
- when Headers#http_response_h.'transfer-encoding' =/= "chunked" ->
+handle_http_body(<<>>, #state{request = #request{method = head}} = State) ->
handle_response(State#state{body = <<>>});
handle_http_body(Body, #state{headers = Headers,
diff --git a/lib/inets/test/httpc_SUITE.erl b/lib/inets/test/httpc_SUITE.erl
index 04340654e1..8c9bbbe831 100644
--- a/lib/inets/test/httpc_SUITE.erl
+++ b/lib/inets/test/httpc_SUITE.erl
@@ -174,6 +174,8 @@ misc() ->
timeout_memory_leak,
wait_for_whole_response,
post_204_chunked,
+ head_chunked_empty_body,
+ head_empty_body,
chunkify_fun
].
@@ -1423,7 +1425,7 @@ post_204_chunked(_Config) ->
{ok, ListenSocket} = gen_tcp:listen(0, [{active,once}, binary]),
{ok,{_,Port}} = inet:sockname(ListenSocket),
spawn(fun () -> custom_server(Msg, Chunk, ListenSocket,
- fun post_204_receive/0) end),
+ fun custom_receive/0) end),
{ok,Host} = inet:gethostname(),
End = "/cgi-bin/erl/httpd_example:post_204",
@@ -1433,7 +1435,7 @@ post_204_chunked(_Config) ->
%% Second request times out in the faulty case.
{ok, _} = httpc:request(post, {URL, [], "text/html", []}, [], []).
-post_204_receive() ->
+custom_receive() ->
receive
{tcp, _, Msg} ->
ct:log("Message received: ~p", [Msg])
@@ -1461,6 +1463,58 @@ send_response(Msg, Chunk, Socket) ->
gen_tcp:send(Socket, Chunk).
%%--------------------------------------------------------------------
+head_chunked_empty_body() ->
+ [{doc,"Test that HTTP responses (to HEAD requests) with 'Transfer-Encoding: chunked' and empty chunked-encoded body do not freeze the http client"}].
+head_chunked_empty_body(_Config) ->
+ Msg = "HTTP/1.1 403 Forbidden\r\n" ++
+ "Date: Thu, 23 Aug 2018 13:36:29 GMT\r\n" ++
+ "Content-Type: text/html\r\n" ++
+ "Server: inets/6.5.2.3\r\n" ++
+ "Cache-Control: no-cache\r\n" ++
+ "Pragma: no-cache\r\n" ++
+ "Expires: Fri, 24 Aug 2018 07:49:35 GMT\r\n" ++
+ "Transfer-Encoding: chunked\r\n" ++
+ "\r\n",
+ Chunk = "0\r\n\r\n",
+
+ {ok, ListenSocket} = gen_tcp:listen(0, [{active,once}, binary]),
+ {ok,{_,Port}} = inet:sockname(ListenSocket),
+ spawn(fun () -> custom_server(Msg, Chunk, ListenSocket,
+ fun custom_receive/0) end),
+ {ok,Host} = inet:gethostname(),
+ URL = ?URL_START ++ Host ++ ":" ++ integer_to_list(Port),
+ {ok, _} = httpc:request(head, {URL, []}, [], []),
+ timer:sleep(500),
+ %% Second request times out in the faulty case.
+ {ok, _} = httpc:request(head, {URL, []}, [], []).
+
+%%--------------------------------------------------------------------
+head_empty_body() ->
+ [{doc,"Test that HTTP responses (to HEAD requests) with 'Transfer-Encoding: chunked' and empty body do not freeze the http client"}].
+head_empty_body(_Config) ->
+ Msg = "HTTP/1.1 403 Forbidden\r\n" ++
+ "Date: Thu, 23 Aug 2018 13:36:29 GMT\r\n" ++
+ "Content-Type: text/html\r\n" ++
+ "Server: inets/6.5.2.3\r\n" ++
+ "Cache-Control: no-cache\r\n" ++
+ "Pragma: no-cache\r\n" ++
+ "Expires: Fri, 24 Aug 2018 07:49:35 GMT\r\n" ++
+ "Transfer-Encoding: chunked\r\n" ++
+ "\r\n",
+ NoChunk = "", %% Do not chunk encode!
+
+ {ok, ListenSocket} = gen_tcp:listen(0, [{active,once}, binary]),
+ {ok,{_,Port}} = inet:sockname(ListenSocket),
+ spawn(fun () -> custom_server(Msg, NoChunk, ListenSocket,
+ fun custom_receive/0) end),
+ {ok,Host} = inet:gethostname(),
+ URL = ?URL_START ++ Host ++ ":" ++ integer_to_list(Port),
+ {ok, _} = httpc:request(head, {URL, []}, [], []),
+ timer:sleep(500),
+ %% Second request times out in the faulty case.
+ {ok, _} = httpc:request(head, {URL, []}, [], []).
+
+%%--------------------------------------------------------------------
chunkify_fun() ->
[{doc,"Test that a chunked encoded request does not include the 'Content-Length header'"}].
chunkify_fun(_Config) ->