Sourcemeta Core 0.0.0
Loading...
Searching...
No Matches
URI

A strict RFC 3986 URI implementation, with RFC 3987 IRI syntax checking. More...

Classes

class  sourcemeta::core::URI
class  sourcemeta::core::URIParseError
class  sourcemeta::core::URIError

Detailed Description

A strict RFC 3986 URI implementation, with RFC 3987 IRI syntax checking.

This functionality is included as follows:

#include <sourcemeta/core/uri.h>

Class Documentation

◆ sourcemeta::core::URI

class sourcemeta::core::URI

A parsed URI that can be inspected, resolved, and recomposed

Public Member Functions

 URI ()=default
 Default constructor creates an empty URI.
 URI (const URI &)=default
 Copy constructor.
 URI (URI &&) noexcept=default
 Move constructor.
template<typename T>
 URI (T &&input)
 URI (std::istream &input)
auto is_absolute () const noexcept -> bool
auto is_urn () const -> bool
auto is_tag () const -> bool
auto is_mailto () const -> bool
auto is_file () const -> bool
auto is_http () const -> bool
auto is_https () const -> bool
auto is_fragment_only () const -> bool
auto is_relative () const -> bool
auto is_ipv4 () const -> bool
auto is_ipv6 () const -> bool
auto is_loopback () const -> bool
auto is_localhost () const -> bool
auto empty () const -> bool
auto scheme () const -> std::optional< std::string_view >
auto host () const -> std::optional< std::string_view >
auto port () const -> std::optional< std::uint32_t >
auto authority () const -> std::optional< std::string >
auto path () const -> std::optional< std::string_view >
auto path (const std::string &path) -> URI &
auto path (std::string &&path) -> URI &
auto append_path (std::string_view path) -> URI &
auto append_path (const URI &reference) -> URI &
auto append_path (URI &&reference) -> URI &
auto extension (std::string &&extension) -> URI &
auto fragment () const -> std::optional< std::string_view >
auto fragment (const std::string_view fragment) -> URI &
auto query () const -> std::optional< Query >
auto query (const std::string_view query) -> URI &
auto recompose () const -> std::string
auto recompose_relative () const -> std::string
auto recompose_without_fragment () const -> std::optional< std::string >
auto canonicalize () -> URI &
auto to_path () const -> std::filesystem::path
auto resolve_from (const URI &base) -> URI &
auto relative_to (const URI &base) -> URI &
auto rebase (const URI &base, const URI &new_base) -> URI &
auto rebase (const URI &base, URI &&new_base) -> URI &
auto has_same_authority (const URI &other) const noexcept -> bool
auto userinfo () const -> std::optional< std::string_view >
auto userinfo (const std::string_view userinfo) -> URI &
auto is_internationalized () const noexcept -> bool

Static Public Member Functions

static auto from_fragment (const std::string_view fragment) -> URI
static auto from_path (const std::filesystem::path &path) -> URI
static auto from_iri (std::string_view input) -> URI
static auto canonicalize (std::string_view input) -> std::string
static auto escape (std::string_view input, bool maybe_encoded=false) -> std::string
template<typename Output>
static auto escape (const std::string_view input, Output &output, const bool maybe_encoded=false) -> void
template<typename Output>
static auto append_query_parameter (Output &sink, const std::string_view name, const std::string_view value, const char opener='?') -> void
static auto unescape (std::string_view input) -> std::string
template<typename Output>
static auto unescape_form (const std::string_view input, Output &output) -> bool
static auto normalize_path (std::string_view path) -> std::string
static auto is_scheme (std::string_view input) noexcept -> bool
static auto is_gen_delim (char character) noexcept -> bool
static auto is_uri (std::string_view input) noexcept -> bool
static auto is_uri_reference (std::string_view input) noexcept -> bool
static auto is_iri (std::string_view input) noexcept -> bool
static auto is_iri_reference (std::string_view input) noexcept -> bool
static auto strip_path_prefix (std::string_view path, std::string_view prefix) -> std::optional< std::string >
static auto rebase_path (std::string_view path, std::string_view old_prefix, std::string_view new_prefix) -> std::optional< std::string >

