diff options
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/pleroma/http/adapter_helper.ex | 4 | ||||
| -rw-r--r-- | lib/pleroma/http/adapter_helper/default.ex | 3 | ||||
| -rw-r--r-- | lib/pleroma/http/adapter_helper/gun.ex | 9 | ||||
| -rw-r--r-- | lib/pleroma/http/adapter_helper/hackney.ex | 2 | ||||
| -rw-r--r-- | lib/pleroma/http/http.ex | 9 | ||||
| -rw-r--r-- | lib/pleroma/tesla/middleware/follow_redirects.ex | 106 | 
6 files changed, 109 insertions, 24 deletions
| diff --git a/lib/pleroma/http/adapter_helper.ex b/lib/pleroma/http/adapter_helper.ex index 0532ea31d..bcb9b2b1e 100644 --- a/lib/pleroma/http/adapter_helper.ex +++ b/lib/pleroma/http/adapter_helper.ex @@ -24,7 +24,6 @@ defmodule Pleroma.HTTP.AdapterHelper do            | {Connection.proxy_type(), Connection.host(), pos_integer()}    @callback options(keyword(), URI.t()) :: keyword() -  @callback after_request(keyword()) :: :ok    @callback get_conn(URI.t(), keyword()) :: {:ok, term()} | {:error, term()}    @spec format_proxy(String.t() | tuple() | nil) :: proxy() | nil @@ -67,9 +66,6 @@ defmodule Pleroma.HTTP.AdapterHelper do      Keyword.merge(opts, timeout: timeout)    end -  @spec after_request(keyword()) :: :ok -  def after_request(opts), do: adapter_helper().after_request(opts) -    def get_conn(uri, opts), do: adapter_helper().get_conn(uri, opts)    defp adapter, do: Application.get_env(:tesla, :adapter) diff --git a/lib/pleroma/http/adapter_helper/default.ex b/lib/pleroma/http/adapter_helper/default.ex index 218cfacc0..e13441316 100644 --- a/lib/pleroma/http/adapter_helper/default.ex +++ b/lib/pleroma/http/adapter_helper/default.ex @@ -9,9 +9,6 @@ defmodule Pleroma.HTTP.AdapterHelper.Default do      AdapterHelper.maybe_add_proxy(opts, AdapterHelper.format_proxy(proxy))    end -  @spec after_request(keyword()) :: :ok -  def after_request(_opts), do: :ok -    @spec get_conn(URI.t(), keyword()) :: {:ok, keyword()}    def get_conn(_uri, opts), do: {:ok, opts}  end diff --git a/lib/pleroma/http/adapter_helper/gun.ex b/lib/pleroma/http/adapter_helper/gun.ex index 6f7cc9784..5b4629978 100644 --- a/lib/pleroma/http/adapter_helper/gun.ex +++ b/lib/pleroma/http/adapter_helper/gun.ex @@ -34,15 +34,6 @@ defmodule Pleroma.HTTP.AdapterHelper.Gun do      |> Keyword.merge(incoming_opts)    end -  @spec after_request(keyword()) :: :ok -  def after_request(opts) do -    if opts[:conn] && opts[:body_as] != :chunks do -      ConnectionPool.release_conn(opts[:conn]) -    end - -    :ok -  end -    defp add_scheme_opts(opts, %{scheme: "http"}), do: opts    defp add_scheme_opts(opts, %{scheme: "https"}) do diff --git a/lib/pleroma/http/adapter_helper/hackney.ex b/lib/pleroma/http/adapter_helper/hackney.ex index 42d552740..cd569422b 100644 --- a/lib/pleroma/http/adapter_helper/hackney.ex +++ b/lib/pleroma/http/adapter_helper/hackney.ex @@ -24,8 +24,6 @@ defmodule Pleroma.HTTP.AdapterHelper.Hackney do    defp add_scheme_opts(opts, _), do: opts -  def after_request(_), do: :ok -    @spec get_conn(URI.t(), keyword()) :: {:ok, keyword()}    def get_conn(_uri, opts), do: {:ok, opts}  end diff --git a/lib/pleroma/http/http.ex b/lib/pleroma/http/http.ex index 8ded76601..afcb4d738 100644 --- a/lib/pleroma/http/http.ex +++ b/lib/pleroma/http/http.ex @@ -69,14 +69,11 @@ defmodule Pleroma.HTTP do          request = build_request(method, headers, options, url, body, params)          adapter = Application.get_env(:tesla, :adapter) -        client = Tesla.client([Tesla.Middleware.FollowRedirects], adapter) +        client = Tesla.client([Pleroma.HTTP.Middleware.FollowRedirects], adapter) -        response = request(client, request) - -        AdapterHelper.after_request(adapter_opts) - -        response +        request(client, request) +      # Connection release is handled in a custom FollowRedirects middleware        err ->          err      end diff --git a/lib/pleroma/tesla/middleware/follow_redirects.ex b/lib/pleroma/tesla/middleware/follow_redirects.ex new file mode 100644 index 000000000..f2c502c69 --- /dev/null +++ b/lib/pleroma/tesla/middleware/follow_redirects.ex @@ -0,0 +1,106 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2015-2020 Tymon Tobolski <https://github.com/teamon/tesla/blob/master/lib/tesla/middleware/follow_redirects.ex> +# Copyright © 2020 Pleroma Authors <https://pleroma.social/> +# SPDX-License-Identifier: AGPL-3.0-only + +defmodule Pleroma.HTTP.Middleware.FollowRedirects do +  @moduledoc """ +  Pool-aware version of https://github.com/teamon/tesla/blob/master/lib/tesla/middleware/follow_redirects.ex + +  Follow 3xx redirects +  ## Options +  - `:max_redirects` - limit number of redirects (default: `5`) +  """ + +  alias Pleroma.Gun.ConnectionPool + +  @behaviour Tesla.Middleware + +  @max_redirects 5 +  @redirect_statuses [301, 302, 303, 307, 308] + +  @impl Tesla.Middleware +  def call(env, next, opts \\ []) do +    max = Keyword.get(opts, :max_redirects, @max_redirects) + +    redirect(env, next, max) +  end + +  defp redirect(env, next, left) do +    opts = env.opts[:adapter] + +    case Tesla.run(env, next) do +      {:ok, %{status: status} = res} when status in @redirect_statuses and left > 0 -> +        release_conn(opts) + +        case Tesla.get_header(res, "location") do +          nil -> +            {:ok, res} + +          location -> +            location = parse_location(location, res) + +            case get_conn(location, opts) do +              {:ok, opts} -> +                %{env | opts: Keyword.put(env.opts, :adapter, opts)} +                |> new_request(res.status, location) +                |> redirect(next, left - 1) + +              e -> +                e +            end +        end + +      {:ok, %{status: status}} when status in @redirect_statuses -> +        release_conn(opts) +        {:error, {__MODULE__, :too_many_redirects}} + +      other -> +        unless opts[:body_as] == :chunks do +          release_conn(opts) +        end + +        other +    end +  end + +  defp get_conn(location, opts) do +    uri = URI.parse(location) + +    case ConnectionPool.get_conn(uri, opts) do +      {:ok, conn} -> +        {:ok, Keyword.merge(opts, conn: conn)} + +      e -> +        e +    end +  end + +  defp release_conn(opts) do +    ConnectionPool.release_conn(opts[:conn]) +  end + +  # The 303 (See Other) redirect was added in HTTP/1.1 to indicate that the originally +  # requested resource is not available, however a related resource (or another redirect) +  # available via GET is available at the specified location. +  # https://tools.ietf.org/html/rfc7231#section-6.4.4 +  defp new_request(env, 303, location), do: %{env | url: location, method: :get, query: []} + +  # The 307 (Temporary Redirect) status code indicates that the target +  # resource resides temporarily under a different URI and the user agent +  # MUST NOT change the request method (...) +  # https://tools.ietf.org/html/rfc7231#section-6.4.7 +  defp new_request(env, 307, location), do: %{env | url: location} + +  defp new_request(env, _, location), do: %{env | url: location, query: []} + +  defp parse_location("https://" <> _rest = location, _env), do: location +  defp parse_location("http://" <> _rest = location, _env), do: location + +  defp parse_location(location, env) do +    env.url +    |> URI.parse() +    |> URI.merge(location) +    |> URI.to_string() +  end +end | 
