diff options
author | Loïc Hoguin <[email protected]> | 2019-01-05 22:30:10 +0100 |
---|---|---|
committer | Loïc Hoguin <[email protected]> | 2019-01-05 22:30:10 +0100 |
commit | 08c4a71c801246c66427f2a37d2f0f6de561d448 (patch) | |
tree | e12b21419c277692d44834e6b867a0f5c95d07b2 | |
parent | ab72796fdcc30a1227cbdd9069bd36aff14ebcfc (diff) | |
download | gun-08c4a71c801246c66427f2a37d2f0f6de561d448.tar.gz gun-08c4a71c801246c66427f2a37d2f0f6de561d448.tar.bz2 gun-08c4a71c801246c66427f2a37d2f0f6de561d448.zip |
Fix transfer-encoding precedence over content-length
-rw-r--r-- | src/gun_http.erl | 28 | ||||
-rw-r--r-- | test/rfc7230_SUITE.erl | 26 |
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). |