Constructor & Destructor Documentation

◆ URI() [1/2]

template<typename T>
sourcemeta::core::URI::URI ( T && input)
inlineexplicit

This constructor creates a URI from a string. For example:

#include <sourcemeta/core/uri.h>
const sourcemeta::core::URI uri{"https://www.sourcemeta.com"};
Definition uri.h:43

◆ URI() [2/2]

sourcemeta::core::URI::URI ( std::istream & input)

This constructor creates a URI from a C++ input stream. For example:

#include <sourcemeta/core/uri.h>
#include <sstream>
std::istringstream input{"https://www.sourcemeta.com"};
const sourcemeta::core::URI uri{input};

Member Function Documentation

◆ append_path() [1/3]

auto sourcemeta::core::URI::append_path ( const URI & reference) -> URI &

Append a path to the existing URI from a parsed reference. The reference must contain only a path. A scheme, authority, query, or fragment throws URIError. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
sourcemeta::core::URI uri{"https://www.sourcemeta.com/foo"};
const sourcemeta::core::URI reference{"bar/baz"};
uri.append_path(reference);
assert(uri.recompose() == "https://www.sourcemeta.com/foo/bar/baz");
auto append_path(std::string_view path) -> URI &
auto recompose() const -> std::string

◆ append_path() [2/3]

auto sourcemeta::core::URI::append_path ( std::string_view path) -> URI &

Append a path to the existing URI path or set a path if such component does not exist in the URI. The argument is treated as a path component to merge in. Authority prefixes and ? or # delimiters throw URIError. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
sourcemeta::core::URI uri{"https://www.sourcemeta.com/foo"};
uri.append_path("bar/baz");
assert(uri.recompose() == "https://www.sourcemeta.com/foo/bar/baz");

◆ append_path() [3/3]

auto sourcemeta::core::URI::append_path ( URI && reference) -> URI &

Append a path to the existing URI from a parsed reference, moving the path out of the reference rather than copying it. The reference must contain only a path. A scheme, authority, query, or fragment throws URIError. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
#include <utility>
sourcemeta::core::URI uri{"https://www.sourcemeta.com/foo"};
sourcemeta::core::URI reference{"bar/baz"};
uri.append_path(std::move(reference));
assert(uri.recompose() == "https://www.sourcemeta.com/foo/bar/baz");

◆ append_query_parameter()

template<typename Output>
auto sourcemeta::core::URI::append_query_parameter ( Output & sink,
const std::string_view name,
const std::string_view value,
const char opener = '?' ) -> void
inlinestatic

Append a percent-encoded name and value pair to a query, form body, or fragment under construction (RFC 3986 Section 2.1), joining it to any preceding pair. The caller writes the opening character of a fresh parameter list, the "?" of a query unless overridden through the opener, and the sink must not alias the name or value. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
#include <string>
std::string query{"https://example.com/authorize?"};
"code");
"openid profile");
assert(query ==
"https://example.com/authorize?response_type=code"
"&scope=openid%20profile");
static auto append_query_parameter(Output &sink, const std::string_view name, const std::string_view value, const char opener='?') -> void
Definition uri.h:931
auto query() const -> std::optional< Query >

◆ authority()

auto sourcemeta::core::URI::authority ( ) const -> std::optional< std::string >
nodiscard

Get the recomposed authority component of the URI, if any, in the RFC 3986 form [ userinfo "@" ] host [ ":" port ], with IPv6 hosts wrapped in brackets. A URI with an empty authority, such as file:///path, returns a present but empty value, so a caller must not treat a present value as necessarily non-empty. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
const sourcemeta::core::URI uri{"https://example.com:8443/foo"};
assert(uri.authority().has_value());
assert(uri.authority().value() == "example.com:8443");
const sourcemeta::core::URI file{"file:///path"};
assert(file.authority().has_value());
assert(file.authority().value().empty());
auto authority() const -> std::optional< std::string >

◆ canonicalize() [1/2]

auto sourcemeta::core::URI::canonicalize ( ) -> URI &

