aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLoïc Hoguin <[email protected]>2019-01-05 22:30:10 +0100
committerLoïc Hoguin <[email protected]>2019-01-05 22:30:10 +0100
commit08c4a71c801246c66427f2a37d2f0f6de561d448 (patch)
treee12b21419c277692d44834e6b867a0f5c95d07b2
parentab72796fdcc30a1227cbdd9069bd36aff14ebcfc (diff)
downloadgun-08c4a71c801246c66427f2a37d2f0f6de561d448.tar.gz
gun-08c4a71c801246c66427f2a37d2f0f6de561d448.tar.bz2
gun-08c4a71c801246c66427f2a37d2f0f6de561d448.zip
Fix transfer-encoding precedence over content-length
-rw-r--r--src/gun_http.erl28
-rw-r--r--test/rfc7230_SUITE.erl26
2 files changed, 39 insertions, 15 deletions
diff --git a/src/gun_http.erl b/src/gun_http.erl
index 164ede8..ec459a3 100644
--- a/src/gun_http.erl
+++ b/src/gun_http.erl
@@ -522,22 +522,20 @@ response_io_from_headers(<<"HEAD">>, _, _, _) ->
response_io_from_headers(_, _, Status, _) when (Status =:= 204) or (Status =:= 304) ->
head;
response_io_from_headers(_, Version, _Status, Headers) ->
- case lists:keyfind(<<"content-length">>, 1, Headers) of
- {_, <<"0">>} ->
- head;
- {_, Length} ->
- {body, cow_http_hd:parse_content_length(Length)};
- _ when Version =:= 'HTTP/1.0' ->
- body_close;
+ case lists:keyfind(<<"transfer-encoding">>, 1, Headers) of
+ {_, TE} when Version =:= 'HTTP/1.1' ->
+ case cow_http_hd:parse_transfer_encoding(TE) of
+ [<<"chunked">>] -> body_chunked;
+ [<<"identity">>] -> body_close
+ end;
_ ->
- case lists:keyfind(<<"transfer-encoding">>, 1, Headers) of
- false ->
- body_close;
- {_, TE} ->
- case cow_http_hd:parse_transfer_encoding(TE) of
- [<<"chunked">>] -> body_chunked;
- [<<"identity">>] -> body_close
- end
+ case lists:keyfind(<<"content-length">>, 1, Headers) of
+ {_, <<"0">>} ->
+ head;
+ {_, Length} ->
+ {body, cow_http_hd:parse_content_length(Length)};
+ _ ->
+ body_close
end
end.
diff --git a/test/rfc7230_SUITE.erl b/test/rfc7230_SUITE.erl
index c7aa63d..07d6b13 100644
--- a/test/rfc7230_SUITE.erl
+++ b/test/rfc7230_SUITE.erl
@@ -18,6 +18,7 @@
-import(ct_helper, [doc/1]).
-import(gun_test, [init_origin/2]).
+-import(gun_test, [init_origin/3]).
-import(gun_test, [receive_from/1]).
all() ->
@@ -56,3 +57,28 @@ do_host_port(Transport, DefaultPort, HostHeaderPort) ->
[<<"host: localhost", Rest/bits>>] = [L || <<"host: ", _/bits>> = L <- Lines],
HostHeaderPort = Rest,
gun:close(ConnPid).
+
+transfer_encoding_overrides_content_length(_) ->
+ doc("When both transfer-encoding and content-length are provided, "
+ "content-length must be ignored. (RFC7230 3.3.3)"),
+ {ok, _, OriginPort} = init_origin(tcp, http,
+ fun(_, ClientSocket, ClientTransport) ->
+ {ok, _} = ClientTransport:recv(ClientSocket, 0, 1000),
+ ClientTransport:send(ClientSocket,
+ "HTTP/1.1 200 OK\r\n"
+ "content-length: 12\r\n"
+ "transfer-encoding: chunked\r\n"
+ "\r\n"
+ "6\r\n"
+ "hello \r\n"
+ "6\r\n"
+ "world!\r\n"
+ "0\r\n\r\n"
+ )
+ end),
+ {ok, ConnPid} = gun:open("localhost", OriginPort),
+ {ok, http} = gun:await_up(ConnPid),
+ StreamRef = gun:get(ConnPid, "/"),
+ {response, nofin, 200, _} = gun:await(ConnPid, StreamRef),
+ {ok, <<"hello world!">>} = gun:await_body(ConnPid, StreamRef),
+ gun:close(ConnPid).