Botan 3.13.0
Crypto and TLS for C&
Botan::URI Class Referencefinal

#include <uri.h>

Classes

class  Authority

Public Types

using Host = Authority::Host
 A validated DNS name, or a literal IPv4 or IPv6 address.
using HostKind = Authority::HostKind
 Tag for the alternative held by Host.

Public Member Functions

const std::optional< Authority > & authority () const
const std::optional< std::string > & fragment () const
std::optional< std::reference_wrapper< const Host > > host () const
std::strong_ordering operator<=> (const URI &other) const
bool operator== (const URI &other) const
const std::string & original_input () const
const std::string & path () const
const std::optional< std::string > & query () const
std::optional< std::string_view > raw_authority () const
const std::string & scheme () const

Static Public Member Functions

static std::vector< URI > filter_scheme (std::string_view scheme, std::span< const URI > uris)
static std::optional< URI > from_string (std::string_view raw)

Detailed Description

URI (RFC 3986 subset)

Definition at line 25 of file uri.h.

Member Typedef Documentation

◆ Host

A validated DNS name, or a literal IPv4 or IPv6 address.

Definition at line 114 of file uri.h.

◆ HostKind

Tag for the alternative held by Host.

Definition at line 117 of file uri.h.

Member Function Documentation

◆ authority()

const std::optional< Authority > & Botan::URI::authority ( ) const
inline

Return the parsed URI authority, if this URI has one.

Definition at line 132 of file uri.h.

132{ return m_authority; }

Referenced by from_string(), and Botan::HTTP::http_sync().

◆ filter_scheme()

std::vector< URI > Botan::URI::filter_scheme ( std::string_view scheme,
std::span< const URI > uris )
static

Return a list of URIs (possibly empty) which match the specified scheme and which contain a non-empty authority

Definition at line 367 of file uri.cpp.

367 {
368 std::vector<URI> results;
369
370 const auto normalized_scheme = tolower_string(scheme);
371
372 for(const auto& uri : uris) {
373 if(uri.scheme() == normalized_scheme && uri.authority().has_value()) {
374 results.push_back(uri);
375 }
376 }
377
378 return results;
379}
const std::string & scheme() const
Definition uri.h:127
std::string tolower_string(std::string_view str)
Definition parsing.cpp:183

References scheme(), and Botan::tolower_string().

◆ fragment()

const std::optional< std::string > & Botan::URI::fragment ( ) const
inline

The fragment component, without the leading "#". Nullopt if no "#" was present; present-but-empty distinguishes "http://h/p#" from "http://h/p".

Definition at line 168 of file uri.h.

168{ return m_fragment; }

Referenced by from_string().

◆ from_string()

std::optional< URI > Botan::URI::from_string ( std::string_view raw)
static

Parse a URI, return nullopt on failure

Definition at line 164 of file uri.cpp.