Canonicalize a URI. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
sourcemeta::core::URI uri{"hTtP://exAmpLe.com:80/TEST"};
assert(uri.recompose() == "http://example.com/TEST");
auto canonicalize() -> URI &

◆ canonicalize() [2/2]

auto sourcemeta::core::URI::canonicalize ( std::string_view input) -> std::string
static

A convenient method to canonicalize and recompose a URI from a string. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
const auto result{
sourcemeta::core::URI::canonicalize("hTtP://exAmpLe.com:80/TEST")};
assert(result == "http://example.com/TEST");

◆ empty()

auto sourcemeta::core::URI::empty ( ) const -> bool
nodiscard

Check if the URI corresponds to the empty URI. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
assert(uri.empty());
auto empty() const -> bool

◆ escape() [1/2]

template<typename Output>
auto sourcemeta::core::URI::escape ( const std::string_view input,
Output & output,
const bool maybe_encoded = false ) -> void
inlinestatic

Percent-encode a string per RFC 3986, appending the result to a string like output sink rather than allocating a new string. Besides a std::string the sink can be a wiping string for secret material. The input can optionally be treated as possibly already encoded. The output must not alias the input. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
#include <string>
std::string output{"key="};
sourcemeta::core::URI::escape("foo bar", output);
assert(output == "key=foo%20bar");
static auto escape(std::string_view input, bool maybe_encoded=false) -> std::string

◆ escape() [2/2]

auto sourcemeta::core::URI::escape ( std::string_view input,
bool maybe_encoded = false ) -> std::string
staticnodiscard

Percent-encode a string per RFC 3986, escaping every octet outside the unreserved set. The input can optionally be treated as possibly already encoded, preserving valid escapes and decoding needlessly encoded unreserved octets so the result is stable under repeated application. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
assert(sourcemeta::core::URI::escape("foo bar/baz") == "foo%20bar%2Fbaz");
assert(sourcemeta::core::URI::escape("a b%2Fc", true) == "a%20b%2Fc");

◆ extension()

auto sourcemeta::core::URI::extension ( std::string && extension) -> URI &

If the URI has a path, this method sets or replace the extension in the path. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
sourcemeta::core::URI uri{"https://www.sourcemeta.com/foo"};
uri.extension("json");
assert(uri.recompose() == "https://www.sourcemeta.com/foo.json");
auto extension(std::string &&extension) -> URI &

◆ fragment() [1/2]

auto sourcemeta::core::URI::fragment ( ) const -> std::optional< std::string_view >
nodiscard

Get the fragment part of the URI, if any. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
const sourcemeta::core::URI uri{"https://www.sourcemeta.com/#foo"};
assert(uri.fragment().has_value());
assert(uri.fragment().value() == "foo");
auto fragment() const -> std::optional< std::string_view >

◆ fragment() [2/2]

auto sourcemeta::core::URI::fragment ( const std::string_view fragment) -> URI &

Set the fragment part of the URI. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
sourcemeta::core::URI uri{"https://www.sourcemeta.com"};
const std::string fragment{"foo"};
assert(uri.fragment().has_value());
assert(uri.fragment().value() == "foo");

◆ from_fragment()

auto sourcemeta::core::URI::from_fragment ( const std::string_view fragment) -> URI
static

Create a URI from a fragment. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
assert(uri.recompose() == "#foo");
static auto from_fragment(const std::string_view fragment) -> URI

◆ from_iri()

auto sourcemeta::core::URI::from_iri ( std::string_view input) -> URI
static

Create a URI from a string that may be an Internationalized Resource Identifier (IRI) as defined by RFC 3987, accepting the non-ASCII characters that a plain URI does not permit. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
const auto
uri{sourcemeta::core::URI::from_iri("https://example.com/café")};
assert(uri.recompose() == "https://example.com/café");
static auto from_iri(std::string_view input) -> URI

◆ from_path()

auto sourcemeta::core::URI::from_path ( const std::filesystem::path & path) -> URI
static

