Network Addressing and URLs

Network Addressing Types

Address and Network Values

IpAddress stores IPv4 or IPv6 bits and uses canonical lowercase compressed text for IPv6. IpNetwork stores a normalized CIDR range and provides containment and boundary operations. IPv6 zone identifiers are intentionally not part of an address; ScopeId stores the optional numeric scope on an endpoint.

Hosts and Endpoints

HostName is a strict IDNA2008 value with canonical lowercase NFC Unicode semantics and a canonical ASCII transport form, while Host contains either a name or a numeric address. Default formatting returns Unicode; HostNameFormat::IdnaAscii exposes the A-label/NR-LDH form sent to native resolvers and suitable for SNI or certificate comparison. IpEndpoint is always resolved. HostEndpoint can remain unresolved until an asynchronous operation starts. Bracketed IPv6 endpoint text keeps the numeric scope after % and before the closing bracket.

Parsing Errors

Each fromStringOrThrow() factory is the diagnostic parsing API and raises ParseError with the specific invalid component or syntax rule. The matching fromString() factory catches that parse error and returns std::nullopt, making it suitable for tolerant input tests without losing detailed diagnostics where they are needed.

See Working with IP Addresses and Hostnames for parsing, formatting, endpoint construction, and CIDR range examples.

URLs

Network URL Values

Url represents absolute URLs intended for network operations. HTTP, HTTPS, FTP, and FTPS authorities are parsed into HostEndpoint values with their default ports. File and mailto URLs use scheme-specific rules, while unknown schemes retain a custom authority and parse its endpoint only when possible.

Parsing strictly decodes percent-encoded UTF-8 and NFC-normalizes path, query, fragment, and user-info values. Dot segments remain unchanged. authorityText() retains the source authority, but toString() creates canonical transport text and therefore does not preserve the original encoding spelling.

hasQuery() and hasFragment() distinguish an absent delimiter from an explicitly empty query or fragment. Canonical output retains explicitly empty delimiters.

Relative References

resolved() and resolvedOrThrow() apply RFC 3986 reference resolution to hierarchical URLs. They support absolute, scheme-relative, absolute-path, relative-path, query-only, fragment-only, and empty references. Resolution removes dot segments from the resulting path; ordinary absolute parsing continues to retain them.

HTTP, HTTPS, FTP, FTPS, file, and authority-bearing custom URLs can act as bases. Mail addresses and authority-free custom URLs are opaque and cannot resolve relative references.

Safety and Display

fromString() returns the invalid Url{} placeholder for malformed input; fromStringOrThrow() reports a detailed ParseError. UrlParseOptions defaults to a 16 KiB input limit.

UrlFormatOptions selects IDNA ASCII or Unicode host names and controls default-port and fragment output. Passwords are redacted by default and can be explicitly revealed. For an opaque custom authority, the default redaction replaces the complete authority.

Interface

class Host

A numeric IP address or unresolved host name.

Public Functions

Host() noexcept = default

Create the IPv4 any address as host.

inline Host(IpAddress address) noexcept

Create a host from an IP address.

Parameters:

address – The resolved IP address.

inline Host(HostName name) noexcept

Create a host from an unresolved name.

Parameters:

name – The platform-resolvable host name.

bool operator==(const Host &other) const noexcept = default

Compare two hosts.

Parameters:

other – The host to compare with this host.

Returns:

true if both hosts contain the same alternative and value.

inline bool isAddress() const noexcept

Test if this host contains an IP address.

Returns:

true if this is a resolved address.

inline bool isName() const noexcept

Test if this host contains an unresolved name.

Returns:

true if this is a host name.

std::optional<IpAddress> address() const noexcept

Get the contained address.

Returns:

The address, or std::nullopt if this host contains a name.

std::optional<HostName> name() const noexcept

Get the contained host name.

Returns:

The name, or std::nullopt if this host contains an address.

text::String toString() const

Format the contained address or host name.

Returns:

The host text.

std::size_t toHash() const noexcept

Calculate a hash value consistent with host equality.

Returns:

The hash value.

Public Static Functions

static std::optional<Host> fromString(const text::String &text) noexcept

Parse an IP address or platform-resolvable host name.

Parameters:

text – The complete host text without a port.

Returns:

The parsed host, or std::nullopt if the text is invalid.

static Host fromStringOrThrow(const text::String &text)

Parse an IP address or platform-resolvable host name.

