Public Access
lib/gemini: URLs split per RFC 3986 appendix B and resolved per section 5.2 (all 32 reference examples of 5.4 pass, with gemini:// for http://), the request form (no fragment, lower-case host, never an empty path), query encoding for input prompts, Saved Page paths; the response header (status, category, MIME type and parameters, 1024-byte meta limit); gemtext's line types; and display text for the Latin-1 fonts. 12 tests. Q86, decided after step 1: free heap stays above 40 KB in steady state and 20 KB during a handshake; a fetch won't start below 55 KB. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
29 lines
1.1 KiB
C++
29 lines
1.1 KiB
C++
#pragma once
|
|
|
|
#include <string>
|
|
|
|
namespace roro::gemini {
|
|
|
|
// A URL split per RFC 3986 (appendix B). For Gemini, the host is lower-cased and the port
|
|
// defaults to 1965.
|
|
struct Url {
|
|
std::string scheme, authority, host, path, query, fragment;
|
|
int port = -1;
|
|
bool hasAuthority = false, hasQuery = false, hasFragment = false;
|
|
int portOrDefault() const { return port > 0 ? port : 1965; }
|
|
};
|
|
|
|
// False unless it has a scheme and a host: only absolute URLs are fetched.
|
|
bool parseUrl(const std::string& text, Url& out);
|
|
bool isGemini(const std::string& url);
|
|
// `ref` against `base`, per RFC 3986 section 5.2 (dot segments included).
|
|
std::string resolve(const std::string& base, const std::string& ref);
|
|
// What goes on the wire: no fragment, lower-case host, never an empty path.
|
|
std::string requestUrl(const std::string& url);
|
|
// For input prompts: everything but unreserved characters percent-encoded (UTF-8 bytes).
|
|
std::string encodeQuery(const std::string& text);
|
|
// Where a Saved Page lives (Q82): /gemini/saved/<host>[_<port>]/<path>[~<query>].gmi
|
|
std::string savedPath(const std::string& url);
|
|
|
|
} // namespace roro::gemini
|