connection.ex (3388B)
1 # Pleroma: A lightweight social networking server 2 # Copyright © 2017-2020 Pleroma Authors <https://pleroma.social/> 3 # SPDX-License-Identifier: AGPL-3.0-only 4 5 defmodule Pleroma.HTTP.Connection do 6 @moduledoc """ 7 Configure Tesla.Client with default and customized adapter options. 8 """ 9 10 alias Pleroma.Config 11 alias Pleroma.HTTP.AdapterHelper 12 13 require Logger 14 15 @defaults [pool: :federation] 16 17 @type ip_address :: ipv4_address() | ipv6_address() 18 @type ipv4_address :: {0..255, 0..255, 0..255, 0..255} 19 @type ipv6_address :: 20 {0..65_535, 0..65_535, 0..65_535, 0..65_535, 0..65_535, 0..65_535, 0..65_535, 0..65_535} 21 @type proxy_type() :: :socks4 | :socks5 22 @type host() :: charlist() | ip_address() 23 24 @doc """ 25 Merge default connection & adapter options with received ones. 26 """ 27 28 @spec options(URI.t(), keyword()) :: keyword() 29 def options(%URI{} = uri, opts \\ []) do 30 @defaults 31 |> pool_timeout() 32 |> Keyword.merge(opts) 33 |> adapter_helper().options(uri) 34 end 35 36 defp pool_timeout(opts) do 37 {config_key, default} = 38 if adapter() == Tesla.Adapter.Gun do 39 {:pools, Config.get([:pools, :default, :timeout])} 40 else 41 {:hackney_pools, 10_000} 42 end 43 44 timeout = Config.get([config_key, opts[:pool], :timeout], default) 45 46 Keyword.merge(opts, timeout: timeout) 47 end 48 49 @spec after_request(keyword()) :: :ok 50 def after_request(opts), do: adapter_helper().after_request(opts) 51 52 defp adapter, do: Application.get_env(:tesla, :adapter) 53 54 defp adapter_helper do 55 case adapter() do 56 Tesla.Adapter.Gun -> AdapterHelper.Gun 57 Tesla.Adapter.Hackney -> AdapterHelper.Hackney 58 _ -> AdapterHelper 59 end 60 end 61 62 @spec parse_proxy(String.t() | tuple() | nil) :: 63 {:ok, host(), pos_integer()} 64 | {:ok, proxy_type(), host(), pos_integer()} 65 | {:error, atom()} 66 | nil 67 68 def parse_proxy(nil), do: nil 69 70 def parse_proxy(proxy) when is_binary(proxy) do 71 with [host, port] <- String.split(proxy, ":"), 72 {port, ""} <- Integer.parse(port) do 73 {:ok, parse_host(host), port} 74 else 75 {_, _} -> 76 Logger.warn("Parsing port failed #{inspect(proxy)}") 77 {:error, :invalid_proxy_port} 78 79 :error -> 80 Logger.warn("Parsing port failed #{inspect(proxy)}") 81 {:error, :invalid_proxy_port} 82 83 _ -> 84 Logger.warn("Parsing proxy failed #{inspect(proxy)}") 85 {:error, :invalid_proxy} 86 end 87 end 88 89 def parse_proxy(proxy) when is_tuple(proxy) do 90 with {type, host, port} <- proxy do 91 {:ok, type, parse_host(host), port} 92 else 93 _ -> 94 Logger.warn("Parsing proxy failed #{inspect(proxy)}") 95 {:error, :invalid_proxy} 96 end 97 end 98 99 @spec parse_host(String.t() | atom() | charlist()) :: charlist() | ip_address() 100 def parse_host(host) when is_list(host), do: host 101 def parse_host(host) when is_atom(host), do: to_charlist(host) 102 103 def parse_host(host) when is_binary(host) do 104 host = to_charlist(host) 105 106 case :inet.parse_address(host) do 107 {:error, :einval} -> host 108 {:ok, ip} -> ip 109 end 110 end 111 112 @spec format_host(String.t()) :: charlist() 113 def format_host(host) do 114 host_charlist = to_charlist(host) 115 116 case :inet.parse_address(host_charlist) do 117 {:error, :einval} -> 118 :idna.encode(host_charlist) 119 120 {:ok, _ip} -> 121 host_charlist 122 end 123 end 124 end