summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorrinpatch <rin@patch.cx>2022-01-15 21:14:17 +0300
committerrinpatch <rin@patch.cx>2022-01-15 21:17:26 +0300
commit32cf644f057f3459a3bf28c25889a16d502e2d7a (patch)
treeeafbdedd5ab599619022ce69b4ba736b98944f0e
parent775e0f56420ba525bd9bd303dbfd7916968460c5 (diff)
WIP: Automatic failover to hackney on socks5 proxy detection
-rw-r--r--config/config.exs5
-rw-r--r--lib/pleroma/application.ex6
-rw-r--r--lib/pleroma/http.ex49
-rw-r--r--lib/pleroma/http/adapter_helper.ex13
-rw-r--r--lib/pleroma/http/adapter_helper/hackney.ex35
5 files changed, 103 insertions, 5 deletions
diff --git a/config/config.exs b/config/config.exs
index cb97f49dd..577ebf1d9 100644
--- a/config/config.exs
+++ b/config/config.exs
@@ -181,7 +181,10 @@ config :tesla, :adapter, {Tesla.Adapter.Finch, name: Pleroma.HTTP.FinchPool}
config :pleroma, :http,
proxy_url: nil,
user_agent: :default,
- adapter: []
+ adapter: [],
+ # Ideally this option would be named `adapter`, but somebody decided
+ # to name adapter options that, and renaming it would be too much work.
+ client: :finch
config :pleroma, :instance,
name: "Pleroma",
diff --git a/lib/pleroma/application.ex b/lib/pleroma/application.ex
index dae981d53..6ba57e4a9 100644
--- a/lib/pleroma/application.ex
+++ b/lib/pleroma/application.ex
@@ -59,15 +59,17 @@ defmodule Pleroma.Application do
Pleroma.Docs.JSON.compile()
limiters_setup()
+ http_children = Pleroma.HTTP.setup_and_return_children!()
+
# Define workers and child supervisors to be supervised
children =
[
- {Finch, name: Pleroma.HTTP.FinchPool},
+ # {Finch, name: Pleroma.HTTP.FinchPool},
Pleroma.Repo,
Config.TransferTask,
Pleroma.Emoji,
Pleroma.Web.Plugs.RateLimiter.Supervisor
- ] ++
+ ] ++ http_children ++
cachex_children() ++
[
Pleroma.Stats,
diff --git a/lib/pleroma/http.ex b/lib/pleroma/http.ex
index 01f307d17..ca4938b78 100644
--- a/lib/pleroma/http.ex
+++ b/lib/pleroma/http.ex
@@ -7,6 +7,7 @@ defmodule Pleroma.HTTP do
Wrapper for `Tesla.request/2`.
"""
+ alias Pleroma.Config
alias Pleroma.HTTP.AdapterHelper
alias Pleroma.HTTP.Request
alias Pleroma.HTTP.RequestBuilder, as: Builder
@@ -18,6 +19,54 @@ defmodule Pleroma.HTTP do
@type t :: __MODULE__
@type method() :: :get | :post | :put | :delete | :head
+ defp get_tesla_adapter_and_children(_, {:error, reason}), do: raise "Proxy configuration parse error: #{reason}"
+
+ defp get_tesla_adapter_and_children(:finch, {:ok, _proxy_type, _, _}), do: raise "Finch adapter does not support SOCKS proxies"
+
+ defp get_tesla_adapter_and_children(:finch, proxy) do
+ conn_opts =
+ case proxy do
+ {:ok, host, port} -> [proxy: {:http, host, port, []}]
+ _ -> []
+ end
+
+ children = [{Finch, name: Pleroma.HTTP.FinchPool, conn_opts: conn_opts}]
+ tesla_adapter = {Tesla.Adapter.Finch, name: Pleroma.HTTP.FinchPool}
+
+ {tesla_adapter, children}
+ end
+
+ defp get_tesla_adapter_and_children(:hackney, _proxy) do
+ tesla_adapter = Tesla.Adapter.Hackney
+ children = []
+
+ {tesla_adapter, children}
+ end
+
+ def setup_and_return_children! do
+ parsed_proxy = AdapterHelper.parse_proxy(Config.get([:http, :proxy_url]))
+
+ adapter =
+ case Config.get([:http, :client]) do
+ adapter when adapter in [:finch, :hackney] ->
+ adapter
+
+ nil ->
+ case parsed_proxy do
+ {:ok, {proxy_type, _, _}} when proxy_type in [:socks4, :socks5] -> :hackney
+ _ -> :finch
+ end
+
+ unrecognized_adapter ->
+ raise "No such adapter: #{unrecognized_adapter}"
+ end
+
+ {tesla_adapter, children} = get_tesla_adapter_and_children(adapter, parsed_proxy)
+
+ Application.put_env(:tesla, :adapter, tesla_adapter)
+ children
+ end
+
@doc """
Performs GET request.
diff --git a/lib/pleroma/http/adapter_helper.ex b/lib/pleroma/http/adapter_helper.ex
index f9b489616..c7f7633bc 100644
--- a/lib/pleroma/http/adapter_helper.ex
+++ b/lib/pleroma/http/adapter_helper.ex
@@ -6,7 +6,7 @@ defmodule Pleroma.HTTP.AdapterHelper do
@moduledoc """
Configure Tesla.Client with default and customized adapter options.
"""
- @defaults [name: MyFinch, connect_timeout: 5_000, recv_timeout: 5_000]
+ @defaults [connect_timeout: 5_000, recv_timeout: 5_000]
@type proxy_type() :: :socks4 | :socks5
@type host() :: charlist() | :inet.ip_address()
@@ -43,7 +43,16 @@ defmodule Pleroma.HTTP.AdapterHelper do
def options(%URI{} = uri, opts \\ []) do
@defaults
|> Keyword.merge(opts)
- |> AdapterHelper.Default.options(uri)
+ |> adapter_helper().options(uri)
+ end
+
+ defp adapter, do: Application.get_env(:tesla, :adapter)
+
+ defp adapter_helper do
+ case adapter() do
+ Tesla.Adapter.Hackney -> AdapterHelper.Hackney
+ _ -> AdapterHelper.Default
+ end
end
@spec parse_proxy(String.t() | tuple() | nil) ::
diff --git a/lib/pleroma/http/adapter_helper/hackney.ex b/lib/pleroma/http/adapter_helper/hackney.ex
new file mode 100644
index 000000000..d5f899bba
--- /dev/null
+++ b/lib/pleroma/http/adapter_helper/hackney.ex
@@ -0,0 +1,35 @@
+# Pleroma: A lightweight social networking server
+# Copyright © 2017-2021 Pleroma Authors <https://pleroma.social/>
+# SPDX-License-Identifier: AGPL-3.0-only
+
+defmodule Pleroma.HTTP.AdapterHelper.Hackney do
+ @behaviour Pleroma.HTTP.AdapterHelper
+
+ @spec options(keyword(), URI.t()) :: keyword()
+ def options(connection_opts \\ [], %URI{} = uri) do
+ proxy = Pleroma.Config.get([:http, :proxy_url])
+
+ config_opts = Pleroma.Config.get([:http, :adapter], [])
+
+ []
+ |> Keyword.merge(config_opts)
+ |> Keyword.merge(connection_opts)
+ |> add_scheme_opts(uri)
+ |> maybe_add_with_body()
+ |> Pleroma.HTTP.AdapterHelper.maybe_add_proxy(proxy)
+ end
+
+ defp add_scheme_opts(opts, %URI{scheme: "https"}) do
+ Keyword.put(opts, :ssl_options, versions: [:"tlsv1.2", :"tlsv1.1", :tlsv1])
+ end
+
+ defp add_scheme_opts(opts, _), do: opts
+
+ defp maybe_add_with_body(opts) do
+ if opts[:max_body] do
+ Keyword.put(opts, :with_body, true)
+ else
+ opts
+ end
+ end
+end