Create a URI from a file system path. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
#include <filesystem>
const std::filesystem::path path{"/foo/bar"};
assert(uri.recompose() == "file:///foo/bar");
static auto from_path(const std::filesystem::path &path) -> URI
auto path() const -> std::optional< std::string_view >

◆ has_same_authority()

auto sourcemeta::core::URI::has_same_authority ( const URI & other) const -> bool
nodiscardnoexcept

Check whether two URIs share the same authority component. The authority is the user information, host, and port per RFC 3986 Section 3.2. The scheme is not part of the authority and is not compared. Comparison is byte-exact on the stored values, so call canonicalize() first if you want host case-insensitivity or default-port elision. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
const sourcemeta::core::URI left{"https://example.com/foo"};
const sourcemeta::core::URI right{"https://example.com/bar"};
assert(left.has_same_authority(right));
auto has_same_authority(const URI &other) const noexcept -> bool

◆ host()

auto sourcemeta::core::URI::host ( ) const -> std::optional< std::string_view >
nodiscard

Get the host part of the URI, if any. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
const sourcemeta::core::URI uri{"https://www.sourcemeta.com"};
assert(uri.host().has_value());
assert(uri.host().value() == "www.sourcemeta.com");
auto host() const -> std::optional< std::string_view >

◆ is_absolute()

auto sourcemeta::core::URI::is_absolute ( ) const -> bool
nodiscardnoexcept

Check if the URI is absolute. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
const sourcemeta::core::URI uri{"https://www.sourcemeta.com"};
assert(uri.is_absolute());
auto is_absolute() const noexcept -> bool

◆ is_file()

auto sourcemeta::core::URI::is_file ( ) const -> bool
nodiscard

Check if the URI is a file URI. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
sourcemeta::core::URI uri{"file:///home/jviotti/foo.txt"};
assert(uri.is_file());
auto is_file() const -> bool

◆ is_fragment_only()

auto sourcemeta::core::URI::is_fragment_only ( ) const -> bool
nodiscard

Check if the URI only consists of a fragment. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
const sourcemeta::core::URI uri{"#foo"};
assert(uri.is_fragment_only());
auto is_fragment_only() const -> bool

◆ is_gen_delim()

auto sourcemeta::core::URI::is_gen_delim ( char character) -> bool
staticnodiscardnoexcept

Check if the given character is a URI generic delimiter per RFC 3986 (":" / "/" / "?" / "#" / "[" / "]" / "@"). For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
static auto is_gen_delim(char character) noexcept -> bool

◆ is_http()

auto sourcemeta::core::URI::is_http ( ) const -> bool
nodiscard

Check if the URI has the HTTP scheme (RFC 9110 Section 4.2.1), accepting any scheme case (RFC 3986 Section 3.1). For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
sourcemeta::core::URI uri{"http://www.sourcemeta.com"};
assert(uri.is_http());
auto is_http() const -> bool

◆ is_https()

auto sourcemeta::core::URI::is_https ( ) const -> bool
nodiscard

Check if the URI has the https scheme (RFC 9110 Section 4.2.2), accepting any scheme case (RFC 3986 Section 3.1). For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
sourcemeta::core::URI uri{"https://www.sourcemeta.com"};
assert(uri.is_https());
auto is_https() const -> bool

◆ is_internationalized()

auto sourcemeta::core::URI::is_internationalized ( ) const -> bool
nodiscardnoexcept

Check whether this object holds an Internationalized Resource Identifier (IRI) as defined by RFC 3987, rather than a plain URI. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
const auto
iri{sourcemeta::core::URI::from_iri("https://example.com/foo")};
assert(iri.is_internationalized());
assert(!sourcemeta::core::URI{"https://example.com/foo"}.is_internationalized());
auto is_internationalized() const noexcept -> bool

◆ is_ipv4()

auto sourcemeta::core::URI::is_ipv4 ( ) const -> bool
nodiscard

Check if the host is an IPv4 address. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
sourcemeta::core::URI uri{"http://192.168.1.1/index.html"};
assert(uri.is_ipv4());
auto is_ipv4() const -> bool

◆ is_ipv6()

auto sourcemeta::core::URI::is_ipv6 ( ) const -> bool
nodiscard

