X-Git-Url: http://git.squeep.com/?a=blobdiff_plain;f=lib%2Fpleroma%2Fhttp%2Fhttp.ex;h=7b7c79b649532ef78413d5d51b40a34e172e80dd;hb=4427161ca3798aeee0290f0ed7ac5536039509d8;hp=e64266ae7e9fa9ce2a3a0f7fd467b445c7c47bee;hpb=fe2759bc9f2dad044b49f4954693ac09f9368041;p=akkoma diff --git a/lib/pleroma/http/http.ex b/lib/pleroma/http/http.ex index e64266ae7..7b7c79b64 100644 --- a/lib/pleroma/http/http.ex +++ b/lib/pleroma/http/http.ex @@ -1,37 +1,132 @@ +# Pleroma: A lightweight social networking server +# Copyright © 2017-2020 Pleroma Authors +# SPDX-License-Identifier: AGPL-3.0-only + defmodule Pleroma.HTTP do - require HTTPoison + @moduledoc """ + Wrapper for `Tesla.request/2`. + """ - def request(method, url, body \\ "", headers \\ [], options \\ []) do - options = - process_request_options(options) - |> process_sni_options(url) + alias Pleroma.HTTP.Connection + alias Pleroma.HTTP.Request + alias Pleroma.HTTP.RequestBuilder, as: Builder + alias Tesla.Client + alias Tesla.Env - HTTPoison.request(method, url, body, headers, options) - end + require Logger + + @type t :: __MODULE__ + + @doc """ + Performs GET request. - defp process_sni_options(options, url) do + See `Pleroma.HTTP.request/5` + """ + @spec get(Request.url() | nil, Request.headers(), keyword()) :: + nil | {:ok, Env.t()} | {:error, any()} + def get(url, headers \\ [], options \\ []) + def get(nil, _, _), do: nil + def get(url, headers, options), do: request(:get, url, "", headers, options) + + @doc """ + Performs POST request. + + See `Pleroma.HTTP.request/5` + """ + @spec post(Request.url(), String.t(), Request.headers(), keyword()) :: + {:ok, Env.t()} | {:error, any()} + def post(url, body, headers \\ [], options \\ []), + do: request(:post, url, body, headers, options) + + @doc """ + Builds and performs http request. + + # Arguments: + `method` - :get, :post, :put, :delete + `url` - full url + `body` - request body + `headers` - a keyworld list of headers, e.g. `[{"content-type", "text/plain"}]` + `options` - custom, per-request middleware or adapter options + + # Returns: + `{:ok, %Tesla.Env{}}` or `{:error, error}` + + """ + @spec request(atom(), Request.url(), String.t(), Request.headers(), keyword()) :: + {:ok, Env.t()} | {:error, any()} + def request(method, url, body, headers, options) when is_binary(url) do uri = URI.parse(url) - host = uri.host |> to_charlist() + received_adapter_opts = Keyword.get(options, :adapter, []) + adapter_opts = Connection.options(uri, received_adapter_opts) + options = put_in(options[:adapter], adapter_opts) + params = Keyword.get(options, :params, []) + request = build_request(method, headers, options, url, body, params) - case uri.scheme do - "https" -> options ++ [ssl: [server_name_indication: host]] - _ -> options - end + adapter = Application.get_env(:tesla, :adapter) + client = Tesla.client([Tesla.Middleware.FollowRedirects], adapter) + + pid = Process.whereis(adapter_opts[:pool]) + + pool_alive? = + if adapter == Tesla.Adapter.Gun && pid do + Process.alive?(pid) + else + false + end + + request_opts = + adapter_opts + |> Enum.into(%{}) + |> Map.put(:env, Pleroma.Config.get([:env])) + |> Map.put(:pool_alive?, pool_alive?) + + response = request(client, request, request_opts) + + Connection.after_request(adapter_opts) + + response end - def process_request_options(options) do - config = Application.get_env(:pleroma, :http, []) - proxy = Keyword.get(config, :proxy_url, nil) - options = options ++ [hackney: [pool: :default]] + @spec request(Client.t(), keyword(), map()) :: {:ok, Env.t()} | {:error, any()} + def request(%Client{} = client, request, %{env: :test}), do: request_try(client, request) - case proxy do - nil -> options - _ -> options ++ [proxy: proxy] - end + def request(%Client{} = client, request, %{body_as: :chunks}) do + request_try(client, request) end - def get(url, headers \\ [], options \\ []), do: request(:get, url, "", headers, options) + def request(%Client{} = client, request, %{pool_alive?: false}) do + request_try(client, request) + end - def post(url, body, headers \\ [], options \\ []), - do: request(:post, url, body, headers, options) + def request(%Client{} = client, request, %{pool: pool, timeout: timeout}) do + :poolboy.transaction( + pool, + &Pleroma.Pool.Request.execute(&1, client, request, timeout), + timeout + ) + end + + @spec request_try(Client.t(), keyword()) :: {:ok, Env.t()} | {:error, any()} + def request_try(client, request) do + try do + Tesla.request(client, request) + rescue + e -> + {:error, e} + catch + :exit, e -> + {:error, e} + end + end + + defp build_request(method, headers, options, url, body, params) do + Builder.new() + |> Builder.method(method) + |> Builder.headers(headers) + |> Builder.opts(options) + |> Builder.url(url) + |> Builder.add_param(:body, :body, body) + |> Builder.add_param(:query, :query, params) + |> Builder.convert_to_keyword() + end end