diff options
-rw-r--r-- | src/gun.erl | 7 | ||||
-rw-r--r-- | test/gun_SUITE.erl | 58 | ||||
-rw-r--r-- | test/gun_test.erl | 11 |
3 files changed, 65 insertions, 11 deletions
diff --git a/src/gun.erl b/src/gun.erl index a8b76f8..55e70dd 100644 --- a/src/gun.erl +++ b/src/gun.erl @@ -436,7 +436,12 @@ request(ServerPid, Method, Path, Headers, Body, ReqOpts) -> -spec data(pid(), reference(), fin | nofin, iodata()) -> ok. data(ServerPid, StreamRef, IsFin, Data) -> - gen_statem:cast(ServerPid, {data, self(), StreamRef, IsFin, Data}). + case iolist_size(Data) of + 0 when IsFin =:= nofin -> + ok; + _ -> + gen_statem:cast(ServerPid, {data, self(), StreamRef, IsFin, Data}) + end. %% Tunneling. diff --git a/test/gun_SUITE.erl b/test/gun_SUITE.erl index a7bb0f1..ba5b523 100644 --- a/test/gun_SUITE.erl +++ b/test/gun_SUITE.erl @@ -18,7 +18,9 @@ -import(ct_helper, [doc/1]). -import(ct_helper, [name/0]). +-import(gun_test, [init_origin/2]). -import(gun_test, [init_origin/3]). +-import(gun_test, [receive_all_from/2]). all() -> ct_helper:all(?MODULE). @@ -107,16 +109,41 @@ detect_owner_gone_ws(_) -> end, cowboy:stop_listener(Name). -shutdown_reason(_) -> - doc("The last connection failure must be propagated."), - {ok, Pid} = gun:open("localhost", 12345, #{retry => 0}), - Ref = monitor(process, Pid), - receive - {'DOWN', Ref, process, Pid, {shutdown, econnrefused}} -> - ok - after 200 -> - error(timeout) - end. +ignore_empty_data_http(_) -> + doc("When gun:data/4 is called with nofin and empty data, it must be ignored."), + {ok, OriginPid, OriginPort} = init_origin(tcp, http), + {ok, Pid} = gun:open("localhost", OriginPort), + {ok, http} = gun:await_up(Pid), + Ref = gun:put(Pid, "/", []), + gun:data(Pid, Ref, nofin, "hello "), + gun:data(Pid, Ref, nofin, ["", <<>>]), + gun:data(Pid, Ref, fin, "world!"), + Data = receive_all_from(OriginPid, 500), + Lines = binary:split(Data, <<"\r\n">>, [global]), + Zero = [Z || <<"0">> = Z <- Lines], + 1 = length(Zero), + gun:close(Pid). + +ignore_empty_data_http2(_) -> + doc("When gun:data/4 is called with nofin and empty data, it must be ignored."), + {ok, OriginPid, OriginPort} = init_origin(tcp, http2), + {ok, Pid} = gun:open("localhost", OriginPort, #{protocols => [http2]}), + {ok, http2} = gun:await_up(Pid), + timer:sleep(100), %% Give enough time for the handshake to fully complete. + Ref = gun:put(Pid, "/", []), + gun:data(Pid, Ref, nofin, "hello "), + gun:data(Pid, Ref, nofin, ["", <<>>]), + gun:data(Pid, Ref, fin, "world!"), + Data = receive_all_from(OriginPid, 500), + << + %% HEADERS frame. + Len1:24, 1, _:40, _:Len1/unit:8, + %% First DATA frame. + 6:24, 0, _:7, 0:1, _:32, "hello ", + %% Second and final DATA frame. + 6:24, 0, _:7, 1:1, _:32, "world!" + >> = Data, + gun:close(Pid). info(_) -> doc("Get info from the Gun connection."), @@ -261,6 +288,17 @@ retry_timeout(_) -> error(shutdown_too_late) end. +shutdown_reason(_) -> + doc("The last connection failure must be propagated."), + {ok, Pid} = gun:open("localhost", 12345, #{retry => 0}), + Ref = monitor(process, Pid), + receive + {'DOWN', Ref, process, Pid, {shutdown, econnrefused}} -> + ok + after 200 -> + error(timeout) + end. + transform_header_name(_) -> doc("The transform_header_name option allows changing the case of header names."), {ok, ListenSocket} = gen_tcp:listen(0, [binary, {active, false}]), diff --git a/test/gun_test.erl b/test/gun_test.erl index 14c70c3..e74fcd0 100644 --- a/test/gun_test.erl +++ b/test/gun_test.erl @@ -106,3 +106,14 @@ receive_from(Pid, Timeout) -> after Timeout -> error(timeout) end. + +receive_all_from(Pid, Timeout) -> + receive_all_from(Pid, Timeout, <<>>). + +receive_all_from(Pid, Timeout, Acc) -> + try + More = receive_from(Pid, Timeout), + receive_all_from(Pid, Timeout, <<Acc/binary, More/binary>>) + catch error:timeout -> + Acc + end. |