Check if the host is an IPv6 address. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
sourcemeta::core::URI uri{"http://[::1]"};
assert(uri.is_ipv6());
auto is_ipv6() const -> bool

◆ is_iri()

auto sourcemeta::core::URI::is_iri ( std::string_view input) -> bool
staticnodiscardnoexcept

Check if the given string is a valid absolute IRI (has a scheme) per RFC 3987 without constructing a full URI object. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
assert(sourcemeta::core::URI::is_iri("https://example.com/path"));
assert(!sourcemeta::core::URI::is_iri("relative/path"));
static auto is_iri(std::string_view input) noexcept -> bool

◆ is_iri_reference()

auto sourcemeta::core::URI::is_iri_reference ( std::string_view input) -> bool
staticnodiscardnoexcept

Check if the given string is a valid IRI reference per RFC 3987 (absolute or relative) without constructing a full URI object. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
assert(sourcemeta::core::URI::is_iri_reference("https://example.com"));
assert(sourcemeta::core::URI::is_iri_reference("relative/path"));
static auto is_iri_reference(std::string_view input) noexcept -> bool

◆ is_localhost()

auto sourcemeta::core::URI::is_localhost ( ) const -> bool
nodiscard

Check if the host is the special-use domain name localhost or a name falling within it, such as foo.localhost, in any case and with or without the trailing dot of the absolute form (RFC 6761 Section 6.3). A loopback IP literal is not a localhost name. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
sourcemeta::core::URI uri{"http://localhost:8000"};
assert(uri.is_localhost());
sourcemeta::core::URI address{"http://127.0.0.1:8000"};
assert(!address.is_localhost());
auto is_localhost() const -> bool

◆ is_loopback()

auto sourcemeta::core::URI::is_loopback ( ) const -> bool
nodiscard

Check if the host is a loopback IP literal, any address in 127.0.0.0/8 (RFC 1122 Section 3.2.1.3), ::1 (RFC 4291 Section 2.5.3), or an IPv4-mapped or IPv4-compatible IPv6 address embedding a 127.0.0.0/8 address (RFC 4291 Section 2.5.5). The name localhost is deliberately not a loopback host, as it usually resolves to one but that is a different claim (RFC 8252 Section 8.3). For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
sourcemeta::core::URI uri{"http://127.0.0.1:8000"};
assert(uri.is_loopback());
sourcemeta::core::URI name{"http://localhost:8000"};
assert(!name.is_loopback());
auto is_loopback() const -> bool

◆ is_mailto()

auto sourcemeta::core::URI::is_mailto ( ) const -> bool
nodiscard

Check if the URI has the mailto scheme. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
const sourcemeta::core::URI uri{"mailto:joe@example.com"};
assert(uri.is_mailto());
auto is_mailto() const -> bool

◆ is_relative()

auto sourcemeta::core::URI::is_relative ( ) const -> bool
nodiscard

Check if the URI is relative. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
sourcemeta::core::URI uri{"./foo"};
assert(uri.is_relative());
auto is_relative() const -> bool

◆ is_scheme()

auto sourcemeta::core::URI::is_scheme ( std::string_view input) -> bool
staticnodiscardnoexcept

Check if the given string is a valid URI scheme per RFC 3986 (ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )). For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
static auto is_scheme(std::string_view input) noexcept -> bool

◆ is_tag()

auto sourcemeta::core::URI::is_tag ( ) const -> bool
nodiscard

Check if the URI is a tag as described by RFC 4151. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
const sourcemeta::core::URI uri{"tag:yaml.org,2002:int"};
assert(uri.is_tag());
auto is_tag() const -> bool

◆ is_uri()

auto sourcemeta::core::URI::is_uri ( std::string_view input) -> bool
staticnodiscardnoexcept

Check if the given string is a valid absolute URI (has a scheme) per RFC 3986 without constructing a full URI object. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
assert(sourcemeta::core::URI::is_uri("https://example.com/path"));
assert(!sourcemeta::core::URI::is_uri("://bad"));
assert(!sourcemeta::core::URI::is_uri("relative/path"));
static auto is_uri(std::string_view input) noexcept -> bool

