Packages
tesla
1.13.2
1.20.0
1.18.3
1.18.2
1.18.1
1.18.0
1.17.0
1.16.0
1.15.3
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.1
1.14.0
1.13.2
1.13.1
1.13.0
1.12.3
1.12.2
1.12.1
1.12.0
1.11.2
1.11.1
1.11.0
1.10.3
1.10.2
1.10.1
1.10.0
1.9.0
1.8.1
retired
1.8.0
1.7.0
1.6.1
1.6.0
1.5.1
1.5.0
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.3
1.3.2
1.3.1
1.3.0
1.2.1
1.2.0
1.1.0
1.0.0
1.0.0-beta.1
0.10.0
0.9.0
0.8.0
0.7.2
0.7.1
0.7.0
0.6.0
0.5.2
0.5.1
0.5.0
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.2.2
0.2.1
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
HTTP client library, with support for middleware and multiple adapters.
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
lib/tesla/adapter/hackney.ex
if Code.ensure_loaded?(:hackney) do
defmodule Tesla.Adapter.Hackney do
@moduledoc """
Adapter for [hackney](https://github.com/benoitc/hackney).
Remember to add `{:hackney, "~> 1.13"}` to dependencies (and `:hackney` to applications in `mix.exs`)
Also, you need to recompile tesla after adding `:hackney` dependency:
```shell
mix deps.clean tesla
mix deps.compile tesla
```
## Examples
```elixir
# set globally in config/config.exs
config :tesla, :adapter, Tesla.Adapter.Hackney
# set per module
defmodule MyClient do
def client do
Tesla.client([], Tesla.Adapter.Hackney)
end
end
```
## Adapter specific options
- `:max_body` - Max response body size in bytes. Actual response may be bigger because hackney stops after the last chunk that surpasses `:max_body`.
"""
@behaviour Tesla.Adapter
alias Tesla.Multipart
@impl Tesla.Adapter
def call(env, opts) do
with {:ok, status, headers, body} <- request(env, opts) do
{:ok, %{env | status: status, headers: format_headers(headers), body: format_body(body)}}
end
end
defp format_headers(headers) do
for {key, value} <- headers do
{String.downcase(to_string(key)), to_string(value)}
end
end
defp format_body(data) when is_list(data), do: IO.iodata_to_binary(data)
defp format_body(data) when is_binary(data) or is_reference(data), do: data
defp request(env, opts) do
request(
env.method,
Tesla.build_url(env),
env.headers,
env.body,
Tesla.Adapter.opts(env, opts)
)
end
defp request(method, url, headers, %Stream{} = body, opts),
do: request_stream(method, url, headers, body, opts)
defp request(method, url, headers, body, opts) when is_function(body),
do: request_stream(method, url, headers, body, opts)
defp request(method, url, headers, %Multipart{} = mp, opts) do
headers = headers ++ Multipart.headers(mp)
body = Multipart.body(mp)
request(method, url, headers, body, opts)
end
defp request(method, url, headers, body, opts) do
handle(:hackney.request(method, url, headers, body || ~c"", opts), opts)
end
defp request_stream(method, url, headers, body, opts) do
with {:ok, ref} <- :hackney.request(method, url, headers, :stream, opts) do
case send_stream(ref, body) do
:ok -> handle(:hackney.start_response(ref), opts)
error -> handle(error, opts)
end
else
e -> handle(e, opts)
end
end
defp send_stream(ref, body) do
Enum.reduce_while(body, :ok, fn data, _ ->
case :hackney.send_body(ref, data) do
:ok -> {:cont, :ok}
error -> {:halt, error}
end
end)
end
defp handle({:error, _} = error, _opts), do: error
defp handle({:ok, status, headers}, _opts), do: {:ok, status, headers, []}
defp handle({:ok, ref}, _opts) when is_reference(ref) do
handle_async_response({ref, %{status: nil, headers: nil}})
end
defp handle({:ok, status, headers, ref}, opts) when is_reference(ref) do
with {:ok, body} <- :hackney.body(ref, Keyword.get(opts, :max_body, :infinity)) do
{:ok, status, headers, body}
end
end
defp handle({:ok, status, headers, body}, _opts), do: {:ok, status, headers, body}
defp handle_async_response({ref, %{headers: headers, status: status}})
when not (is_nil(headers) or is_nil(status)) do
{:ok, status, headers, ref}
end
defp handle_async_response({ref, output}) do
receive do
{:hackney_response, ^ref, {:status, status, _}} ->
handle_async_response({ref, %{output | status: status}})
{:hackney_response, ^ref, {:headers, headers}} ->
handle_async_response({ref, %{output | headers: headers}})
end
end
end
end