diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/pleroma/gun/api/api.ex | 25 | ||||
-rw-r--r-- | lib/pleroma/gun/api/gun.ex | 9 | ||||
-rw-r--r-- | lib/pleroma/gun/api/mock.ex | 35 | ||||
-rw-r--r-- | lib/pleroma/gun/connections.ex | 70 | ||||
-rw-r--r-- | lib/pleroma/http/connection.ex | 56 |
5 files changed, 175 insertions, 20 deletions
diff --git a/lib/pleroma/gun/api/api.ex b/lib/pleroma/gun/api/api.ex index 7e6d2f929..43ee7f354 100644 --- a/lib/pleroma/gun/api/api.ex +++ b/lib/pleroma/gun/api/api.ex @@ -6,20 +6,21 @@ defmodule Pleroma.Gun.API do @callback open(charlist(), pos_integer(), map()) :: {:ok, pid()} @callback info(pid()) :: map() @callback close(pid()) :: :ok + @callback await_up(pid) :: {:ok, atom()} | {:error, atom()} + @callback connect(pid(), map()) :: reference() + @callback await(pid(), reference()) :: {:response, :fin, 200, []} - def open(host, port, opts) do - api().open(host, port, opts) - end + def open(host, port, opts), do: api().open(host, port, opts) - def info(pid) do - api().info(pid) - end + def info(pid), do: api().info(pid) - def close(pid) do - api().close(pid) - end + def close(pid), do: api().close(pid) - defp api do - Pleroma.Config.get([Pleroma.Gun.API], Pleroma.Gun.API.Gun) - end + def await_up(pid), do: api().await_up(pid) + + def connect(pid, opts), do: api().connect(pid, opts) + + def await(pid, ref), do: api().await(pid, ref) + + defp api, do: Pleroma.Config.get([Pleroma.Gun.API], Pleroma.Gun.API.Gun) end diff --git a/lib/pleroma/gun/api/gun.ex b/lib/pleroma/gun/api/gun.ex index d97f5a7c9..603dd700e 100644 --- a/lib/pleroma/gun/api/gun.ex +++ b/lib/pleroma/gun/api/gun.ex @@ -31,4 +31,13 @@ defmodule Pleroma.Gun.API.Gun do @impl API def close(pid), do: :gun.close(pid) + + @impl API + def await_up(pid), do: :gun.await_up(pid) + + @impl API + def connect(pid, opts), do: :gun.connect(pid, opts) + + @impl API + def await(pid, ref), do: :gun.await(pid, ref) end diff --git a/lib/pleroma/gun/api/mock.ex b/lib/pleroma/gun/api/mock.ex index b1a30a73c..5e1bb8abc 100644 --- a/lib/pleroma/gun/api/mock.ex +++ b/lib/pleroma/gun/api/mock.ex @@ -73,6 +73,41 @@ defmodule Pleroma.Gun.API.Mock do end @impl API + def open({127, 0, 0, 1}, 8123, _) do + Task.start_link(fn -> Process.sleep(1_000) end) + end + + @impl API + def open('localhost', 9050, _) do + Task.start_link(fn -> Process.sleep(1_000) end) + end + + @impl API + def await_up(_pid) do + {:ok, :http} + end + + @impl API + def connect(pid, %{host: _, port: 80}) do + ref = make_ref() + Registry.register(API.Mock, ref, pid) + ref + end + + @impl API + def connect(pid, %{host: _, port: 443, protocols: [:http2], transport: :tls}) do + ref = make_ref() + Registry.register(API.Mock, ref, pid) + ref + end + + @impl API + def await(pid, ref) do + [{_, ^pid}] = Registry.lookup(API.Mock, ref) + {:response, :fin, 200, []} + end + + @impl API def info(pid) do [{_, info}] = Registry.lookup(API.Mock, pid) info diff --git a/lib/pleroma/gun/connections.ex b/lib/pleroma/gun/connections.ex index 3716d9f74..6cec4277a 100644 --- a/lib/pleroma/gun/connections.ex +++ b/lib/pleroma/gun/connections.ex @@ -4,6 +4,7 @@ defmodule Pleroma.Gun.Connections do use GenServer + require Logger @type domain :: String.t() @type conn :: Pleroma.Gun.Conn.t() @@ -154,14 +155,69 @@ defmodule Pleroma.Gun.Connections do end defp open_conn(key, uri, from, state, opts) do - {:ok, conn} = API.open(to_charlist(uri.host), uri.port, opts) + host = to_charlist(uri.host) + port = uri.port + + result = + if opts[:proxy] do + with {proxy_host, proxy_port} <- opts[:proxy], + {:ok, conn} <- API.open(proxy_host, proxy_port, opts), + {:ok, _} <- API.await_up(conn) do + connect_opts = %{host: host, port: port} + + connect_opts = + if uri.scheme == "https" do + Map.put(connect_opts, :protocols, [:http2]) + |> Map.put(:transport, :tls) + else + connect_opts + end + + with stream <- API.connect(conn, connect_opts), + {:response, :fin, 200, _} <- API.await(conn, stream) do + {:ok, conn, true} + end + else + {:error, error} -> + {:error, error} - state = - put_in(state.conns[key], %Pleroma.Gun.Conn{ - conn: conn, - waiting_pids: [from] - }) + error -> + Logger.warn(inspect(error)) + {:error, :error_connection_to_proxy} + end + else + with {:ok, conn} <- API.open(host, port, opts) do + {:ok, conn, false} + else + {:error, error} -> + {:error, error} - {:noreply, state} + error -> + Logger.warn(inspect(error)) + {:error, :error_connection} + end + end + + case result do + {:ok, conn, is_up} -> + {from_list, used, conn_state} = if is_up, do: {[], 1, :up}, else: {[from], 0, :open} + + state = + put_in(state.conns[key], %Pleroma.Gun.Conn{ + conn: conn, + waiting_pids: from_list, + used: used, + state: conn_state + }) + + if is_up do + {:reply, conn, state} + else + {:noreply, state} + end + + {:error, _error} -> + {:reply, nil, state} + end end end diff --git a/lib/pleroma/http/connection.ex b/lib/pleroma/http/connection.ex index fbf135bf9..39c0fff43 100644 --- a/lib/pleroma/http/connection.ex +++ b/lib/pleroma/http/connection.ex @@ -14,6 +14,8 @@ defmodule Pleroma.HTTP.Connection do version: :master ] + require Logger + @doc """ Configure a client connection @@ -33,13 +35,20 @@ defmodule Pleroma.HTTP.Connection 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) + 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_url) + |> Keyword.merge(proxy: proxy) pool = options[:pool] url = options[:url] @@ -75,4 +84,49 @@ defmodule Pleroma.HTTP.Connection do |> 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 |