diff --git a/lib/mint/http.ex b/lib/mint/http.ex index 4283f1c4..639fff5c 100644 --- a/lib/mint/http.ex +++ b/lib/mint/http.ex @@ -903,6 +903,9 @@ defmodule Mint.HTTP do Contrary to `recv/3`, this function does not return partial responses on errors. Use `recv/3` for full control. + This function only handles responses for the given `request_ref`. Do not use it when making + concurrent requests as responses other than for `request_ref` are ignored. + ## Examples iex> {:ok, conn} = Mint.HTTP.connect(:https, "httpbin.org", 443, mode: :passive) @@ -922,9 +925,9 @@ defmodule Mint.HTTP do headers: [{binary(), binary()}], body: binary() } - def recv_response(conn, ref, timeout) - when is_reference(ref) and Util.is_timeout(timeout) do - recv_response([], {nil, [], ""}, conn, ref, timeout) + def recv_response(conn, request_ref, timeout) + when is_reference(request_ref) and Util.is_timeout(timeout) do + recv_response([], {nil, [], ""}, conn, request_ref, timeout) end defp recv_response( diff --git a/test/mint/http1/conn_test.exs b/test/mint/http1/conn_test.exs index 7d646459..507110f5 100644 --- a/test/mint/http1/conn_test.exs +++ b/test/mint/http1/conn_test.exs @@ -482,6 +482,32 @@ defmodule Mint.HTTP1Test do } end + test "handles trailers", %{port: port, server_ref: server_ref} do + assert {:ok, conn} = HTTP1.connect(:http, "localhost", port, mode: :passive) + assert_receive {^server_ref, server_socket} + + {:ok, conn, ref} = HTTP1.request(conn, "GET", "/", [], nil) + + :ok = :gen_tcp.send(server_socket, "HTTP/1.1 200 OK\r\n") + :ok = :gen_tcp.send(server_socket, "transfer-encoding: chunked\r\n") + :ok = :gen_tcp.send(server_socket, "trailer: x-trailer\r\n\r\n") + :ok = :gen_tcp.send(server_socket, "5\r\nhello\r\n") + :ok = :gen_tcp.send(server_socket, "5\r\nworld\r\n0\r\n") + :ok = :gen_tcp.send(server_socket, "x-trailer: foo\r\n\r\n") + + assert {:ok, _conn, response} = Mint.HTTP.recv_response(conn, ref, 100) + + assert response == %{ + body: "helloworld", + headers: [ + {"transfer-encoding", "chunked"}, + {"trailer", "x-trailer"}, + {"x-trailer", "foo"} + ], + status: 200 + } + end + test "handles errors", %{port: port, server_ref: server_ref} do assert {:ok, conn} = HTTP1.connect(:http, "localhost", port, mode: :passive) assert_receive {^server_ref, server_socket} diff --git a/test/mint/http2/conn_test.exs b/test/mint/http2/conn_test.exs index a948e166..212d165b 100644 --- a/test/mint/http2/conn_test.exs +++ b/test/mint/http2/conn_test.exs @@ -2206,6 +2206,55 @@ defmodule Mint.HTTP2Test do assert HTTP2.open?(conn) end + test "handles trailers", %{conn: conn} do + {conn, ref} = open_request(conn) + + assert_recv_frames [headers(stream_id: stream_id)] + + <> = + server_encode_headers([{"x-trailer", "foo"}]) + + data = + server_encode_frames([ + headers( + stream_id: stream_id, + hbf: + server_encode_headers([ + {":status", "200"}, + {"content-type", "text/plain"} + ]), + flags: set_flags(:headers, [:end_headers]) + ), + data( + stream_id: stream_id, + data: "helloworld", + flags: set_flags(:data, []) + ), + headers( + stream_id: stream_id, + hbf: trailer_hbf1, + flags: set_flags(:headers, [:end_stream]) + ), + continuation( + stream_id: stream_id, + hbf: trailer_hbf2, + flags: set_flags(:continuation, [:end_headers]) + ) + ]) + + :ok = :ssl.send(server_get_socket(), data) + + assert {:ok, _conn, response} = Mint.HTTP.recv_response(conn, ref, 100) + + assert response == %{ + body: "helloworld", + headers: [{"content-type", "text/plain"}, {"x-trailer", "foo"}], + status: 200 + } + + assert HTTP2.open?(conn) + end + test "handles errors", %{conn: conn} do {conn, ref} = open_request(conn) assert_recv_frames [headers(stream_id: _stream_id)]