diff options
Diffstat (limited to 'lib/pleroma/http')
-rw-r--r-- | lib/pleroma/http/connection.ex | 112 | ||||
-rw-r--r-- | lib/pleroma/http/http.ex | 59 | ||||
-rw-r--r-- | lib/pleroma/http/request_builder.ex | 2 |
3 files changed, 136 insertions, 37 deletions
diff --git a/lib/pleroma/http/connection.ex b/lib/pleroma/http/connection.ex index 7e2c6f5e8..d4e6d0f99 100644 --- a/lib/pleroma/http/connection.ex +++ b/lib/pleroma/http/connection.ex @@ -7,14 +7,13 @@ defmodule Pleroma.HTTP.Connection do Connection for http-requests. """ - @hackney_options [ + @options [ connect_timeout: 10_000, - recv_timeout: 20_000, - follow_redirect: true, - force_redirect: true, + timeout: 20_000, pool: :federation ] - @adapter Application.get_env(:tesla, :adapter) + + require Logger @doc """ Configure a client connection @@ -25,19 +24,108 @@ defmodule Pleroma.HTTP.Connection do """ @spec new(Keyword.t()) :: Tesla.Env.client() def new(opts \\ []) do - Tesla.client([], {@adapter, hackney_options(opts)}) + middleware = [Tesla.Middleware.FollowRedirects] + adapter = Application.get_env(:tesla, :adapter) + Tesla.client(middleware, {adapter, options(opts)}) end - # fetch Hackney options + # fetch http options # - def hackney_options(opts) do + def options(opts) do options = Keyword.get(opts, :adapter, []) adapter_options = Pleroma.Config.get([:http, :adapter], []) + proxy_url = Pleroma.Config.get([:http, :proxy_url], nil) - @hackney_options - |> Keyword.merge(adapter_options) - |> Keyword.merge(options) - |> Keyword.merge(proxy: proxy_url) + proxy = + case parse_proxy(proxy_url) do + {:ok, proxy_host, proxy_port} -> {proxy_host, proxy_port} + _ -> nil + end + + options = + @options + |> Keyword.merge(adapter_options) + |> Keyword.merge(options) + |> Keyword.merge(proxy: proxy) + + pool = options[:pool] + url = options[:url] + + if not is_nil(url) and not is_nil(pool) and Pleroma.Gun.Connections.alive?(pool) do + get_conn_for_gun(url, options, pool) + else + options + end + end + + defp get_conn_for_gun(url, options, pool) do + case Pleroma.Gun.Connections.checkin(url, options, pool) do + nil -> + options + + conn -> + %{host: host, port: port} = URI.parse(url) + + # verify sertificates opts for gun + tls_opts = [ + verify: :verify_peer, + cacerts: :certifi.cacerts(), + depth: 20, + server_name_indication: to_charlist(host), + reuse_sessions: false, + verify_fun: {&:ssl_verify_hostname.verify_fun/3, [check_hostname: to_charlist(host)]} + ] + + Keyword.put(options, :conn, conn) + |> Keyword.put(:close_conn, false) + |> Keyword.put(:original, "#{host}:#{port}") + |> Keyword.put(:tls_opts, tls_opts) + end + end + + @spec parse_proxy(String.t() | tuple() | nil) :: + {tuple, pos_integer()} | {:error, atom()} | nil + def parse_proxy(nil), do: nil + + def parse_proxy(proxy) when is_binary(proxy) do + with [host, port] <- String.split(proxy, ":"), + {port, ""} <- Integer.parse(port) do + {:ok, parse_host(host), port} + else + {_, _} -> + Logger.warn("parsing port in proxy fail #{inspect(proxy)}") + {:error, :error_parsing_port_in_proxy} + + :error -> + Logger.warn("parsing port in proxy fail #{inspect(proxy)}") + {:error, :error_parsing_port_in_proxy} + + _ -> + Logger.warn("parsing proxy fail #{inspect(proxy)}") + {:error, :error_parsing_proxy} + end + end + + def parse_proxy(proxy) when is_tuple(proxy) do + with {_type, host, port} <- proxy do + {:ok, parse_host(host), port} + else + _ -> + Logger.warn("parsing proxy fail #{inspect(proxy)}") + {:error, :error_parsing_proxy} + end + end + + @spec parse_host(String.t() | tuple()) :: charlist() | atom() + def parse_host(host) when is_atom(host), do: to_charlist(host) + + def parse_host(host) when is_binary(host) do + host = to_charlist(host) + + case :inet.parse_address(host) do + {:error, :einval} -> host + {:ok, ip} -> ip + end end end diff --git a/lib/pleroma/http/http.ex b/lib/pleroma/http/http.ex index dec24458a..0a7db737f 100644 --- a/lib/pleroma/http/http.ex +++ b/lib/pleroma/http/http.ex @@ -28,21 +28,44 @@ defmodule Pleroma.HTTP do """ def request(method, url, body \\ "", headers \\ [], options \\ []) do try do + options = process_request_options(options) + + adapter_gun? = Application.get_env(:tesla, :adapter) == Tesla.Adapter.Gun + options = - process_request_options(options) - |> process_sni_options(url) + if adapter_gun? do + adapter_opts = + Keyword.get(options, :adapter, []) + |> Keyword.put(:url, url) + + Keyword.put(options, :adapter, adapter_opts) + else + options + end params = Keyword.get(options, :params, []) - %{} - |> Builder.method(method) - |> Builder.headers(headers) - |> Builder.opts(options) - |> Builder.url(url) - |> Builder.add_param(:body, :body, body) - |> Builder.add_param(:query, :query, params) - |> Enum.into([]) - |> (&Tesla.request(Connection.new(options), &1)).() + request = + %{} + |> Builder.method(method) + |> Builder.url(url) + |> Builder.headers(headers) + |> Builder.opts(options) + |> Builder.add_param(:body, :body, body) + |> Builder.add_param(:query, :query, params) + |> Enum.into([]) + + client = Connection.new(options) + response = Tesla.request(client, request) + + if adapter_gun? do + %{adapter: {_, _, [adapter_options]}} = client + pool = adapter_options[:pool] + Pleroma.Gun.Connections.checkout(adapter_options[:conn], self(), pool) + Pleroma.Gun.Connections.process_queue(pool) + end + + response rescue e -> {:error, e} @@ -52,20 +75,8 @@ defmodule Pleroma.HTTP do end end - defp process_sni_options(options, nil), do: options - - defp process_sni_options(options, url) do - uri = URI.parse(url) - host = uri.host |> to_charlist() - - case uri.scheme do - "https" -> options ++ [ssl: [server_name_indication: host]] - _ -> options - end - end - def process_request_options(options) do - Keyword.merge(Pleroma.HTTP.Connection.hackney_options([]), options) + Keyword.merge(Pleroma.HTTP.Connection.options([]), options) end @doc """ diff --git a/lib/pleroma/http/request_builder.ex b/lib/pleroma/http/request_builder.ex index e23457999..4e77870bd 100644 --- a/lib/pleroma/http/request_builder.ex +++ b/lib/pleroma/http/request_builder.ex @@ -48,7 +48,7 @@ defmodule Pleroma.HTTP.RequestBuilder do def headers(request, header_list) do header_list = if Pleroma.Config.get([:http, :send_user_agent]) do - header_list ++ [{"User-Agent", Pleroma.Application.user_agent()}] + header_list ++ [{"user-agent", Pleroma.Application.user_agent()}] else header_list end |