Skip to content

Commit 2549e1f

Browse files
committed
Add Mint.HTTP1.recv_response/3,5
1 parent 50b11d6 commit 2549e1f

File tree

2 files changed

+159
-1
lines changed

2 files changed

+159
-1
lines changed

lib/mint/http1.ex

Lines changed: 130 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -529,6 +529,136 @@ defmodule Mint.HTTP1 do
529529
"Use Mint.HTTP.set_mode/2 to set the connection to passive mode"
530530
end
531531

532+
@doc """
533+
TODO
534+
535+
## Examples
536+
537+
iex> {:ok, conn} = Mint.HTTP1.connect(:https, "httpbin.org", 443, mode: :passive)
538+
iex> {:ok, conn, ref} = Mint.HTTP1.request(conn, "GET", "/status/user-agent", [], nil)
539+
iex> {:ok, _conn, response} = Mint.HTTP1.recv_response(conn, ref, 5000)
540+
iex> response
541+
%{
542+
status: 201,
543+
headers: [
544+
{"date", ...},
545+
...
546+
],
547+
body: "{\\n \\"user-agent\\": \\"mint/1.6.2\\"\\n}\\n"
548+
}
549+
"""
550+
def recv_response(conn, ref, timeout) do
551+
recv_response(conn, ref, timeout, %{status: nil, headers: [], body: ""}, fn
552+
conn, {:status, status}, acc ->
553+
{:cont, conn, %{acc | status: status}}
554+
555+
conn, {:headers, headers}, acc ->
556+
{:cont, conn, update_in(acc.headers, &(&1 ++ headers))}
557+
558+
conn, {:data, data}, acc ->
559+
{:cont, conn, update_in(acc.body, &(&1 <> data))}
560+
561+
conn, :done, acc ->
562+
{:cont, conn, acc}
563+
end)
564+
end
565+
566+
@doc """
567+
TODO
568+
569+
## Examples
570+
571+
iex> {:ok, conn} = Mint.HTTP1.connect(:https, "httpbin.org", 443, mode: :passive)
572+
iex> {:ok, conn, ref} = Mint.HTTP1.request(conn, "GET", "/user-agent", [], nil)
573+
iex> {:ok, _conn, _acc} =
574+
...> Mint.HTTP1.recv_response(conn, ref, 5000, nil, fn
575+
...> conn, entry, acc ->
576+
...> IO.inspect(entry)
577+
...> {:cont, conn, acc}
578+
...> end)
579+
580+
Outputs:
581+
582+
{:status, 201}
583+
{:headers, [{"date", ...}, ...]}
584+
{:data, "{\\n \\"user-agent\\": \\"mint/1.6.2\\"\\n}\\n"}
585+
:done
586+
"""
587+
def recv_response(conn, ref, timeout, acc, fun) do
588+
recv_response([], acc, fun, conn, ref, timeout)
589+
end
590+
591+
defp recv_response([{:status, ref, status} | rest], acc, fun, conn, ref, timeout) do
592+
case fun.(conn, {:status, status}, acc) do
593+
{:cont, conn, acc} ->
594+
recv_response(rest, acc, fun, conn, ref, timeout)
595+
596+
{:halt, conn, acc} ->
597+
{:ok, conn, acc}
598+
599+
other ->
600+
raise ArgumentError,
601+
"expected {:cont, conn, acc} or {:halt, conn, acc}, got: #{inspect(other)}"
602+
end
603+
end
604+
605+
defp recv_response([{:headers, ref, headers} | rest], acc, fun, conn, ref, timeout) do
606+
case fun.(conn, {:headers, headers}, acc) do
607+
{:cont, conn, acc} ->
608+
recv_response(rest, acc, fun, conn, ref, timeout)
609+
610+
{:halt, conn, acc} ->
611+
{:ok, conn, acc}
612+
613+
other ->
614+
raise ArgumentError,
615+
"expected {:cont, conn, acc} or {:halt, conn, acc}, got: #{inspect(other)}"
616+
end
617+
end
618+
619+
defp recv_response([{:data, ref, data} | rest], acc, fun, conn, ref, timeout) do
620+
case fun.(conn, {:data, data}, acc) do
621+
{:cont, conn, acc} ->
622+
recv_response(rest, acc, fun, conn, ref, timeout)
623+
624+
{:halt, conn, acc} ->
625+
{:ok, conn, acc}
626+
627+
other ->
628+
raise ArgumentError,
629+
"expected {:cont, conn, acc} or {:halt, conn, acc}, got: #{inspect(other)}"
630+
end
631+
end
632+
633+
defp recv_response([{:done, ref} | _], acc, fun, conn, ref, _timeout) do
634+
case fun.(conn, :done, acc) do
635+
{:cont, conn, acc} ->
636+
{:ok, conn, acc}
637+
638+
{:halt, conn, acc} ->
639+
{:ok, conn, acc}
640+
641+
other ->
642+
raise ArgumentError,
643+
"expected {:cont, conn, acc} or {:halt, conn, acc}, got: #{inspect(other)}"
644+
end
645+
end
646+
647+
defp recv_response([], acc, fun, conn, ref, timeout) do
648+
start_time = System.monotonic_time(:millisecond)
649+
650+
with {:ok, conn, entries} <- recv(conn, 0, timeout) do
651+
timeout =
652+
if is_integer(timeout) do
653+
timeout - System.monotonic_time(:millisecond) - start_time
654+
else
655+
timeout
656+
end
657+
658+
recv_response(entries, acc, fun, conn, ref, timeout)
659+
end
660+
end
661+
532662
@doc """
533663
See `Mint.HTTP.set_mode/2`.
534664
"""

test/mint/http1/conn_test.exs

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,37 @@ defmodule Mint.HTTP1Test do
55

66
require Mint.HTTP
77

8+
test "foo" do
9+
{:ok, _} =
10+
Bandit.start_link(
11+
port: 4000,
12+
plug: fn conn, _ ->
13+
Plug.Conn.send_resp(conn, 200, "hi")
14+
end,
15+
startup_log: false
16+
)
17+
18+
{:ok, conn} = HTTP1.connect(:http, "localhost", 4000, mode: :passive)
19+
{:ok, conn, ref} = HTTP1.request(conn, "GET", "/", [], nil)
20+
{:ok, conn, response} = HTTP1.recv_response(conn, ref, 5000)
21+
22+
assert %{
23+
status: 200,
24+
headers: [
25+
{"date", _},
26+
{"content-length", "2"},
27+
{"vary", "accept-encoding"},
28+
{"cache-control", "max-age=0, private, must-revalidate"}
29+
],
30+
body: "hi"
31+
} = response
32+
33+
assert HTTP1.open?(conn)
34+
end
35+
836
setup do
937
{:ok, port, server_ref} = TestServer.start()
10-
assert {:ok, conn} = HTTP1.connect(:http, "localhost", port)
38+
assert {:ok, conn} = HTTP1.connect(:http, "localhost", port, mode: :passive)
1139
assert_receive {^server_ref, server_socket}
1240

1341
[conn: conn, port: port, server_ref: server_ref, server_socket: server_socket]

0 commit comments

Comments
 (0)