frenzy/lib/frenzy/network.ex

71 lines
2.0 KiB
Elixir

defmodule Frenzy.Network do
require Logger
@http_redirect_codes [301, 302]
@spec http_get(String.t()) :: {:ok, Mojito.Response.t()} | {:error, term()}
def http_get(url) do
case Mojito.request(:get, url, [], "", transport_opts: [cacertfile: CAStore.file_path()]) do
{:ok, %Mojito.Response{status_code: 200} = response} ->
{:ok, response}
{:ok, %Mojito.Response{status_code: status_code, headers: headers}}
when status_code in @http_redirect_codes ->
headers
|> Enum.find(fn {name, _value} -> name == "location" end)
|> case do
{"location", new_url} ->
new_url =
case URI.parse(new_url) do
%URI{host: nil, path: path} ->
# relative path
%URI{URI.parse(url) | path: path} |> URI.to_string()
uri ->
uri
end
Logger.debug("Got 301 redirect from #{url} to #{new_url}")
http_get(new_url)
_ ->
{:error, "Missing Location header for redirect"}
end
{:ok, %Mojito.Response{status_code: 403}} ->
{:error, "403 Forbidden"}
{:ok, %Mojito.Response{status_code: 404}} ->
{:error, "404 Not Found"}
{:ok, %Mojito.Response{status_code: status_code}} ->
{:error, "HTTP #{status_code}"}
{:error, error} ->
{:error, error}
end
end
@gemini_success_codes 20..29
@gemini_redirect_codes 30..39
@spec gemini_request(String.t() | URI.t()) :: {:ok, Gemini.Response.t()} | {:error, term()}
def gemini_request(uri) do
case Gemini.request(uri) do
{:ok, %Gemini.Response{status: code} = response} when code in @gemini_success_codes ->
{:ok, response}
{:ok, %Gemini.Response{status: code, meta: new_url}}
when code in @gemini_redirect_codes ->
gemini_request(URI.merge(uri, new_url))
{:ok, %Gemini.Response{status: code}} ->
{:error, "Unhandled Gemini status code: #{code}"}
{:error, reason} ->
{:error, reason}
end
end
end