Parameters:

text – The complete host text without a port.

Throws:

err::ParseError – If the text is not a valid host.

Returns:

The parsed host.

class HostEndpoint

A host name or IP address paired with a network port.

Public Functions

HostEndpoint() noexcept = default

Create the IPv4 any address with the automatic port.

inline HostEndpoint(Host host, Port port, ScopeId scopeId = {}) noexcept

Create an endpoint from a resolved address or unresolved host name.

Parameters:
  • host – The resolved address or unresolved name.

  • port – The transport port.

  • scopeId – The numeric IPv6 scope identifier, or zero if unspecified.

bool operator==(const HostEndpoint &other) const noexcept = default

Compare two host endpoints.

Parameters:

other – The endpoint to compare with this endpoint.

Returns:

true if all endpoint components are equal.

inline const Host &host() const noexcept

Get the resolved address or unresolved host name.

Returns:

The endpoint host.

inline constexpr Port port() const noexcept

Get the transport port.

Returns:

The endpoint port.

inline constexpr ScopeId scopeId() const noexcept

Get the IPv6 scope identifier.

Returns:

The scope identifier, or zero if unspecified.

text::String toString() const

Format the endpoint, including IPv6 brackets and an optional scope.

Returns:

The endpoint text.

std::size_t toHash() const noexcept

Calculate a hash value consistent with endpoint equality.

Returns:

The hash value.

Public Static Functions

static std::optional<HostEndpoint> fromString(const text::String &text) noexcept

Parse a resolved or unresolved host endpoint.

Parameters:

text – The complete host, optional IPv6 scope, and port text.

Returns:

The endpoint, or std::nullopt if the text is invalid.

static HostEndpoint fromStringOrThrow(const text::String &text)

Parse a resolved or unresolved host endpoint.

Parameters:

text – The complete host, optional IPv6 scope, and port text.

Throws:

err::ParseError – If the text is not a valid host endpoint.

Returns:

The parsed endpoint.

class HostName

A strict IDNA2008 host name with canonical Unicode and ASCII forms.

See: Network Addressing and URLs

Public Functions

inline std::strong_ordering operator<=>(const HostName &other) const noexcept

Compare two host names.

Parameters:

other – The host name to compare with this host name.

Returns:

The strong lexical ordering between the names.

inline bool operator==(const HostName &other) const noexcept

Test two canonical Unicode host names for equality.

inline const text::String &name() const noexcept

Get the host name.

Returns:

The retained host name.

inline text::String toString(HostNameFormat format = HostNameFormat::Unicode) const

Get the host name as text.

Parameters:

format – The Unicode semantic or IDNA ASCII transport representation.

Returns:

The selected canonical representation.

inline std::size_t toHash() const noexcept

Calculate the host-name hash.

Returns:

The hash value.

Public Static Functions

static std::optional<HostName> fromString(const text::String &text) noexcept

Validate and retain a platform-resolvable host name.

Parameters:

text – The complete host name without a port.

Returns:

The host name, or std::nullopt if the text is invalid.

static HostName fromStringOrThrow(const text::String &text)

Validate and retain a platform-resolvable host name.

Parameters:

text – The complete host name without a port.

Throws:

err::ParseError – If the text is not a valid host name.

Returns:

The validated host name.

enum class erbsland::network::HostNameFormat : uint8_t

Select the semantic Unicode or ASCII transport form of a host name.

Values:

enumerator Unicode

Return canonical lowercase NFC Unicode.

enumerator IdnaAscii

Return canonical lowercase IDNA2008 A-label/NR-LDH text.

class IpAddress

An IPv4 or IPv6 address.

Public Types

using Bytes = mem::ByteArray<16>

The fixed 16-byte address storage in network byte order.

Public Functions

constexpr IpAddress() noexcept = default

Create the IPv4 any address.

std::strong_ordering operator<=>(const IpAddress &other) const noexcept = default

Compare two addresses by version and binary value.

Parameters:

other – The address to compare with this address.

Returns:

The strong ordering between the addresses.

inline constexpr bool isV4() const noexcept

Test if this is an IPv4 address.

Returns:

true for an IPv4 address.

inline constexpr bool isV6() const noexcept

Test if this is an IPv6 address.

Returns:

true for an IPv6 address.

bool isAny() const noexcept

Test if all address bits are zero.

Returns:

true for an IPv4 or IPv6 any address.

bool isLoopback() const noexcept

Test if this is an IPv4 or IPv6 loopback address.

Returns:

true for an address in 127.0.0.0/8 or the IPv6 address ::1.

inline constexpr IpVersion version() const noexcept

Get the IP version.

Returns:

The address version.

inline constexpr const Bytes &bytes() const noexcept

Get the address bytes in network byte order.

For IPv4 addresses, the first four bytes contain the address and the remaining bytes are zero.

Returns:

The fixed 16-byte address storage.

text::String toString() const

Format the address in canonical text form.

Returns:

The dotted-decimal IPv4 or lowercase compressed IPv6 representation.

std::size_t toHash() const noexcept

Calculate a hash value consistent with address equality.

Returns:

The hash value.

Public Static Functions

static std::optional<IpAddress> fromString(const text::String &text) noexcept

Parse an IPv4 or IPv6 address.

Parameters:

text – The complete address text without a port or scope identifier.

Returns:

The parsed address, or std::nullopt if the text is invalid.

static IpAddress fromStringOrThrow(const text::String &text)

Parse an IPv4 or IPv6 address.

Parameters:

text – The complete address text without a port or scope identifier.

Throws:

err::ParseError – If the text is not a valid IPv4 or IPv6 address.

Returns:

The parsed address.

static IpAddress fromBytes(IpVersion version, Bytes bytes) noexcept

Create an address from bytes in network byte order.

For IPv4, bytes after the first four are cleared.

Parameters:
  • version – The IP version that determines how many bytes are significant.

  • bytes – The address bytes in network byte order.

Returns:

The created address.

static IpAddress anyV4() noexcept

Create the IPv4 any address.

Returns:

The address 0.0.0.0.

static IpAddress anyV6() noexcept

Create the IPv6 any address.

Returns:

The address ::.

static IpAddress loopbackV4() noexcept

Create the canonical IPv4 loopback address.

Returns:

The address 127.0.0.1.

static IpAddress loopbackV6() noexcept

Create the IPv6 loopback address.

Returns:

The address ::1.

class IpEndpoint

A resolved IP endpoint.

Public Functions

IpEndpoint() noexcept = default

Create the IPv4 any address with the automatic port.

inline IpEndpoint(IpAddress address, Port port, ScopeId scopeId = {}) noexcept

Create a resolved endpoint.

Parameters:
  • address – The resolved IP address.

  • port – The transport port.

  • scopeId – The numeric IPv6 scope identifier, or zero if unspecified.

std::strong_ordering operator<=>(const IpEndpoint &other) const noexcept = default

Compare two resolved endpoints.

Parameters:

other – The endpoint to compare with this endpoint.

Returns:

The strong ordering between the endpoint values.

inline const IpAddress &address() const noexcept

Get the resolved IP address.

Returns:

The endpoint address.

inline constexpr Port port() const noexcept

Get the transport port.

Returns:

The endpoint port.

inline constexpr ScopeId scopeId() const noexcept

Get the IPv6 scope identifier.

Returns:

The scope identifier, or zero if unspecified.

text::String toString() const

Format the endpoint, including IPv6 brackets and an optional scope.

Returns:

The endpoint text.

std::size_t toHash() const noexcept

Calculate a hash value consistent with endpoint equality.

Returns:

The hash value.

Public Static Functions

static std::optional<IpEndpoint> fromString(const text::String &text) noexcept

Parse a resolved endpoint.

Parameters:

text – The complete address, optional IPv6 scope, and port text.

Returns:

The endpoint, or std::nullopt if the text is invalid.

static IpEndpoint fromStringOrThrow(const text::String &text)

Parse a resolved endpoint.

Parameters:

text – The complete address, optional IPv6 scope, and port text.

Throws:

err::ParseError – If the text is not a valid resolved endpoint.

Returns:

The parsed endpoint.

class IpNetwork

A normalized IPv4 or IPv6 CIDR network.

Public Functions

IpNetwork() noexcept = default

Create the IPv4 default route (0.0.0.0/0).

IpNetwork(IpAddress address, uint8_t prefixLength)

Create and normalize a network.

Parameters:
  • address – An address within the network.

  • prefixLength – The number of fixed leading address bits.

Throws:

err::ParameterError – If the prefix length is invalid for the address version.

std::strong_ordering operator<=>(const IpNetwork &other) const noexcept = default

Compare two normalized networks.