◆ is_uri_reference()

auto sourcemeta::core::URI::is_uri_reference ( std::string_view input) -> bool
staticnodiscardnoexcept

Check if the given string is a valid URI reference per RFC 3986 (absolute or relative) without constructing a full URI object. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
assert(sourcemeta::core::URI::is_uri_reference("https://example.com"));
assert(sourcemeta::core::URI::is_uri_reference("relative/path"));
static auto is_uri_reference(std::string_view input) noexcept -> bool

◆ is_urn()

auto sourcemeta::core::URI::is_urn ( ) const -> bool
nodiscard

Check if the URI is a URN. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
const sourcemeta::core::URI uri{"urn:example:schema"};
assert(uri.is_urn());
auto is_urn() const -> bool

◆ normalize_path()

auto sourcemeta::core::URI::normalize_path ( std::string_view path) -> std::string
staticnodiscard

Remove the "." and ".." segments from a URI path per RFC 3986 Section 5.2.4, preserving leading ".." segments in a relative path. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
assert(sourcemeta::core::URI::normalize_path("/foo/bar/../baz") ==
"/foo/baz");
static auto normalize_path(std::string_view path) -> std::string

◆ path() [1/3]

auto sourcemeta::core::URI::path ( ) const -> std::optional< std::string_view >
nodiscard

Get the path part of the URI, if any. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
uri{"https://www.sourcemeta.com/foo/bar"};
assert(uri.path().has_value());
assert(uri.path().value() == "/foo/bar");

◆ path() [2/3]

auto sourcemeta::core::URI::path ( const std::string & path) -> URI &

Set the path part of the URI. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
sourcemeta::core::URI uri{"https://www.sourcemeta.com"};
const std::string path{"/foo/bar"};
uri.path(path);
assert(uri.path().has_value());
assert(uri.path().value() == "/foo/bar");

◆ path() [3/3]

auto sourcemeta::core::URI::path ( std::string && path) -> URI &

Set the path part of the URI with move semantics. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
sourcemeta::core::URI uri{"https://www.sourcemeta.com"};
std::string path{"/foo/bar"};
uri.path(std::move(path));
assert(uri.path().has_value());
assert(uri.path().value() == "/foo/bar");

◆ port()

auto sourcemeta::core::URI::port ( ) const -> std::optional< std::uint32_t >
nodiscard

Get the port part of the URI, if any. Parsing rejects a port that does not fit in 32 bits even though RFC 3986 leaves the production unbounded. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
const sourcemeta::core::URI uri{"http://localhost:8000"};
assert(uri.port().has_value());
assert(uri.port().value() == 8000);
auto port() const -> std::optional< std::uint32_t >

◆ query() [1/2]

auto sourcemeta::core::URI::query ( ) const -> std::optional< Query >
nodiscard

Get the query part of the URI as a navigable view, if any. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
uri{"https://www.sourcemeta.com/?foo=bar"};
assert(uri.query().has_value());
assert(uri.query().value().raw() == "foo=bar");

◆ query() [2/2]

auto sourcemeta::core::URI::query ( const std::string_view query) -> URI &

Set the query part of the URI. A leading ? in the input is stripped. Passing an empty string clears the query. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
sourcemeta::core::URI uri{"https://www.sourcemeta.com"};
uri.query("foo=bar");
assert(uri.query().has_value());
assert(uri.query().value().raw() == "foo=bar");

◆ rebase() [1/2]

auto sourcemeta::core::URI::rebase ( const URI & base,
const URI & new_base ) -> URI &

Move a URI that lies under a base to the same position under a new base. A URI that is neither the base nor under it is left intact, and so is one that only shares a textual prefix without matching whole path segments. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
sourcemeta::core::URI uri{"https://example.com/foo/bar/baz"};
const sourcemeta::core::URI base{"https://example.com/foo"};
const sourcemeta::core::URI new_base{"/qux"};
uri.rebase(base, new_base);
assert(uri.recompose() == "/qux/bar/baz");
auto rebase(const URI &base, const URI &new_base) -> URI &

