diff --git a/src/hackney_request.erl b/src/hackney_request.erl index b484ae4a..e6fc4f6e 100644 --- a/src/hackney_request.erl +++ b/src/hackney_request.erl @@ -86,8 +86,14 @@ perform(Client0, {Method0, Path0, Headers0, Body0}) -> %% get expect headers Expect = expectation(Headers2), + %% convert iolist body to binary + Body1 = case is_list(Body0) of + true -> iolist_to_binary(Body0); + false -> Body0 + end, + %% build headers with the body. - {FinalHeaders, ReqType, Body, Client1} = case Body0 of + {FinalHeaders, ReqType, Body, Client1} = case Body1 of stream -> {Headers2, ReqType0, stream, Client0}; stream_multipart -> @@ -98,15 +104,11 @@ perform(Client0, {Method0, Path0, Headers0, Body0}) -> handle_multipart_body(Headers2, ReqType0, Size, Boundary, Client0); <<>> when Method =:= <<"POST">> orelse Method =:= <<"PUT">> -> - handle_body(Headers2, ReqType0, Body0, Client0); - [] when Method =:= <<"POST">> orelse Method =:= <<"PUT">> -> - handle_body(Headers2, ReqType0, Body0, Client0); + handle_body(Headers2, ReqType0, Body1, Client0); <<>> -> - {Headers2, ReqType0, Body0, Client0}; - [] -> - {Headers2, ReqType0, Body0, Client0}; + {Headers2, ReqType0, Body1, Client0}; _ -> - handle_body(Headers2, ReqType0, Body0, Client0) + handle_body(Headers2, ReqType0, Body1, Client0) end, %% build final client record @@ -370,13 +372,6 @@ handle_body(Headers, ReqType0, Body0, Client) -> S = hackney_headers_new:get_value(<<"content-length">>, Headers), {S, CT, Body0}; - _ when is_list(Body0) -> % iolist case - Body1 = iolist_to_binary(Body0), - S = erlang:byte_size(Body1), - CT = hackney_headers_new:get_value( - <<"content-type">>, Headers, <<"application/octet-stream">> - ), - {S, CT, Body1}; _ when is_binary(Body0) -> S = erlang:byte_size(Body0), CT = hackney_headers_new:get_value( diff --git a/test/hackney_integration_tests.erl b/test/hackney_integration_tests.erl index 00bac33c..aa6e151d 100644 --- a/test/hackney_integration_tests.erl +++ b/test/hackney_integration_tests.erl @@ -20,6 +20,10 @@ all_tests() -> % fun relative_redirect_request_no_follow/0, fun relative_redirect_request_follow/0, fun test_duplicate_headers/0, + fun test_post_includes_content_headers_with_body/0, + fun test_post_includes_content_headers_with_empty_body/0, + fun test_get_includes_content_headers_with_body/0, + fun test_get_excludes_content_headers_with_empty_body/0, fun test_custom_host_headers/0, fun async_request/0, fun async_head_request/0, @@ -186,6 +190,48 @@ test_custom_host_headers() -> ReqHeaders = proplists:get_value(<<"headers">>, Obj), ?assertEqual(<<"myhost.com">>, proplists:get_value(<<"Host">>, ReqHeaders)). +test_post_includes_content_headers_with_body() -> + URL = <<"http://localhost:8000/post">>, + Body = <<"{\"test\": \"ok\" }">>, + Options = [with_body], + {ok, 200, _H, JsonBody} = hackney:post(URL, [], Body, Options), + Obj = jsone:decode(JsonBody, [{object_format, proplist}]), + ReqHeaders = proplists:get_value(<<"headers">>, Obj), + ?assertEqual(<<"15">>, proplists:get_value(<<"Content-Length">>, ReqHeaders)), + ?assertEqual(<<"application/octet-stream">>, proplists:get_value(<<"Content-Type">>, ReqHeaders)). + +test_post_includes_content_headers_with_empty_body() -> + URL = <<"http://localhost:8000/post">>, + Body = <<>>, + Options = [with_body], + {ok, 200, _H, JsonBody} = hackney:post(URL, [], Body, Options), + Obj = jsone:decode(JsonBody, [{object_format, proplist}]), + ReqHeaders = proplists:get_value(<<"headers">>, Obj), + ?assertEqual(<<"0">>, proplists:get_value(<<"Content-Length">>, ReqHeaders)), + ?assertEqual(<<"application/octet-stream">>, proplists:get_value(<<"Content-Type">>, ReqHeaders)). + +test_get_includes_content_headers_with_body() -> + URL = <<"http://localhost:8000/get">>, + Body = <<"{\"test\": \"ok\" }">>, + Options = [with_body], + {ok, 200, _H, JsonBody} = hackney:get(URL, [], Body, Options), + Obj = jsone:decode(JsonBody, [{object_format, proplist}]), + ReqHeaders = proplists:get_value(<<"headers">>, Obj), + ?assertEqual(<<"15">>, proplists:get_value(<<"Content-Length">>, ReqHeaders)), + ?assertEqual(<<"application/octet-stream">>, proplists:get_value(<<"Content-Type">>, ReqHeaders)). + +test_get_excludes_content_headers_with_empty_body() -> + URL = <<"http://localhost:8000/get">>, + EmptyBodies = [<<>>, [], [<<>>]], + Options = [with_body], + lists:foreach(fun(Body) -> + {ok, 200, _H, JsonBody} = hackney:get(URL, [], Body, Options), + Obj = jsone:decode(JsonBody, [{object_format, proplist}]), + ReqHeaders = proplists:get_value(<<"headers">>, Obj), + ?assertEqual(undefined, proplists:get_value(<<"Content-Type">>, ReqHeaders)), + ?assertEqual(undefined, proplists:get_value(<<"Content-Length">>, ReqHeaders)) + end, EmptyBodies). + test_frees_manager_ets_when_body_is_in_client() -> URL = <<"http://localhost:8000/get">>, BeforeCount = ets:info(hackney_manager_refs, size),