Parameters:

other – The network to compare with this network.

Returns:

The strong ordering between the network values.

inline const IpAddress &address() const noexcept

Get the normalized first address.

Returns:

The first address in the network.

inline constexpr uint8_t prefixLength() const noexcept

Get the prefix length.

Returns:

The number of fixed leading bits.

inline IpAddress firstAddress() const noexcept

Get the first address in the network.

Returns:

The inclusive first address.

IpAddress lastAddress() const noexcept

Get the last address in the network.

Returns:

The inclusive last address.

bool contains(const IpAddress &address) const noexcept

Test if an address belongs to this network.

Parameters:

address – The address to test.

Returns:

true if the versions match and the address is within this network.

bool contains(const IpNetwork &network) const noexcept

Test if another network is fully contained in this network.

Parameters:

network – The network to test.

Returns:

true if the complete network is within this network.

text::String toString() const

Format the normalized network in CIDR notation.

Returns:

The canonical address and decimal prefix length.

std::size_t toHash() const noexcept

Calculate a hash value consistent with network equality.

Returns:

The hash value.

Public Static Functions

static std::optional<IpNetwork> fromString(const text::String &text) noexcept

Parse and normalize an IPv4 or IPv6 CIDR network.

Parameters:

text – The complete CIDR text.

Returns:

The network, or std::nullopt if the text is invalid.

static IpNetwork fromStringOrThrow(const text::String &text)

Parse and normalize an IPv4 or IPv6 CIDR network.

Parameters:

text – The complete CIDR text.

Throws:

err::ParseError – If the text is not a valid CIDR network.

Returns:

The parsed network.

enum class erbsland::network::IpVersion : uint8_t

The version of an IP address.

Values:

enumerator V4

Internet Protocol version 4.

enumerator V6

Internet Protocol version 6.

class Port

A network port number.

Port zero selects an automatic local port and is invalid as a remote destination.

Public Functions

constexpr Port() noexcept = default

Create the automatic port.

inline explicit constexpr Port(const uint16_t value) noexcept

Create a port from its numeric value.

Parameters:

value – The port number, where zero selects an automatic local port.

constexpr std::strong_ordering operator<=>(const Port &other) const noexcept = default

Compare two port numbers.

Parameters:

other – The port to compare with this port.

Returns:

The strong ordering between the numeric values.

inline constexpr bool isAutomatic() const noexcept

Test if this port requests automatic local selection.

Returns:

true if the port number is zero.

inline constexpr uint16_t toRawValue() const noexcept

Get the numeric port value.

Returns:

The port number.

text::String toString() const

Format the decimal port number.

Returns:

The port text.

Public Static Functions

static std::optional<Port> fromString(const text::String &text) noexcept

Parse a decimal port number.

Parameters:

text – The complete decimal port text.

Returns:

The port, or std::nullopt if the text is outside 0 through 65535 or malformed.

static Port fromStringOrThrow(const text::String &text)

Parse a decimal port number.

Parameters:

text – The complete decimal port text.

Throws:

err::ParseError – If the text is not a valid port number.

Returns:

The parsed port.

class ScopeId

A numeric IPv6 scope or network-interface identifier.

Public Functions

constexpr ScopeId() noexcept = default

Create an unspecified scope identifier.

inline explicit constexpr ScopeId(const uint32_t value) noexcept

Create a scope identifier from a numeric interface identifier.

Parameters:

value – The scope value, where zero means unspecified.

constexpr std::strong_ordering operator<=>(const ScopeId &other) const noexcept = default

Compare two scope identifiers.

Parameters:

other – The scope identifier to compare with this value.

Returns:

The strong ordering between the numeric values.

inline constexpr bool isSpecified() const noexcept

Test if a scope identifier is specified.

Returns:

true if the numeric value is nonzero.

inline constexpr uint32_t toRawValue() const noexcept

Get the numeric scope identifier.

Returns:

The scope value.

class Url

An absolute URL value for network operations.

Copies share immutable parsed data. Text components are decoded, NFC-normalized values; serialization is canonical and does not preserve the original percent-encoding spelling.

See: Network Addressing and URLs

Public Functions

Url() noexcept = default

Create an invalid URL placeholder.

Url(HostEndpoint endpoint, text::String path = {}, text::String query = {}, text::String fragment = {})

Create a secure HTTP URL.

