Current section

Files

Jump to
httpoison lib httpoison.ex
Raw

lib/httpoison.ex

defmodule HTTPoison.Base do
defmacro __using__(_) do
quote do
def start do
:application.ensure_all_started(:httpoison)
end
def process_url(url) do
case String.downcase(url) do
<<"http://"::utf8, _::binary>> -> url
<<"https://"::utf8, _::binary>> -> url
_ -> "http://" <> url
end
end
def process_request_body(body), do: body
def process_response_body(body), do: body
def process_request_headers(headers) when is_map(headers) do
Enum.into(headers, [])
end
def process_request_headers(headers), do: headers
def process_response_chunk(chunk), do: chunk
def process_headers(headers), do: Enum.into(headers, %{})
def process_status_code(status_code), do: status_code
def transformer(target) do
receive do
{:hackney_response, id, {:status, code, _reason}} ->
send target, %HTTPoison.AsyncStatus{id: id, code: process_status_code(code)}
transformer(target)
{:hackney_response, id, {:headers, headers}} ->
send target, %HTTPoison.AsyncHeaders{id: id, headers: process_headers(headers)}
transformer(target)
{:hackney_response, id, :done} ->
send target, %HTTPoison.AsyncEnd{id: id}
{:hackney_response, id, chunk} ->
send target, %HTTPoison.AsyncChunk{id: id, chunk: process_response_chunk(chunk)}
transformer(target)
end
end
@doc """
Sends an HTTP request.
Args:
* method - HTTP method, atom (:get, :head, :post, :put, :delete, etc.)
* url - URL, binary string or char list
* body - request body, binary string or char list
* headers - HTTP headers, orddict (eg. [{:Accept, "application/json"}])
* options - orddict of options
Options:
* timeout - timeout in ms, integer
Returns HTTPoison.Response if successful.
Raises HTTPoison.HTTPError if failed.
"""
def request(method, url, body \\ "", headers \\ [], options \\ []) do
timeout = Keyword.get options, :timeout, 5000
stream_to = Keyword.get options, :stream_to
hn_options = [connect_timeout: timeout] ++ Keyword.get options, :hackney, []
body = process_request_body body
if stream_to do
hn_options = [:async, {:stream_to, spawn(__MODULE__, :transformer, [stream_to])}] ++ hn_options
end
case :hackney.request(method,
process_url(to_string(url)),
process_request_headers(headers),
body,
hn_options) do
{:ok, status_code, headers, client} ->
{:ok, body} = :hackney.body(client)
%HTTPoison.Response {
status_code: process_status_code(status_code),
headers: process_headers(headers),
body: process_response_body(body)
}
{:ok, id} ->
%HTTPoison.AsyncResponse { id: id }
{:error, reason} ->
raise HTTPoison.HTTPError, message: to_string(reason)
end
end
def get(url, headers \\ [], options \\ []), do: request(:get, url, "", headers, options)
def put(url, body, headers \\ [], options \\ []), do: request(:put, url, body, headers, options)
def head(url, headers \\ [], options \\ []), do: request(:head, url, "", headers, options)
def post(url, body, headers \\ [], options \\ []), do: request(:post, url, body, headers, options)
def patch(url, body, headers \\ [], options \\ []), do: request(:patch, url, body, headers, options)
def delete(url, headers \\ [], options \\ []), do: request(:delete, url, "", headers, options)
def options(url, headers \\ [], options \\ []), do: request(:options, url, "", headers, options)
defoverridable Module.definitions_in(__MODULE__)
end
end
end
defmodule HTTPoison do
@moduledoc """
The HTTP client for Elixir.
"""
defmodule Response do
defstruct status_code: nil, body: nil, headers: []
end
defmodule AsyncResponse do
defstruct id: nil
end
defmodule AsyncStatus do
defstruct id: nil, code: nil
end
defmodule AsyncHeaders do
defstruct id: nil, headers: []
end
defmodule AsyncChunk do
defstruct id: nil, chunk: nil
end
defmodule AsyncEnd do
defstruct id: nil
end
defmodule HTTPError do
defexception message: nil
end
use HTTPoison.Base
end