Skip to content

Commit 5e3fe5f

Browse files
committed
support arbitrarily large request sizes in mint client
1 parent 2cecb5a commit 5e3fe5f

File tree

1 file changed

+64
-45
lines changed

1 file changed

+64
-45
lines changed

Diff for: lib/arangox/client/mint.ex

+64-45
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ if Code.ensure_compiled(Mint.HTTP) == {:module, Mint.HTTP} do
1111
[__Documentation__](https://hexdocs.pm/mint/Mint.HTTP.html)
1212
"""
1313

14-
alias Mint.HTTP
14+
alias Mint.HTTP1, as: Mint
1515

1616
alias Arangox.{
1717
Client,
@@ -41,7 +41,7 @@ if Code.ensure_compiled(Mint.HTTP) == {:module, Mint.HTTP} do
4141

4242
with(
4343
{:ok, conn} <- open(addr, ssl?, options),
44-
true <- HTTP.open?(conn)
44+
true <- Mint.open?(conn)
4545
) do
4646
{:ok, conn}
4747
else
@@ -62,62 +62,81 @@ if Code.ensure_compiled(Mint.HTTP) == {:module, Mint.HTTP} do
6262
defp open({:tcp, host, port}, ssl?, options) do
6363
scheme = if ssl?, do: :https, else: :http
6464

65-
HTTP.connect(scheme, host, port, options)
65+
Mint.connect(scheme, host, port, options)
6666
end
6767

6868
@impl true
69-
def request(%Request{} = request, %Connection{} = state) do
69+
def request(
70+
%Request{method: method, path: path, headers: headers, body: body},
71+
%Connection{socket: socket} = state
72+
) do
7073
{:ok, conn, ref} =
71-
HTTP.request(
72-
state.socket,
73-
request.method |> Atom.to_string() |> String.upcase(),
74-
request.path,
75-
Enum.into(request.headers, [], fn {k, v} -> {k, v} end),
76-
request.body
74+
Mint.request(
75+
socket,
76+
method
77+
|> to_string()
78+
|> String.upcase(),
79+
path,
80+
Enum.into(headers, []),
81+
body
7782
)
7883

79-
{new_conn, result} =
80-
case HTTP.recv(conn, 0, :infinity) do
81-
{:ok, new_conn, stream} ->
82-
{new_conn, stream}
83-
84-
{:error, new_conn, exception, _stream} ->
85-
{new_conn, exception}
86-
end
87-
88-
new_state = %{state | socket: new_conn}
89-
90-
if alive?(new_state) do
91-
case result do
92-
[
93-
{:status, ^ref, status},
94-
{:headers, ^ref, headers},
95-
{:done, ^ref}
96-
] ->
97-
{:ok, %Response{status: status, headers: Map.new(headers)}, new_state}
98-
99-
[
100-
{:status, ^ref, status},
101-
{:headers, ^ref, headers},
102-
{:data, ^ref, body},
103-
{:done, ^ref}
104-
] ->
105-
{:ok, %Response{status: status, headers: Map.new(headers), body: body}, new_state}
106-
107-
%_{} = exception ->
108-
{:error, exception, new_state}
109-
end
110-
else
111-
{:error, :noproc, new_state}
84+
case do_recv(conn, ref) do
85+
{:ok, new_conn, buffer} ->
86+
do_response(ref, buffer, %{state | socket: new_conn})
87+
88+
{:error, %_{state: :closed} = new_conn, _, ^ref} ->
89+
{:error, :noproc, %{state | socket: new_conn}}
90+
91+
{:error, new_conn, exception, ^ref} ->
92+
{:error, exception, %{state | socket: new_conn}}
93+
end
94+
end
95+
96+
def do_recv(conn, ref, buffer \\ []) do
97+
case Mint.recv(conn, 0, :infinity) do
98+
{:ok, new_conn, next_buffer} ->
99+
if {:done, ref} in next_buffer do
100+
{:ok, new_conn, buffer ++ next_buffer}
101+
else
102+
do_recv(new_conn, ref, buffer ++ next_buffer)
103+
end
104+
105+
{:error, _, _, ^ref} = error ->
106+
error
107+
end
108+
end
109+
110+
def do_response(ref, buffer, state) do
111+
case buffer do
112+
[{:status, ^ref, status}, {:headers, ^ref, headers}, {:done, ^ref}] ->
113+
{:ok, %Response{status: status, headers: Map.new(headers)}, state}
114+
115+
[{:status, ^ref, status}, {:headers, ^ref, headers}, {:data, ^ref, body}, {:done, ^ref}] ->
116+
{:ok, %Response{status: status, headers: Map.new(headers), body: body}, state}
117+
118+
[{:status, ^ref, status}, {:headers, ^ref, headers} | rest_buffer] ->
119+
body =
120+
for kv <- rest_buffer, into: "" do
121+
case kv do
122+
{:data, ^ref, data} ->
123+
data
124+
125+
{:done, ^ref} ->
126+
""
127+
end
128+
end
129+
130+
{:ok, %Response{status: status, headers: Map.new(headers), body: body}, state}
112131
end
113132
end
114133

115134
@impl true
116-
def alive?(%Connection{socket: conn}), do: HTTP.open?(conn)
135+
def alive?(%Connection{socket: conn}), do: Mint.open?(conn)
117136

118137
@impl true
119138
def close(%Connection{socket: conn}) do
120-
HTTP.close(conn)
139+
Mint.close(conn)
121140

122141
:ok
123142
end

0 commit comments

Comments
 (0)