164 {
165 // Empty string is not a valid URI
166 if(raw.empty()) {
167 return {};
168 }
169
170 // RFC 3986:
171 // scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
172 constexpr auto is_scheme_cont_char = CharacterValidityTable::alpha_numeric_plus("+-.");
173
174 const auto is_ascii_alpha = [](char c) -> bool { return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'); };
175
176 // Check the first scheme character
177 if(!is_ascii_alpha(raw.front())) {
178 return {};
179 }
180
181 // Scan the rest of the scheme
182 size_t i = 1;
183 while(i < raw.size() && is_scheme_cont_char(raw[i])) {
184 ++i;
185 }
186 // Scheme wasn't followed by ':' -> invalid
187 if(i >= raw.size() || raw[i] != ':') {
188 return {};
189 }
190
191 // Canonicalize the scheme
192 const std::string scheme = tolower_string(raw.substr(0, i));
193
194 auto rest = raw.substr(i + 1);
195
196 std::optional<Authority> parsed_authority;
197 std::string_view path_query_fragment;
198
199 if(rest.starts_with("//")) {
200 rest.remove_prefix(2); // Strip off the '//'
201
202 // Authority runs to the first '/', '?' or '#'. The remaining is `path ? query # fragment`,
203 // which is validated against the RFC 3986 character set.
204 const auto end = rest.find_first_of("/?#");
205 const auto authority = (end == std::string_view::npos) ? rest : rest.substr(0, end);
206 path_query_fragment = (end == std::string_view::npos) ? std::string_view{} : rest.substr(end);
207
208 // Parse and validate non-empty authority strings (hostname, IPv4, or IPv6 address)
209 if(!authority.empty()) {
210 parsed_authority = Authority::from_string(authority);
211 if(!parsed_authority.has_value()) {
212 return {};
213 }
214 }
215 } else {
216 path_query_fragment = rest;
217 }
218
219 // Validate any `path ? query # fragment` portions of the URL
220 if(!validate_path_query_fragment(path_query_fragment)) {
221 return {};
222 }
223
224 // Split into path / query / fragment. Validation above guarantees at most
225 // one '#', so the first '#' is the fragment delimiter, and within the
226 // pre-fragment portion the first '?' (if any) is the query delimiter.
227 const auto hash = path_query_fragment.find('#');
228 const auto pre_fragment =
229 (hash == std::string_view::npos) ? path_query_fragment : path_query_fragment.substr(0, hash);
230 std::optional<std::string> fragment;
231 if(hash != std::string_view::npos) {
232 fragment = std::string(path_query_fragment.substr(hash + 1));
233 }
234
235 const auto qmark = pre_fragment.find('?');
236 const auto path = (qmark == std::string_view::npos) ? pre_fragment : pre_fragment.substr(0, qmark);
237 std::optional<std::string> query;
238 if(qmark != std::string_view::npos) {
239 query = std::string(pre_fragment.substr(qmark + 1));
240 }
241
242 // Accept
243 return URI(
244 std::string(raw), scheme, std::move(parsed_authority), std::string(path), std::move(query), std::move(fragment));
245}
static constexpr CharacterValidityTable alpha_numeric_plus(std::string_view extras)
Definition charset.h:114
const std::optional< std::string > & fragment() const
Definition uri.h:168
const std::optional< std::string > & query() const
Definition uri.h:161
const std::optional< Authority > & authority() const
Definition uri.h:132
const std::string & path() const
Definition uri.h:154

References Botan::CharacterValidityTable::alpha_numeric_plus(), authority(), fragment(), Botan::URI::Authority::from_string(), path(), query(), scheme(), and Botan::tolower_string().

Referenced by Botan::AlternativeName::add_uri().

◆ host()

std::optional< std::reference_wrapper< const Host > > Botan::URI::host ( ) const
inline

Return the parsed host, if this URI has an authority. TODO(C++26) This can return std::optional<const Host&>

Definition at line 144 of file uri.h.

144 {
145 return m_authority.has_value() ? std::optional<std::reference_wrapper<const Host>>(m_authority->host())
146 : std::nullopt;
147 }

◆ operator<=>()

std::strong_ordering Botan::URI::operator<=> ( const URI & other) const

Order two URIs

Parameters
otherthe URI to compare against
Returns
the ordering of this URI relative to other

Definition at line 115 of file uri.cpp.

115 =>(const URI& other) const {
116 const bool has_authority = raw_authority().has_value();
117 const bool other_has_authority = other.raw_authority().has_value();
118
119 return std::tie(m_scheme, has_authority, m_authority, m_path, m_query, m_fragment) <=>
120 std::tie(
121 other.m_scheme, other_has_authority, other.m_authority, other.m_path, other.m_query, other.m_fragment);
122}
std::optional< std::string_view > raw_authority() const
Definition uri.cpp:130

References raw_authority().

◆ operator==()

bool Botan::URI::operator== ( const URI & other) const

Compare two URIs

Parameters
otherthe URI to compare against
Returns
true if the two URIs are equal

Definition at line 124 of file uri.cpp.

124 {
125 return m_scheme == other.m_scheme && raw_authority().has_value() == other.raw_authority().has_value() &&
126 m_authority == other.m_authority && m_path == other.m_path && m_query == other.m_query &&
127 m_fragment == other.m_fragment;
128}

References raw_authority().

◆ original_input()

const std::string & Botan::URI::original_input ( ) const
inline

The original input that was parsed.

Definition at line 173 of file uri.h.

173{ return m_raw; }

Referenced by Botan::URI::Authority::from_string().

◆ path()

const std::string & Botan::URI::path ( ) const
inline

The path component, preserved verbatim. Begins with "/" when present; empty if the parsed URI had no path (e.g. "http://example.com" or "http://example.com?q").

Definition at line 154 of file uri.h.

154{ return m_path; }

Referenced by from_string(), and Botan::HTTP::http_sync().

◆ query()

const std::optional< std::string > & Botan::URI::query ( ) const
inline

The query component, without the leading "?". Nullopt if no "?" was present; present-but-empty distinguishes "http://h/p?" from "http://h/p".

Definition at line 161 of file uri.h.

161{ return m_query; }

Referenced by from_string(), and Botan::HTTP::http_sync().

◆ raw_authority()

std::optional< std::string_view > Botan::URI::raw_authority ( ) const

Return the raw authority component if this URI included one, including the empty string for URIs such as "ldap:///CN=...".

Definition at line 130 of file uri.cpp.

130 {
131 const auto colon = m_raw.find(':');
132 BOTAN_ASSERT_NOMSG(colon != std::string::npos);
133
134 const size_t rest_offset = colon + 1;
135 if(m_raw.size() < rest_offset + 2 || m_raw[rest_offset] != '/' || m_raw[rest_offset + 1] != '/') {
136 return std::nullopt;
137 }
138
139 const size_t authority_start = rest_offset + 2;
140 const auto authority_end = m_raw.find_first_of("/?#", authority_start);
141 const size_t authority_len =
142 (authority_end == std::string::npos) ? std::string::npos : authority_end - authority_start;
143 return std::string_view(m_raw).substr(authority_start, authority_len);
144}
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75

References BOTAN_ASSERT_NOMSG.

Referenced by operator<=>(), and operator==().

◆ scheme()

const std::string & Botan::URI::scheme ( ) const
inline

Return the scheme, lowercase normalized

Definition at line 127 of file uri.h.

127{ return m_scheme; }

Referenced by filter_scheme(), from_string(), and Botan::HTTP::http_sync().


The documentation for this class was generated from the following files: