# Pleroma: A lightweight social networking server # Copyright © 2017-2022 Pleroma Authors # SPDX-License-Identifier: AGPL-3.0-only defmodule Pleroma.ReverseProxy.Client.Hackney do @behaviour Pleroma.ReverseProxy.Client # redirect handler from Pleb, slightly modified to work with Hackney # https://declin.eu/objects/d4f38e62-5429-4614-86d1-e8fc16e6bf33 # seven years without upstream fix! # https://github.com/benoitc/hackney/issues/273 @redirect_statuses [301, 302, 303, 307, 308] defp get_location(headers) do location = Enum.find(headers, fn {header, _location} -> String.downcase(header) == "location" end) elem(location, 1) end @impl true def request(method, url, headers, body, opts \\ []) do if opts[:follow_redirect] != false do {_state, req_opts} = Access.get_and_update(opts, :follow_redirect, fn a -> {a, false} end) res = :hackney.request(method, url, headers, body, req_opts) case res do {:ok, code, reply_headers, _client} when code in @redirect_statuses -> :hackney.request(method, get_location(reply_headers), headers, body, req_opts) {:ok, code, reply_headers} when code in @redirect_statuses -> :hackney.request(method, get_location(reply_headers), headers, body, req_opts) _ -> res end else :hackney.request(method, url, headers, body, opts) end end @impl true def stream_body(ref) do case :hackney.stream_body(ref) do :done -> :done {:ok, data} -> {:ok, data, ref} {:error, error} -> {:error, error} end end @impl true def close(ref), do: :hackney.close(ref) end