◆ rebase() [2/2]

auto sourcemeta::core::URI::rebase ( const URI & base,
URI && new_base ) -> URI &

Move a URI that lies under a base to the same position under a new base, taking components out of new_base rather than copying them. A URI that is neither the base nor under it is left intact. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
#include <utility>
sourcemeta::core::URI uri{"https://example.com/foo/bar/baz"};
const sourcemeta::core::URI base{"https://example.com/foo"};
sourcemeta::core::URI new_base{"/qux"};
uri.rebase(base, std::move(new_base));
assert(uri.recompose() == "/qux/bar/baz");

◆ rebase_path()

auto sourcemeta::core::URI::rebase_path ( std::string_view path,
std::string_view old_prefix,
std::string_view new_prefix ) -> std::optional< std::string >
staticnodiscard

Replace a URI path prefix with a new prefix. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
"/foo/bar/baz", "/foo", "https://example.com")};
assert(result.has_value());
assert(result.value() == "https://example.com/bar/baz");
static auto rebase_path(std::string_view path, std::string_view old_prefix, std::string_view new_prefix) -> std::optional< std::string >

◆ recompose()

auto sourcemeta::core::URI::recompose ( ) const -> std::string
nodiscard

Recompose a URI as established by RFC 3986. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
uri{"https://www.sourcemeta.com/foo/../bar"};
assert(uri.recompose() == "https://www.sourcemeta.com/foo/../bar");

◆ recompose_relative()

auto sourcemeta::core::URI::recompose_relative ( ) const -> std::string
nodiscard

Recompose the path, query, and fragment of a URI as an RFC 3986 Section 4.2 relative reference. Scheme and authority are omitted. The result only resolves back to the original URI when used against a base that shares the same scheme and authority. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
uri{"https://www.sourcemeta.com/foo?x=1#bar"};
assert(uri.recompose_relative() == "/foo?x=1#bar");
auto recompose_relative() const -> std::string

◆ recompose_without_fragment()

auto sourcemeta::core::URI::recompose_without_fragment ( ) const -> std::optional< std::string >
nodiscard

Recompose a URI as established by RFC 3986, but without including the fragment component. The result is an optional to handle the case where the input URI only consists of a fragment. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
uri{"https://www.sourcemeta.com/foo#bar"};
assert(uri.recompose_without_fragment().has_value());
assert(uri.recompose_without_fragment().value() ==
"https://www.sourcemeta.com/foo");
auto recompose_without_fragment() const -> std::optional< std::string >

◆ relative_to()

auto sourcemeta::core::URI::relative_to ( const URI & base) -> URI &

Express a URI as a relative reference against a base URI, such that resolving the result against that base reproduces this URI:

resolve_from(relative_to(target, base), base) == target
auto relative_to(const URI &base) -> URI &
auto resolve_from(const URI &base) -> URI &

That equation is the definition of a correct result, as RFC 3986 states how to resolve a reference but never how to compute one. It holds when both URIs are absolute and the target path carries no dot segments. Resolution strips those from a reference that keeps its scheme just as it does from a relative one, so a target carrying them is outside the guarantee whether or not a reference gets built. Within those bounds, a URI left intact because no reference expresses it satisfies the equation as well. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
const sourcemeta::core::URI base{"https://www.sourcemeta.com/"};
sourcemeta::core::URI result{"https://www.sourcemeta.com/foo"};
result.relative_to(base);
assert(result.recompose() == "foo");

◆ resolve_from()

auto sourcemeta::core::URI::resolve_from ( const URI & base) -> URI &

Resolve a relative URI against a base URI as established by RFC 3986. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
const sourcemeta::core::URI base{"https://www.sourcemeta.com"};
sourcemeta::core::URI result{"foo"};
result.resolve_from(base);
assert(result.recompose() == "https://www.sourcemeta.com/foo");

◆ scheme()

auto sourcemeta::core::URI::scheme ( ) const -> std::optional< std::string_view >
nodiscard

