Botan 3.13.0
Crypto and TLS for C&
uri.h
Go to the documentation of this file.
1/*
2* (C) 2026 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#ifndef BOTAN_URI_H_
8#define BOTAN_URI_H_
9
10#include <botan/dns_name.h>
11#include <botan/ipv4_address.h>
12#include <botan/ipv6_address.h>
13#include <botan/types.h>
14#include <functional>
15#include <optional>
16#include <string>
17#include <string_view>
18#include <variant>
19
20namespace Botan {
21
22/**
23* URI (RFC 3986 subset)
24*/
25class BOTAN_PUBLIC_API(3, 13) URI final {
26 public:
27 /**
28 * The optional authority component of a URI: a validated DNS name, IPv4
29 * literal, or IPv6 literal, with an optional port.
30 */
31 class BOTAN_PUBLIC_API(3, 13) Authority final {
32 public:
33 /**
34 * A validated DNS name, or a literal IPv4 or IPv6 address.
35 */
36 using Host = std::variant<DNSName, IPv4Address, IPv6Address>;
37
38 /**
39 * Tag for the alternative held by `Host`.
40 */
41 enum class HostKind : uint8_t {
42 DNS = 0,
43 IPv4 = 1,
44 IPv6 = 2,
45 };
46
47 /**
48 * Parse a bare authority "host[:port]" or "[ipv6][:port]".
49 * Returns nullopt for any parse failure.
50 */
51 static std::optional<Authority> from_string(std::string_view raw);
52
53 /**
54 * Parsed host: a DNS name, an IPv4 literal, or an IPv6 literal.
55 */
56 const Host& host() const { return m_host; }
57
58 /**
59 * Which alternative of `host()` is held.
60 */
61 HostKind host_kind() const;
62
63 /**
64 * The host as a string: DNS names and dotted-IPv4 literals are
65 * returned verbatim; IPv6 literals are returned without surrounding
66 * brackets. Lowercased for DNS / IPv4; the IPv6 form is whatever
67 * `IPv6Address::to_string` produces.
68 */
69 std::string host_to_string() const;
70
71 /**
72 * Port if present; nullopt otherwise.
73 */
74 std::optional<uint16_t> port() const { return m_port; }
75
76 /**
77 * The original input that was parsed
78 */
79 const std::string& original_input() const { return m_raw; }
80
81 /**
82 * The userinfo component, preserved verbatim (no case normalization
83 * or pct-decoding) and compared verbatim for identity. nullopt if no
84 * "@" was present; present-but-empty (e.g. "https://@example.com/")
85 * is distinguished from absent.
86 */
87 const std::optional<std::string>& userinfo() const { return m_userinfo; }
88
89 /**
90 * Order two authorities
91 * @param other the authority to compare against
92 * @return the ordering of this authority relative to other
93 */
94 std::strong_ordering operator<=>(const Authority& other) const;
95
96 /**
97 * Compare two authorities
98 * @param other the authority to compare against
99 * @return true if the two authorities are equal
100 */
101 bool operator==(const Authority& other) const;
102
103 private:
104 Authority(std::string raw, std::optional<std::string> userinfo, Host host, std::optional<uint16_t> port) :
105 m_raw(std::move(raw)), m_userinfo(std::move(userinfo)), m_host(std::move(host)), m_port(port) {}
106
107 std::string m_raw;
108 std::optional<std::string> m_userinfo;
109 Host m_host;
110 std::optional<uint16_t> m_port;
111 };
112
113 /// A validated DNS name, or a literal IPv4 or IPv6 address
115
116 /// Tag for the alternative held by `Host`
118
119 /**
120 * Parse a URI, return nullopt on failure
121 */
122 static std::optional<URI> from_string(std::string_view raw);
123
124 /**
125 * Return the scheme, lowercase normalized
126 */
127 const std::string& scheme() const { return m_scheme; }
128
129 /**
130 * Return the parsed URI authority, if this URI has one.
131 */
132 const std::optional<Authority>& authority() const { return m_authority; }
133
134 /**
135 * Return the raw authority component if this URI included one, including
136 * the empty string for URIs such as "ldap:///CN=...".
137 */
138 std::optional<std::string_view> raw_authority() const;
139
140 /**
141 * Return the parsed host, if this URI has an authority.
142 * TODO(C++26) This can return std::optional<const Host&>
143 */
144 std::optional<std::reference_wrapper<const Host>> host() const {
145 return m_authority.has_value() ? std::optional<std::reference_wrapper<const Host>>(m_authority->host())
146 : std::nullopt;
147 }
148
149 /**
150 * The path component, preserved verbatim. Begins with "/" when present;
151 * empty if the parsed URI had no path (e.g. "http://example.com" or
152 * "http://example.com?q").
153 */
154 const std::string& path() const { return m_path; }
155
156 /**
157 * The query component, without the leading "?". Nullopt if no "?" was
158 * present; present-but-empty distinguishes "http://h/p?" from
159 * "http://h/p".
160 */
161 const std::optional<std::string>& query() const { return m_query; }
162
163 /**
164 * The fragment component, without the leading "#". Nullopt if no "#"
165 * was present; present-but-empty distinguishes "http://h/p#" from
166 * "http://h/p".
167 */
168 const std::optional<std::string>& fragment() const { return m_fragment; }
169
170 /**
171 * The original input that was parsed.
172 */
173 const std::string& original_input() const { return m_raw; }
174
175 /**
176 * Order two URIs
177 * @param other the URI to compare against
178 * @return the ordering of this URI relative to other
179 */
180 std::strong_ordering operator<=>(const URI& other) const;
181
182 /**
183 * Compare two URIs
184 * @param other the URI to compare against
185 * @return true if the two URIs are equal
186 */
187 bool operator==(const URI& other) const;
188
189 /**
190 * Return a list of URIs (possibly empty) which match the specified scheme
191 * and which contain a non-empty authority
192 */
193 static std::vector<URI> filter_scheme(std::string_view scheme, std::span<const URI> uris);
194
195 private:
196 URI(std::string raw,
197 std::string scheme,
198 std::optional<Authority> authority,
199 std::string path,
200 std::optional<std::string> query,
201 std::optional<std::string> fragment) :
202 m_raw(std::move(raw)),
203 m_scheme(std::move(scheme)),
204 m_authority(std::move(authority)),
205 m_path(std::move(path)),
206 m_query(std::move(query)),
207 m_fragment(std::move(fragment)) {}
208
209 std::string m_raw;
210 std::string m_scheme;
211 std::optional<Authority> m_authority;
212 std::string m_path;
213 std::optional<std::string> m_query;
214 std::optional<std::string> m_fragment;
215};
216
217} // namespace Botan
218
219#endif
#define BOTAN_PUBLIC_API(maj, min)
Definition api.h:21
const std::optional< std::string > & userinfo() const
Definition uri.h:87
const Host & host() const
Definition uri.h:56
std::optional< uint16_t > port() const
Definition uri.h:74
std::variant< DNSName, IPv4Address, IPv6Address > Host
Definition uri.h:36
const std::string & original_input() const
Definition uri.h:79
const std::optional< std::string > & fragment() const
Definition uri.h:168
static std::optional< URI > from_string(std::string_view raw)
Definition uri.cpp:164
const std::string & scheme() const
Definition uri.h:127
std::optional< std::reference_wrapper< const Host > > host() const
Definition uri.h:144
std::strong_ordering operator<=>(const URI &other) const
Definition uri.cpp:115
const std::optional< std::string > & query() const
Definition uri.h:161
Authority::HostKind HostKind
Tag for the alternative held by Host.
Definition uri.h:117
const std::string & original_input() const
Definition uri.h:173
const std::optional< Authority > & authority() const
Definition uri.h:132
bool operator==(const URI &other) const
Definition uri.cpp:124
Authority::Host Host
A validated DNS name, or a literal IPv4 or IPv6 address.
Definition uri.h:114
const std::string & path() const
Definition uri.h:154
auto operator<=>(const Strong< T, Tags... > &lhs, const Strong< T, Tags... > &rhs)
bool operator==(const AlgorithmIdentifier &x, const AlgorithmIdentifier &y)
Definition alg_id.cpp:54