Url(UrlScheme scheme, HostEndpoint endpoint, text::String path = {}, text::String query = {}, text::String fragment = {})

Create an HTTP, HTTPS, FTP, or FTPS URL.

Throws:

err::ParameterError – If the scheme or endpoint is invalid for a network URL.

bool isValid() const noexcept

Test whether this URL is valid.

UrlScheme scheme() const noexcept

Get the parsed scheme.

text::String schemeText() const noexcept

Get the canonical lowercase scheme text.

bool isSecureScheme() const noexcept

Test whether the built-in scheme uses a secure transport.

HostEndpoint endpoint() const noexcept

Get the parsed endpoint, or the default endpoint if none was parsed.

text::String authorityText() const noexcept

Get the original or constructed authority text.

text::String username() const noexcept

Get the decoded username.

text::String password() const noexcept

Get the decoded password.

text::String path() const noexcept

Get the decoded NFC path.

text::String query() const noexcept

Get the decoded NFC query.

bool hasQuery() const noexcept

Test whether a query delimiter is present, including an explicitly empty query.

text::String fragment() const noexcept

Get the decoded NFC fragment.

bool hasFragment() const noexcept

Test whether a fragment delimiter is present, including an explicitly empty fragment.

text::String toString(UrlFormatOptions options = {}) const

Format this URL in canonical form.

Url resolved(const text::String &reference, UrlParseOptions options = {}) const noexcept

Resolve a relative or absolute URI reference, returning an invalid URL on failure.

Url resolvedOrThrow(const text::String &reference, UrlParseOptions options = {}) const

Resolve a relative or absolute URI reference.

Throws:

err::ParseError – If the base or reference is invalid, unsupported, or exceeds configured limits.

Public Static Functions

static Url fromString(const text::String &text, UrlParseOptions options = {}) noexcept

Parse an absolute URL, returning an invalid URL on failure.

static Url fromStringOrThrow(const text::String &text, UrlParseOptions options = {})

Parse an absolute URL.

Throws:

err::ParseError – If the URL is invalid or exceeds configured limits.

static Url file(text::String path, text::String query = {}, text::String fragment = {})

Create a local file URL.

static Url file(Host host, text::String path, text::String query = {}, text::String fragment = {})

Create a hosted file URL.

static Url mailto(text::String address, text::String query = {}, text::String fragment = {})

Create a mailto URL.

static auto custom(text::String scheme, text::String path = {}, text::String query = {}, text::String fragment = {}) -> Url

Create a custom path-only URL.

static auto customWithAuthority(text::String scheme, text::String authority, text::String path = {}, text::String query = {}, text::String fragment = {}) -> Url

Create a custom URL with an opaque authority.

class UrlFormatOptions

Options for formatting a URL.

Public Functions

inline constexpr HostNameFormat hostNameFormat() const noexcept

Get the host-name format.

inline constexpr UrlFormatOptions &setHostNameFormat(const HostNameFormat value) noexcept

Set the host-name format.

inline constexpr bool includesDefaultPort() const noexcept

Test whether default ports are included.

inline constexpr UrlFormatOptions &setIncludeDefaultPort(const bool value) noexcept

Include or omit default ports.

inline constexpr bool includesFragment() const noexcept

Test whether the fragment is included.

inline constexpr UrlFormatOptions &setIncludeFragment(const bool value) noexcept

Include or omit the fragment.

inline constexpr bool redactsPassword() const noexcept

Test whether passwords are redacted.

inline constexpr UrlFormatOptions &setRedactPassword(const bool value) noexcept

Enable or disable password redaction.

class UrlParseOptions

Limits used while parsing a URL.

Public Functions

inline constexpr unit::ByteLength maximumLength() const noexcept

Get the maximum source length.

inline constexpr UrlParseOptions &setMaximumLength(const unit::ByteLength value) noexcept

Set the maximum source length.

Public Static Attributes

static constexpr auto cDefaultMaximumLength = unit::ByteLength{16U * 1024U}

The default maximum source length.

enum class erbsland::network::UrlScheme : uint8_t

A supported URL scheme.

Values:

enumerator Invalid

No valid URL.

enumerator Http

Plain HTTP.

enumerator Https

HTTP over TLS.

enumerator Ftp

Plain FTP.

enumerator Ftps

FTP over TLS.

enumerator File

A file URL.

enumerator Mailto

An email address URL.

enumerator Custom

A syntactically valid custom scheme.