File 0821-inets-Fix-handling-of-HTTP-HEAD-requests-in-httpc.patch of Package erlang

From 04c35a6c7b8ff89a0973fdb8cc7deadeb900dc86 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A9ter=20Dimitrov?= <peterdmv@erlang.org>
Date: Fri, 15 Nov 2019 15:28:02 +0100
Subject: [PATCH] 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.
---
 lib/inets/src/http_client/httpc_handler.erl |  6 +--
 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])
@@ -1460,6 +1462,58 @@ send_response(Msg, Chunk, Socket) ->
     timer:sleep(250),
     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'"}].
-- 
2.16.4

openSUSE Build Service is sponsored by