Page MenuHomePhorge

No OneTemporary

Size
8 KB
Referenced Files
None
Subscribers
None
diff --git a/lib/tesla/adapter/hackney.ex b/lib/tesla/adapter/hackney.ex
index 7a38686..1402d89 100644
--- a/lib/tesla/adapter/hackney.ex
+++ b/lib/tesla/adapter/hackney.ex
@@ -1,52 +1,77 @@
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.6"}` to dependencies (and `:hackney` to applications in `mix.exs`)
+ Also, you need to recompile tesla after adding `:hackney` dependency:
+
+ ```
+ mix deps.clean tesla
+ mix deps.compile tesla
+ ```
+
+ ### Example usage
+ ```
+ # set globally in config/config.exs
+ config :tesla, :adapter, :hackney
+
+ # set per module
+ defmodule MyClient do
+ use Tesla
+
+ adapter :hackney
+ end
+ ```
+ """
+
alias Tesla.Multipart
def call(env, opts) do
with {:ok, status, headers, body} <- request(env, opts || []) do
%{env | status: status,
headers: headers,
body: body}
end
end
defp request(env, opts) do
request(
env.method,
Tesla.build_url(env.url, env.query),
Enum.into(env.headers, []),
env.body,
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 || '', opts)
end
defp request_stream(method, url, headers, body, opts) do
with {:ok, ref} <- :hackney.request(method, url, headers, :stream, opts) do
for data <- body, do: :ok = :hackney.send_body(ref, data)
handle :hackney.start_response(ref)
else
e -> handle(e)
end
end
defp handle({:error, _} = error), do: error
defp handle({:ok, status, headers}), do: {:ok, status, headers, []}
defp handle({:ok, status, headers, ref}) when is_reference(ref) do
with {:ok, body} <- :hackney.body(ref) do
{:ok, status, headers, body}
end
end
defp handle({:ok, status, headers, body}), do: {:ok, status, headers, body}
end
end
diff --git a/lib/tesla/adapter/httpc.ex b/lib/tesla/adapter/httpc.ex
index 8894547..9fb9d20 100644
--- a/lib/tesla/adapter/httpc.ex
+++ b/lib/tesla/adapter/httpc.ex
@@ -1,69 +1,71 @@
defmodule Tesla.Adapter.Httpc do
@moduledoc """
- Adapter for `:httpc`
+ Adapter for [httpc](http://erlang.org/doc/man/httpc.html)
- **NOTE** Tesla overrides default autoredirect value with false to ensure
- consistency between adapters
+ This is the default adapter.
+
+ **NOTE** Tesla overrides default autoredirect value with false to ensure
+ consistency between adapters
"""
import Tesla.Adapter.Shared, only: [stream_to_fun: 1, next_chunk: 1]
alias Tesla.Multipart
@override_defaults autoredirect: false
@http_opts ~w(timeout connect_timeout ssl essl autoredirect proxy_auth version relaxed url_encode)a
def call(env, opts) do
opts = Keyword.merge(@override_defaults, opts || [])
with {:ok, {status, headers, body}} <- request(env, opts) do
format_response(env, status, headers, body)
end
end
defp format_response(env, {_, status, _}, headers, body) do
%{env | status: status,
headers: headers,
body: body}
end
defp request(env, opts) do
content_type = to_charlist(env.headers["content-type"] || "")
handle request(
env.method || :get,
Tesla.build_url(env.url, env.query) |> to_charlist,
Enum.into(env.headers, [], fn {k,v} -> {to_charlist(k), to_charlist(v)} end),
content_type,
env.body,
Keyword.split(opts ++ env.opts, @http_opts)
)
end
defp request(method, url, headers, _content_type, nil, {http_opts, opts}) do
:httpc.request(method, {url, headers}, http_opts, opts)
end
defp request(method, url, headers, _content_type, %Multipart{} = mp, opts) do
headers = headers ++ Multipart.headers(mp)
headers = for {key, value} <- headers, do: {to_charlist(key), to_charlist(value)}
{content_type, headers} = Keyword.pop_first(headers, 'Content-Type', 'text/plain')
body = stream_to_fun(Multipart.body(mp))
request(method, url, headers, to_charlist(content_type), body, opts)
end
defp request(method, url, headers, content_type, %Stream{} = body, opts) do
fun = stream_to_fun(body)
request(method, url, headers, content_type, fun, opts)
end
defp request(method, url, headers, content_type, body, opts) when is_function(body) do
body = {:chunkify, &next_chunk/1, body}
request(method, url, headers, content_type, body, opts)
end
defp request(method, url, headers, content_type, body, {http_opts, opts}) do
:httpc.request(method, {url, headers, content_type, body}, http_opts, opts)
end
defp handle({:error, {:failed_connect, _}}), do: {:error, :econnrefused}
defp handle(response), do: response
end
diff --git a/lib/tesla/adapter/ibrowse.ex b/lib/tesla/adapter/ibrowse.ex
index 2710499..fff802f 100644
--- a/lib/tesla/adapter/ibrowse.ex
+++ b/lib/tesla/adapter/ibrowse.ex
@@ -1,50 +1,75 @@
if Code.ensure_loaded?(:ibrowse) do
defmodule Tesla.Adapter.Ibrowse do
+ @moduledoc """
+ Adapter for [ibrowse](https://github.com/cmullaparthi/ibrowse)
+
+ Remember to add `{:ibrowse, "~> 4.2"}` to dependencies (and `:ibrowse` to applications in `mix.exs`)
+ Also, you need to recompile tesla after adding `:ibrowse` dependency:
+
+ ```
+ mix deps.clean tesla
+ mix deps.compile tesla
+ ```
+
+ ### Example usage
+ ```
+ # set globally in config/config.exs
+ config :tesla, :adapter, :ibrowse
+
+ # set per module
+ defmodule MyClient do
+ use Tesla
+
+ adapter :ibrowse
+ end
+ ```
+ """
+
import Tesla.Adapter.Shared, only: [stream_to_fun: 1, next_chunk: 1]
alias Tesla.Multipart
def call(env, opts) do
with {:ok, status, headers, body} <- request(env, opts || []) do
%{env | status: status,
headers: headers,
body: body}
end
end
defp request(env, opts) do
body = env.body || []
handle request(
Tesla.build_url(env.url, env.query) |> to_charlist,
Enum.into(env.headers, []),
env.method,
body,
opts ++ env.opts
)
end
defp request(url, headers, method, %Multipart{} = mp, opts) do
headers = headers ++ Multipart.headers(mp)
body = stream_to_fun(Multipart.body(mp))
request(url, headers, method, body, opts)
end
defp request(url, headers, method, %Stream{} = body, opts) do
fun = stream_to_fun(body)
request(url, headers, method, fun, opts)
end
defp request(url, headers, method, body, opts) when is_function(body) do
body = {&next_chunk/1, body}
opts = Keyword.put(opts, :transfer_encoding, :chunked)
request(url, headers, method, body, opts)
end
defp request(url, headers, method, body, opts) do
:ibrowse.send_req(url, headers, method, body, opts)
end
defp handle({:error, {:conn_failed, error}}), do: error
defp handle(response), do: response
end
end
diff --git a/lib/tesla/adapter/shared.ex b/lib/tesla/adapter/shared.ex
index ebe7dc8..7bb16ee 100644
--- a/lib/tesla/adapter/shared.ex
+++ b/lib/tesla/adapter/shared.ex
@@ -1,13 +1,15 @@
defmodule Tesla.Adapter.Shared do
+ @moduledoc false
+
def stream_to_fun(stream) do
reductor = fn(item, _acc) -> {:suspend, item} end
{_, _, fun} = Enumerable.reduce(stream, {:suspend, nil}, reductor)
fun
end
def next_chunk(fun), do: parse_chunk fun.({:cont, nil})
defp parse_chunk({:suspended, item, fun}), do: {:ok, item, fun}
defp parse_chunk(_), do: :eof
end

File Metadata

Mime Type
text/x-diff
Expires
Sat, Sep 19, 12:21 AM (16 h, 52 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
1768535
Default Alt Text
(8 KB)

Event Timeline