diff --git a/lib/chronoscope/gemini/connection_client.ex b/lib/chronoscope/gemini/connection_client.ex index 8299a22..05566aa 100644 --- a/lib/chronoscope/gemini/connection_client.ex +++ b/lib/chronoscope/gemini/connection_client.ex @@ -64,7 +64,13 @@ defmodule Chronoscope.Gemini.ConnectionClient do defp parse_response(response, peercert) do response |> Response.parse() - |> Map.put(:cert_expiration, Certificate.expiration_date(peercert)) - |> then(&{:ok, &1}) + + case Response.parse(response) do + {:ok, result} -> + {:ok, Map.put(result, :cert_expiration, Certificate.expiration_date(peercert))} + + {:error, error} -> + {:error, error} + end end end diff --git a/lib/chronoscope/gemini/response.ex b/lib/chronoscope/gemini/response.ex index 9574c9d..5b70843 100644 --- a/lib/chronoscope/gemini/response.ex +++ b/lib/chronoscope/gemini/response.ex @@ -1,6 +1,26 @@ defmodule Chronoscope.Gemini.Response do + @response_pattern ~r/^(?[0-9]{2}) (?.+)\r\n(?(?s:.)*)/ + def parse(response) do - # TODO - %{status: 20, mime_type: "text/gemini", body: to_string(response)} + response + |> to_string() + |> parse_response() + end + + defp parse_response(response) do + case Regex.named_captures(@response_pattern, response) do + nil -> + {:error, "bad response: #{response}"} + + match -> + match + |> Map.update!("status", &String.to_integer/1) + |> to_atom_keys() + |> then(&{:ok, &1}) + end + end + + defp to_atom_keys(response) do + Map.new(response, fn {k, v} -> {String.to_atom(k), v} end) end end diff --git a/lib/chronoscope_web/controllers/api/v1/gemini/connection_controller.ex b/lib/chronoscope_web/controllers/api/v1/gemini/connection_controller.ex index d10bc7a..7d77324 100644 --- a/lib/chronoscope_web/controllers/api/v1/gemini/connection_controller.ex +++ b/lib/chronoscope_web/controllers/api/v1/gemini/connection_controller.ex @@ -61,7 +61,7 @@ defmodule ChronoscopeWeb.API.V1.Gemini.ConnectionController do end defp format_response(response) do - Map.take(response, [:status, :mime_type, :body]) + Map.take(response, [:status, :mime_type, :body, :cert_expiration]) end defp bad_request_response(conn, message) do diff --git a/test/chronoscope/gemini/client_test.exs b/test/chronoscope/gemini/client_test.exs index 092ff38..76b373f 100644 --- a/test/chronoscope/gemini/client_test.exs +++ b/test/chronoscope/gemini/client_test.exs @@ -53,12 +53,13 @@ defmodule Chronoscope.Gemini.ClientTest do end test ":connect - not cached" do + response ="20 text/gemini\r\nHello!" |> to_charlist() peercert = peercert() peercert_expiration = Certificate.expiration_date(peercert) SSLMock |> expect(:connect, fn ~c"localhost", 4444, _, _ -> {:ok, :socket} end) - |> expect(:send, fn :socket, _ -> send_ssl_response([]) end) + |> expect(:send, fn :socket, _ -> send_ssl_response(response) end) |> expect(:peercert, fn :socket -> {:ok, peercert} end) |> expect(:close, fn :socket -> :ok end)