diff options
author | Péter Dimitrov <peterdmv@erlang.org> | 2019-11-15 15:28:02 +0100 |
---|---|---|
committer | Péter Dimitrov <peterdmv@erlang.org> | 2019-11-21 17:00:24 +0100 |
commit | 04c35a6c7b8ff89a0973fdb8cc7deadeb900dc86 (patch) | |
tree | fd8818358ccab7cc993ac2a4a808a6aab1f5fdfb | |
parent | 0a1b3d9c1dff82d82ce78e4b4cd01acd1bbf2924 (diff) | |
download | erlang-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.erl | 6 | ||||
-rw-r--r-- | lib/inets/test/httpc_SUITE.erl | 58 |
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) -> |