Get the scheme part of the URI, if any. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
const sourcemeta::core::URI uri{"https://www.sourcemeta.com"};
assert(uri.scheme().has_value());
assert(uri.scheme().value() == "https");
auto scheme() const -> std::optional< std::string_view >

◆ strip_path_prefix()

auto sourcemeta::core::URI::strip_path_prefix ( std::string_view path,
std::string_view prefix ) -> std::optional< std::string >
staticnodiscard

Strip a URI path prefix and return the remaining suffix. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
const auto result{
sourcemeta::core::URI::strip_path_prefix("/foo/bar/baz", "/foo")};
assert(result.has_value());
assert(result.value() == "bar/baz");
static auto strip_path_prefix(std::string_view path, std::string_view prefix) -> std::optional< std::string >

◆ to_path()

auto sourcemeta::core::URI::to_path ( ) const -> std::filesystem::path
nodiscard

Convert a URI into a filesystem path. If the URI is not under the file scheme, get the URI path component as a filesystem path. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
const sourcemeta::core::URI uri{"file:///home/jviotti/foo.txt"};
assert(uri.to_path() == "/home/jviotti/foo.txt");
auto to_path() const -> std::filesystem::path

◆ unescape()

auto sourcemeta::core::URI::unescape ( std::string_view input) -> std::string
staticnodiscard

Percent-decode every escape sequence in a string per RFC 3986, leaving malformed sequences untouched. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
const auto decoded{sourcemeta::core::URI::unescape("foo%20bar%2Fbaz")};
assert(decoded == "foo bar/baz");
static auto unescape(std::string_view input) -> std::string

◆ unescape_form()

template<typename Output>
auto sourcemeta::core::URI::unescape_form ( const std::string_view input,
Output & output ) -> bool
inlinestaticnodiscard

Decode an "application/x-www-form-urlencoded" component (RFC 6749 Appendix B and the HTML URL-encoded form syntax), appending the decoded bytes to the output. Besides a std::string the sink can be a wiping string for a secret such as a decoded client credential. Each "+" becomes a space and each "%" followed by two hexadecimal digits becomes its octet. A "%" that is not followed by two hexadecimal digits is rejected, returning false with the output restored to its original contents. The output must not alias the input. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
#include <string>
std::string output;
assert(sourcemeta::core::URI::unescape_form("a+b%2Fc", output));
assert(output == "a b/c");
static auto unescape_form(const std::string_view input, Output &output) -> bool
Definition uri.h:974

◆ userinfo() [1/2]

auto sourcemeta::core::URI::userinfo ( ) const -> std::optional< std::string_view >
nodiscard

Get the user information part of the URI, if any. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
const sourcemeta::core::URI uri{"https://user:@host"};
assert(uri.userinfo().has_value());
assert(uri.userinfo().value() == "user:");
auto userinfo() const -> std::optional< std::string_view >

As mentioned in RFC 3986, the format "user:password" is deprecated. Applications should not render as clear text any data after the first colon. See https://tools.ietf.org/html/rfc3986#section-3.2.1

◆ userinfo() [2/2]

auto sourcemeta::core::URI::userinfo ( const std::string_view userinfo) -> URI &

Set the user information part of the URI. Passing an empty string clears the user information. For example:

#include <sourcemeta/core/uri.h>
#include <cassert>
sourcemeta::core::URI uri{"http://host/path"};
uri.userinfo("user");
assert(uri.userinfo().has_value());
assert(uri.userinfo().value() == "user");

◆ sourcemeta::core::URIParseError

class sourcemeta::core::URIParseError

An error that represents a URI parsing failure

Inheritance diagram for sourcemeta::core::URIParseError:

Public Member Functions

 URIParseError (const std::uint64_t column)
 Construct an error from the column at which parsing failed.
auto column () const noexcept -> std::uint64_t
 Get the column number of the error.

◆ sourcemeta::core::URIError

class sourcemeta::core::URIError

An error that represents a general URI error event

Inheritance diagram for sourcemeta::core::URIError:

Public Member Functions

 URIError (const char *message)
 Construct an error with the given message.
 URIError (std::string message)=delete
 URIError (std::string &&message)=delete
 URIError (std::string_view message)=delete