# URI - Proposed Wording (Revision 5)

Document Number: N3975
Revises: N3947
Date: 2014-05-22
Authors: Glyn Matthews <glyn.matthews@gmail.com>, Dean Michael Berris <dberris@google.com>

## Introduction

Note

Notes highlighted in yellow are comments on the proposed wording and are not intended for the actual TS.

## Revisions to N3947

1. Numerous updates to wording and style to make it more compatible with the standard document.
2. Removed `string_type` member typedef for the `uri` class.
3. Improved specification of the definition of port [uri.definition.port].
4. Updated [uri.requirements] to be the same as the filesystem proposal.
5. Renamed `uri_error_code` to `uri_errc` [class.uri_errc].
6. Added an additional sentence in [uri.scope] to describe the `uri_errc` `enum`.
7. Made member functions `constexpr` and `noexcept`, where appropriate.
8. Improved specification of equality and comparison operators [uri.header-synopsis.equality-comparison].
9. Added a section describing uri encoding conversions [class.uri.conversions]
10. Added some sentences on `make_error_code`, `make_error_condition` and `uri_category` [uri.header-synopsis.error-handling].
11. Updated `uri_builder`.
12. Improved specification for `to_uri` and `to_filesystem_path` to handle the case where the URI or filesystem path is relative [uri.header-synopsis.filesystem-interop].

## Revisions to N3827

1. Reverted normalization invariant and added the `normalize` member function and `uri_normalization_level` again.
2. Added functions for interoperability with `std::filesystem::path`.
3. Replaced multiple exception classes with a single exception class, `uri_error`. The `uri_error` enum has become `uri_error_code`.
4. Updated `make_relative` and `resolve` sections.
5. Removed references to IETF RFC 2732, which, it was pointed out, is superseded by IETF RFC 3986.

## Revisions to N3792

1. Normalization is now an invariant of the `std::experimental::uri` class.
2. Removed `uri_normalization_level`.
3. Removed `normalize` member function.

## Revisions to N3720

1. Added an “Error Reporting” section.
2. Renamed “Alloc” to “Allocator” to bring it more in to line with the standard.
3. Renamed `uri::make_reference` to `uri::make_relative`.
4. Renamed `uri_comparison_level` to `uri_normalization_level`.
5. Added sections for `uri_error` and `uri_normalization_level`.
6. Added a `base_uri_error` that can be thrown by the `resolve` and `make_relative` member functions in the event that the base URI is not valid.
7. Improved documentation of URI resolution in the Terms and Definition section and in the description of the `resolve` member functions.
8. Using the standard hash specialization instead of `hash_value`.
9. Allowed the `Source` template argument to be `basic_string_view<CharT, CharTraits>`
10. `uri_builder` now allows copy and move.
11. All constructors that accept an argument of type `Source` now also take `InputIterator` overloads.
12. Fixed minor typographical errors.

## 1 Scope [uri.scope]

The scope of this Technical Specification will include a single `std::experimental::uri` type, specifications about how the are intended to be processed and extended, including some additional helper types and functions. It will include a `std::experimental::uri_builder` type to build a URI from its components. It will also include a `std::experimental::uri_errc` `enum` which enumerates the types of error that can occur when parsing, normalizing, resolving or building a URI, or percent decoding. Finally, it will include types and functions for percent encoding and decoding, URI references, reference resolution and URI normalization and comparison.

## 2 Conformance [uri.conformance]

### 2.1 Generic syntax [uri.conformance.generic-syntax]

The generic syntax of a URI is defined in IETF RFC 3986. section 3.

All URIs are of the form:

    scheme ":" "hierarchical part" [ "?" query ] [ "#" fragment ]

The scheme is used to identify the specification needed to parse the rest of the URI. A generic syntax parser can parse any URI into its main parts. The scheme can then be used to identify whether further scheme-specific parsing can be performed.

The hierarchical part refers to the part of the URI that holds identification information that is hierarchical in nature. This may contain an authority (always prefixed with a double slash character (“//”)) and/or a path. The path part is required, thought it may be empty. The authority part holds an optional user info part, ending with an at character (“@”); a host identifier and an optional port number, preceded by a colon character(”:”). The host may be an IP address or domain name. The normative reference for IPv6 addresses is IETF RFC 3986.

The query is an optional part following a question mark character (”?”) that contains information that is not hierarchical.

Finally, the fragment is an optional part, prefixed by a hash character (“#”) that is used to identify secondary sources.

IETF RFC 3987 specifies a new protocol element, the Internationalized Resource Identifier (IRI). The IRI complements a URI, and extends it to allow unicode characters. The syntax of an IRI is specified in IETF RFC 3987, section 2.

IETF RFC 6874 specifies scoped IDs in IPv6 addresses. The syntax is specified in IETF RFC 6874, section 2.

### 2.2 URI Normalization and Comparison [uri.conformance.uri-normalization-and-comparison]

The rules for URI normalization are specified in IETF RFC 3986, section 6 and IETF RFC 3987, section 5.

### 2.3 URI References [uri.conformance.uri-references]

The rule for transforming references is given in IETF RFC 3986, section 5.2.2.

### 2.4 Removing Dot Segments [uri.conformance.removing-dot-segments]

The rule for removing dot segments is given in IETF RFC 3986, section 5.2.4.

### 2.5 URI Recomposition [uri.conformance.uri-recomposition]

The rule for recomposing a URI from its parts is given in IETF RFC 3986, section 5.3.

## 3 Terms and Definitions [uri.definitions]

### 3.1 URI [uri.definition.uri]

A Uniform Resource Identifier is a sequence of characters from a limited set with a specific syntax used to identify a name or resource. URIs can be classified as URLs or URNs. The URI syntax is defined in IETF RFC 3986.

### 3.2 URL [uri.definition.url]

A Uniform Resource Locator (URL) is a type of URI, complementary to a URN used to locate a resource over a network.

### 3.3 URN [uri.definition.urn]

A Uniform Resource Name (URN) is a type of URI, complementary to a URL used to unambiguously identify resources.

### 3.4 IRI [uri.definition.iri]

An Internationalized Resource Identifier (IRI) is a complement to the URI that allows characters from the Universal Character Set (Unicode/ISO 10646). The IRI syntax is defined in IETF RFC 3987.

### 3.5 URI Part [uri.definition.uri-part]

A generic URI is decomposed into four principal parts: the scheme, the hierarchical part, an optional query and optional fragment. The hierarchical part can be further decomposed into four parts: the user info, host, port and path.

### 3.6 Scheme [uri.definition.scheme]

A scheme name is the top level of the URI naming structure. It indicates the specifications, syntax and semantics of the rest of the URI structure. It is always followed by a colon character (”:”). The scheme syntax is defined in IETF RFC 3986, section 3.1.

### 3.7 Query [uri.definition.query]

A query is a part, indicated by a question mark character (”?”) and terminated by a hash character (“#”), that contains non-hierarchical information. It is commonly structured as a sequence of key-value parameter values separated by equals (“=”), which are separated by a semi-colon character (”;”) or ampersand character (“&”). The query syntax is defined in IETF RFC 3986, section 3.4.

### 3.8 Fragment [uri.definition.fragment]

A fragment is indicated by a hash character (“#”) and allows indirect identification of a secondary resource. For example, a fragment may refer to a section header in an HTML document with an id attribute of the same name. The fragment syntax is defined in IETF RFC 3986, section 3.5.

### 3.9 Hierarchical Part [uri.definition.hierarchical-part]

The hierarchical part of a URI contains hierarchical information. If it starts with two consecutive forward slash characters (“//”), it is followed by an authority and a path. The authority can be further broken down into a user-information part, a hostname and a port. The authority is followed by an optional path. If the hierarchical part does not begin with two consecutive forward slash characters (“//”), then it contains a path.

### 3.10 Authority [uri.definition.authority]

The hierarchical part contains an authority. The authority contains an optional user info followed by an at character (“@”), a host and an optional port, preceded by a colon character (”:”). The authority syntax is defined in IETF RFC 3986, section 3.2.

### 3.11 User Info [uri.definition.user-info]

The user info is an optional part of the URI authority, terminated by an at character (“@”) and is followed by a host. It is used in the telnet scheme:

    telnet://<user>:<password>@<host>:<port>/

The user info syntax is defined in IETF RFC 3986, section 3.2.1.

### 3.12 Host [uri.definition.host]

The hostname contains a domain name or IP address. The host syntax is defined in IETF RFC 3986, section 3.2.2.

### 3.13 Domain Name [uri.definition.domain-name]

A domain name is human-readable string used to identify a host. Domain names are registered in the Domain Name System (DNS).

### 3.14 IP Address [uri.definition.ip-address]

The IP address can either be an IPv4 (e.g. `127.0.0.1`) or an IPv6 address (e.g. `::1`. In a URI, an IPv6 address is enclosed in square brace characters (“[]”).

### 3.15 Port [uri.definition.port]

The optional port is a non-negative integer value, always preceded by a colon character (”:”). If the port is not present, even if a colon is present, then the port is considered to have the value of the default port of the scheme. The port syntax is defined in IETF RFC 3986, section 3.2.3.

### 3.16 Path [uri.definition.path]

The path is a part of the hierarchical data and is a sequence of segments, each separated by a forward slash character (“/”). It is terminated by a question mark character (”?”), followed by a query, a hash character (“#”) followed by a fragment or by the end of the URI. The path syntax is defined in IETF RFC 3986, section 3.3.

### 3.17 Dot Segments [uri.definition.dot-segments]

Dot segments are elements in a path containing either a dot character (”.”) or two consecutive dot characters (”..”), separated by a forward slash character (“/”). Dot segments can be removed from a path as part of its normalization without changing the URI semantics.

### 3.18 Absolute URI [uri.definition.absolute-uri]

An absolute URI always specifies the scheme. URIs that don’t provide the scheme are called relative references.

### 3.19 Opaque URI [uri.definition.opaque-uri]

An opaque URI is an absolute URI that does not provide two consecutive forward slash characters (“//”) after the scheme-delimiting colon character (”:”). Opaque URIs have no authority and the part immediately following the colon character (”:”) is the path. Some examples of opaque URIs are:

    mailto:john.doe@example.com
    news:comp.lang.c++

URIs that provide two consecutive forward slash characters (“//”) following the scheme-delimiting colon character (”:”) are known as hierarchical URIs. Some examples are:

    http://www.example.com/
    ftp://john.doe@ftp.example.com/

### 3.20 Normalization [uri.definition.normalization]

URI normalization is the process by which a URI is transformed in order to determine of two URIs are equivalent. There are different levels to comparison, which trade-off the number of false negatives and complexity. The normalization and comparison procedures are defined in IETF RFC 3986, section 6.

### 3.21 Comparison Ladder [uri.definition.comparison-ladder]

The comparison ladder describes how URIs can be compared using normalization in different ways, trading off the complexity of the method and the number of false negatives. The comparison ladder is defined in IETF RFC 3986, section 6.2 and IETF RFC 3987, section 5.3.

### 3.22 Base URI [uri.definition.base-uri]

A base URI is required to be established in order for relative references to be usable. The specification for establishing a base URI is defined in IETF RFC 3986, section 5.1. The base URI can also be used as the basis for building URIs.

### 3.23 Relative Reference [uri.definition.relative-reference]

Relative references are URIs that do not provide a scheme. Relative references are only usable when a base URI is known, against which the relative reference can be resolved. The relative reference is defined in IETF RFC 3986, section 4.2 and IETF RFC 3987, section 6.5.

### 3.24 Reference Resolution [uri.definition.reference-resolution]

Relative references can be resolved against a base URI, producing an absolute URI. Only the scheme is required to be present in the base URI. Reference resolution is defined in IETF RFC 3986, section 5.

Pre-parsing and normalization of the URI is performed before transforming the reference.

The transform reference for resolving URIs is given in IETF RFC 3986, section 5.2.2.

### 3.25 Percent Encoding [uri.definition.percent-encoding]

Percent encoding is the mechanism used to encode reserved characters in a URI. See IETF RFC 3986, section 2.1.

### 3.26 Case Normalization [uri.definition.case-normalization]

All characters in a URI scheme and host are lower-case. All hexidecimal digits within a percent-encoded triplet are upper-case. See IETF RFC 3986, section 6.2.2.1 and IETF RFC 3987, section 5.3.2.1.

### 3.27 Percent Encoding Normalization [uri.definition.percent-encoding-normalization]

URIs should be normalized by decoding any percent-encoded octet that corresponds to a an unreserved character. See IETF RFC 3986, section 6.2.2.2 and IETF RFC 3987, section 5.3.2.3.

### 3.28 Path Segment Normalization [uri.definition.path-segment-normalization]

Path segments [uri.definition.dot-segments] should be removed from URIs that are not relative references. See IETF RFC 3986, section 6.2.2.3 and IETF RFC 3987, section 5.3.2.4.

### 3.29 Character Normalization [uri.definition.character-normalization]

In Unicode, different sequences of characters could be defined as equivalent depending on how they are encoded. See IETF RFC 3987, section 5.3.2.2.

### 3.30 IPv6 Zone IDs [uri.definition.ipv6-zone-ids]

A zone index is used to identify to which scope a non-global address belongs in an IPv6 address. It is specified in IETF RFC 6874.

## 4 Requirements [uri.requirements]

Throughout this Technical Specification, `char`, `wchar_t`, `char16_t`, and `char32_t` are collectively called encoded character types.

Template parameters named `charT` shall be one of the encoded character types.

Template parameters named `InputIterator` shall meet the C++ Standard’s library input iterator requirements ([input.iterators] C++11 section 24.2.3) and shall have a value type that is one of the encoded character types.

> [Note: Use of an encoded character type implies an associated encoding. Since `signed char` and `unsigned char` have no implied encoding, they are not included as permitted types. –end note]

Note

The above text uses similar wording to N3940 [fs.req] section 5.

Function template parameters named `Source`, `UserInfoSource`, `HostSource`, `PortSource`, `KeySource`, `ParamSource` shall be one of:

- `basic_string<charT, traits, Allocator>`. The type charT shall be an encoded character type. A function argument `const Source& source` shall have an effective range [`cbegin(source)`, `cend(source)`).
- A type meeting the input iterator requirements that iterates over a NTCTS [defns.ntcts]. The value type shall be an encoded character type. A function argument `InputIterator begin` shall have an effective range [`begin`, `end`) where `end` is the first iterator value with an element value equal to `iterator_traits<InputIterator>::value_type()`.
- A character array that after array-to-pointer decay results in a pointer to a NTCTS. The value type shall be an encoded character type. A function argument `const Source& source` shall have an effective range [source, end) where end is the first iterator value with an element value equal to `iterator_traits<decay<Source>::type>::value_type()`.

Arguments of type `Source`, `UserInfoSource`, `HostSource`, `PortSource`, `KeySource`, `ParamSource` shall not be null pointers.

Note

This is similar wording to the filesystem path requirements in N3940 ([path.req]).

The `uri` class shall parse according to the rules described in IETF RFC 3986, Section 3.

The `uri` class shall correctly parse IPv6 addresses, described in IETF RFC 3986.

The `uri` class shall parse internationalized URIs according to IETF RFC 3987, section 2.

The `uri` class shall parse zone IDs in IPv6 addresses according to IETF RFC 6874, section 2.

Template parameters named Allocator shall meet the C++ Standard’s library Allocator requirements (C++11 17.6.3.5)

## 5 Header `<experimental/uri>` Synopsis [uri.header-synopsis]

    #include <string>                     // std::basic_string
    #include <system_error>               // std::error_code
    #include <iosfwd>                     // std::basic_istream, std::basic_ostream
    #include <iterator>                   // std::iterator_traits
    #include <memory>                     // std::allocator
    #include <experimental/optional>      // std::experimental::optional
    #include <experimental/string_view>   // std::experimental::basic_string_view
    #include <experimental/filesystem>    // std::experimental::filesystem::path

    namespace std {
    namespace experimental {
    // class declarations
    class uri;
    class uri_builder;
    class uri_error;

    enum class uri_errc {
     // uri syntax errors
     invalid_syntax = 1,

     // uri reference and resolution errors
     base_uri_is_empty,
     base_uri_is_not_absolute,
     base_uri_is_opaque,
     base_uri_does_not_match,

     // builder errors
     invalid_uri,
     invalid_scheme,
     invalid_user_info,
     invalid_host,
     invalid_port,
     invalid_path,
     invalid_query,
     invalid_fragment,

     // decoding errors
     not_enough_input,
     non_hex_input,
     conversion_failed,
    };

    enum class uri_normalization_level {
     string_comparison,
     syntax_based,
    };

    // factory functions
    template <class Source>
    uri make_uri(const Source& source, error_code& ec);
    template <class InputIterator>
    uri make_uri(InputIterator first, InputIterator last, error_code& ec);
    template <class Source, class Allocator>
    uri make_uri(const Source& source, const Allocator& a, error_code& ec);
    template <class InputIterator, class Allocator>
    uri make_uri(InputIterator first, InputIterator last, const Allocator& a, error_code& ec);

    // interoperability with filesystem::path
    uri to_uri(const experimental::filesystem::path& p);
    template <class Allocator>
    uri to_uri(const experimental::filesystem::path& p, const Allocator& a);
    experimental::filesystem::path to_filesystem_path(const uri& u);
    experimental::filesystem::path to_filesystem_path(const uri& u, error_code& ec);

    // equality and comparison operators
    constexpr bool operator== (const uri& lhs, const uri& rhs) noexcept;
    constexpr bool operator!= (const uri& lhs, const uri& rhs) noexcept;
    constexpr bool operator<  (const uri& lhs, const uri& rhs) noexcept;
    constexpr bool operator>  (const uri& lhs, const uri& rhs) noexcept;
    constexpr bool operator<= (const uri& lhs, const uri& rhs) noexcept;
    constexpr bool operator>= (const uri& lhs, const uri& rhs) noexcept;

    // stream operators
    template <typename charT, class traits>
    basic_ostream<charT, traits>&
    operator<< (basic_ostream<charT, traits>& os, const uri& u);
    template <typename charT, class traits>
    basic_istream<charT, traits>&
    operator>> (basic_istream<charT, traits>& is, uri& u);

    // swap functions
    void swap(uri& lhs, uri& rhs) noexcept;
    } // namespace experimental

    template <class T> struct hash;
    template <> struct hash<experimental::uri>;

    namespace experimental {
    // error handling
    error_code make_error_code(uri_errc e) noexcept;
    error_condition make_error_condition(uri_errc e) noexcept;
    const error_category& uri_category() noexcept;
    } // namespace experimental

    template <>
    struct is_error_code_enum<experimental::uri_errc> : public true_type { };
    } // namespace std

### 5.1 Declarations [uri.header-synopsis.declarations]

The `<experimental/uri>` header contains a declaration for a `uri` class, a `uri_builder` class and an exception class, `uri_error` in the `std::experimental` namespace.

### 5.2 Factory functions [uri.header-synopsis.factory-functions]

    // factory functions
    template <class Source>
    uri make_uri(const Source& source, error_code& ec);

Effects: Constructs an object of class `uri`. The source is copied into the `uri` object and parsed. The encoding is assumed to depend on the underlying character type and implementation. On error, the `error_code` is set and `make_uri` returns an empty `uri` object.

    template <class InputIterator>
    uri make_uri(InputIterator first, InputIterator last, error_code& ec);

Effects: Constructs an object of class `uri`. The source is copied into the `uri` object and parsed. The encoding is assumed to depend on the underlying character type and implementation. On error, the `error_code` is set and `make_uri` returns an empty `uri` object.

    template <class Source, class Allocator>
    uri make_uri(const Source& source, const Allocator& a, error_code& ec);

Effects: Constructs an object of class `uri`. The source is copied into the `uri` object and parsed. The encoding is assumed to depend on the underlying character type and implementation. On error, the `error_code` is set and `make_uri` returns an empty `uri` object. All memory allocation is performed by `a`.

    template <class InputIterator, class Allocator>
    uri make_uri(InputIterator first, InputIterator last, const Allocator& a,
                 error_code& ec);

Effects: Constructs an object of class `uri`. The source is copied into the `uri` object and parsed. The encoding is assumed to depend on the underlying character type and implementation. On error, the `error_code` is set and `make_uri` returns an empty `uri` object. All memory allocation is performed by `a`.

### 5.3 Interoperability with `std::experimental::filesystem::path` [uri.header-synopsis.filesystem-interop]

    uri to_uri(const experimental::filesystem::path& p);

Effects: Returns a `uri` object with the `file` scheme and the absolute path to `p`. If `p` is absolute, the result is an absolute URI with a scheme `file`. If `p` is relative, the result is a URI relative reference.
Example:

    // On UNIX
    std::experimental::filesystem::path p("/home/example/.bashrc");
    std::experimental::uri u(std::experimental::to_uri(p));
    assert(u.is_absolute());
    assert("file:///home/example/.bashrc" == u.string());
    assert("/home/example/.bashrc" == *u.path());

End example
Example:

    std::experimental::filesystem::path p(".bashrc");
    std::experimental::uri u(std::experimental::to_uri(p));
    assert(u.is_relative());
    assert(".bashrc" == u.string());
    assert(".bashrc" == *u.path());

End example

    template <class Allocator>
    uri to_uri(const experimental::filesystem::path& p, const Allocator& a);

Effects: Returns a `uri` object with the `file` scheme and the absolute path to `p`. All memory allocation is performed by `a`.
Example:

    std::experimental::filesystem::path p("/home/example/.bashrc");
    my_ns::my_allocator a;
    std::experimental::uri u(std::experimental::to_uri(p, a));
    assert("file:///home/example/.bashrc" == u.string());

End example

    experimental::filesystem::path to_filesystem_path(const uri& u);

Effects: If `u` is an absolute URI with the `file` scheme, the result is a `experimental::filesystem::path` object with an absolute path given a `uri`. If `u` is relative, the result is a relative `experimental::filesystem::path`. If the `uri` can not be converted to an `experimental::filesystem::path`, a `uri_error` is thrown.
Example:

    try {
      std::experimental::uri u("file:///home/example/.bashrc");
      std::experimental::filesystem::path p(std::experimental::to_filesystem_path(u));
      assert(p.is_absolute());
      assert("/home/example/.bashrc" == p.string());
    }
    catch (const std::experimental::uri_error& e) {
      // handle error
    }

End example
Example:

    try {
      std::experimental::uri u("file:///home/example/");
      std::experimental::uri v("file:///home/example/.bashrc");
      std::experimental::uri w = u.make_relative(v);
      std::experimental::filesystem::path p(std::experimental::to_filesystem_path(w));
      assert(p.is_relative());
      assert(".bashrc" == p.string());
    }
    catch (const std::experimental::uri_error& e) {
      // handle error
    }

End example
Throws: `uri_error`

    experimental::filesystem::path to_filesystem_path(const uri& u, error_code& ec);

Effects: If `u` is an absolute URI with the `file` scheme, the result is a `experimental::filesystem::path` object with an absolute path given a `uri`. If `u` is relative, the result is a relative `experimental::filesystem::path`. If the `uri` can not be converted to a `experimental::filesystem::path`, `ec` is set.
Example:

    std::experimental::uri u("file:///home/example/.bashrc");
    std::error_code ec;
    std::experimental::filesystem::path p(std::experimental::to_filesystem_path(u, ec));
    if (!ec) {
      assert(p.is_absolute());
      assert("/home/example/.bashrc" == p.string());
    }
    else {
      // handle error
    }

End example

### 5.4 Equality and Comparison Operators [uri.header-synopsis.equality-comparison]

    constexpr bool operator== (const uri& lhs, const uri& rhs) noexcept;

Returns: `lhs.compare(rhs, uri_normalization_level::string_comparison) == 0`

> [Note: The equality operator uses a character-by-character comparison of two `uri` objects. –end note]

    constexpr bool operator!= (const uri& lhs, const uri& rhs) noexcept;

Returns: `!(lhs == rhs)`

    constexpr bool operator<  (const uri& lhs, const uri& rhs) noexcept;

Returns: `lhs.compare(rhs, uri_normalization_level::string_comparison) < 0`

> [Note: The less-than operator uses a character-by-character comparison of two `uri` objects. –end note]

    constexpr bool operator>  (const uri& lhs, const uri& rhs) noexcept;

Returns: `(rhs < lhs)`

    constexpr bool operator<= (const uri& lhs, const uri& rhs) noexcept;

Returns: `!(lhs > rhs)`

    constexpr bool operator>= (const uri& lhs, const uri& rhs) noexcept;

Returns: `!(lhs < rhs)`

### 5.5 Stream Operators [uri.header-synopsis.stream-operators]

    template <typename charT, class traits>
    basic_ostream<charT, traits>&
    operator<< (basic_ostream<charT, traits>& os, const uri& u);

Effects: `os << u.to_string<charT, traits>();`.

> [Note: `u` is percent encoded according to [uri.definition.percent-encoding]]

    template <typename charT, class traits>
    basic_istream<charT, traits>&
    operator>> (basic_istream<charT, traits>& is, uri& u);

Effects: `string<charT, traits> tmp; is >> tmp; std::error_code ec; u = make_uri(tmp, ec); if (ec) is.setstate(ios_base::fail);`

### 5.6 Swap [uri.header-synopsis.swap]

    void swap(uri& lhs, uri& rhs) noexcept;

Effects: `lhs.swap(rhs);`

### 5.7 URI Hash [uri.header-synopsis.hash]

    template <> struct hash<experimental::uri>;

Effects: The template specialization shall meet the requirements of class template hash (20.8.12).

## 6 Error Reporting [uri.error-reporting]

Some URI functions provide two overloads, one that throws an exception to report errors, and a second that sets an `std::error_code`.

Member functions of `uri` not having an error of type `std::error_code&` report errors as follow, unless otherwise specified:

- A `uri_error` is thrown.
- Failure to allocate storage is reported by throwing an exception as describe in the C++ standard, 17.6.4.10 [res.on.exception.handling].

Functions that have an error of type `std::error_code&` report errors as follows:

- If a parsing error indicates an invalid URI, or a URI relative reference is passed as a base URI, the `std::error_code&` argument is set as appropriate for the specific error. Otherwise, `clear` is called on the `error_code&` argument.

### 6.1 Error Handling [uri.error-reporting.error-handling]

    error_code make_error_code(uri_errc e) noexcept;

Returns: `error_code(static_cast<int>(e), uri_category())`

    error_condition make_error_condition(uri_errc e) noexcept;

Returns: `error_condition(static_cast<int>(e), uri_category())`

    const error_category& uri_category() noexcept;

Returns: A reference to an object of a type derived from class error_category.
Remarks: The object’s `default_error_condition` and equivalent virtual functions shall behave as specified for the class `error_category`. The object’s `name` virtual function shall return a pointer to the string `"uri"`.

## 7 Class `uri` [class.uri]

    namespace std {
    namespace experimental {
    class uri {

    public:

        // typedefs
        typedef unspecified value_type;
        typedef implementation-defined iterator;
        typedef implementation-defined const_iterator;
        typedef experimental::basic_string_view<value_type> string_view;

        // constructors and destructor
        uri();
        template <class Source, class Allocator = allocator<value_type>>
        explicit uri(const Source& source, const Allocator& a = Allocator());
        template <class InputIterator, class Allocator = allocator<value_type>>
        uri(InputIterator begin, InputIterator end, const Allocator& a = Allocator());
        uri(const uri& other);
        uri(uri&& other) noexcept;
        ~uri();

        // assignment
        uri& operator= (const uri& other);
        uri& operator= (uri&& other) noexcept;

        // modifiers
        void swap(uri& other) noexcept;

        // iterators
        constexpr const_iterator begin() const noexcept;
        constexpr const_iterator end() const noexcept;
        constexpr const_iterator cbegin() const noexcept;
        constexpr const_iterator cend() const noexcept;

        // accessors
        constexpr experimental::optional<string_view> scheme() const;
        constexpr experimental::optional<string_view> user_info() const;
        constexpr experimental::optional<string_view> host() const;
        constexpr experimental::optional<string_view> port() const;
        template <class intT>
        constexpr experimental::optional<intT> port() const;
        constexpr experimental::optional<string_view> path() const;
        constexpr experimental::optional<string_view> authority() const;
        constexpr experimental::optional<string_view> query() const;
        constexpr experimental::optional<string_view> fragment() const;

        // string accessors
        template <class charT,
                  class traits = char_traits<charT>,
                  class Allocator = allocator<charT>>
        basic_string<charT, traits, Allocator>
        to_string(const Allocator& a = Allocator()) const;
        string string() const;
        wstring wstring() const;
        string u8string() const;
        u16string u16string() const;
        u32string u32string() const;

        // query
        constexpr bool empty() const noexcept;
        constexpr bool is_absolute() const noexcept;
        constexpr bool is_relative() const noexcept;
        constexpr bool is_hierarchical() const noexcept;
        constexpr bool is_opaque() const noexcept;

        // transformers
        uri normalize(uri_normalization_level level) const;
        template <class Allocator>
        uri normalize(uri_normalization_level level, const Allocator& alloc) const;
        uri normalize(uri_normalization_level level, error_code& ec) const;
        template <class Allocator>
        uri normalize(uri_normalization_level level, const Allocator& alloc,
                      error_code& ec) const;

        uri make_relative(const uri& u) const;
        template <class Allocator>
        uri make_relative(const uri& u, const Allocator& a) const;
        uri make_relative(const uri& u, error_code& ec) const;
        template <class Allocator>
        uri make_relative(const uri& u, const Allocator& a, error_code& ec) const;

        uri resolve(const uri& u) const;
        template <class Allocator>
        uri resolve(const uri& u, const Allocator& a) const;
        uri resolve(const uri& u, error_code& ec) const;
        template <class Allocator>
        uri resolve(const uri& u, const Allocator& a, error_code& ec) const;

        // comparison
        constexpr int compare(const uri& other, uri_normalization_level level) const noexcept;

        // percent encoding and decoding
        template <class InputIterator, class OutputIterator>
        static OutputIterator encode_user_info(InputIterator begin, InputIterator end,
                                               OutputIterator out);
        template <class InputIterator, class OutputIterator>
        static OutputIterator encode_host(InputIterator begin, InputIterator end,
                                          OutputIterator out);
        template <class InputIterator, class OutputIterator>
        static OutputIterator encode_port(InputIterator begin, InputIterator end,
                                          OutputIterator out);
        template <class InputIterator, class OutputIterator>
        static OutputIterator encode_path(InputIterator begin, InputIterator end,
                                          OutputIterator out);
        template <class InputIterator, class OutputIterator>
        static OutputIterator encode_query(InputIterator begin, InputIterator end,
                                           OutputIterator out);
        template <class InputIterator, class OutputIterator>
        static OutputIterator encode_fragment(InputIterator begin, InputIterator end,
                                              OutputIterator out);
        template <class InputIterator, class OutputIterator>
        static OutputIterator decode(InputIterator begin, InputIterator end,
                                     OutputIterator out);

    };
    } // namespace experimental
    } // namespace std

### 7.1 `uri` Conversions [class.uri.conversions]

For member functions returning strings, value type and encoding conversion is performed if the value type of the argument or return differs from `uri::value_type`. Encoding and method of conversion for the argument or return value to be converted to is determined by its value type:

- `char`: Encoding is UTF-8. Conversion method is unspecified.
- `wchar_t`: Encoding is unspecified. Conversion method is unspecified.
- `char16_t`: Encoding is UTF-16. Conversion method is unspecified.
- `char32_t`: Encoding is UTF-32. Conversion method is unspecified.

Note

This is based on wording in the filesystem path requirements in N3940 (http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2014/n3940.html#path.arg.convert)

### 7.2 `uri` Requirements [class.uri.reqs]

Each URI part is required to be a contiguous memory block.

Case normalization shall be performed according to IETF RFC 3986, section 6.2.2.1 and IETF RFC 3987, section 5.3.2.1.

Percent encoding normalization shall be performed according to IETF RFC 3986, section 6.2.2.2 and IETF RFC 3987, section 5.3.2.3.

Removing dot segments (”.”, ”..”) from a path shall conform to IETF RFC 3986, section 5.2.4.

URI References returned by `std::experimental::uri::make_relative` shall be transformed by using the algorithm in IETF RFC 3986, section 5.2.2.

### 7.3 `uri` members [class.uri.members]

#### 7.3.1 `uri` constructors [class.uri.members.constructors]

    uri();

Effects: Constructs an object of class `uri`.
Postconditions: `empty()`

    uri(const uri& other);

Effects: Constructs a `uri` object with the underlying data having the original values of `other`.

    uri(uri&& other) noexcept;

Effects: Constructs a `uri` object with the underlying data having the original values of `other`. `other` is left in a valid, but unspecified state.

    template <class Source, class Allocator = allocator<value_type>>
    uri(const Source& source, const Allocator& a = Allocator());

Effects: The source is copied into the `uri` object and parsed. The encoding is assumed to depend on the underlying character type and implementation. Conversion, if any, is performed as specified by [class.uri.conversions]. All memory allocation is performed by `a`.
Postconditions: `!empty() && is_absolute()`
Throws: `uri_error` if `source` is not a valid URI string.

    template <class InputIterator, class Allocator = allocator<value_type>>
    uri(InputIterator begin, InputIterator end, const Allocator& a = Allocator());

Effects: The source is copied into the `uri` object and parsed. The encoding is assumed to depend on the underlying character type and implementation. Conversion, if any, is performed as specified by [class.uri.conversions]. All memory allocation is performed by `a`.
Postconditions: `!empty() && is_absolute()`
Throws: `uri_error` if the string in the range [`begin`, `end`) is not a valid URI string.

#### 7.3.2 `uri` assignment [class.uri.members.assignment]

    uri& operator= (const uri& other);

Effects: Modifies the underlying data to have the original values of `other`. If `this` and `other` are the same object, there is no effect.

    uri& operator= (uri&& other) noexcept;

Effects: Modifies the underlying data to have the original values of `other`. `other` is left in a valid, but unspecified state. If `this` and `other` are the same object, there is no effect.

#### 7.3.3. `uri` modifiers [class.uri.members.modifiers]

    void swap(uri& other) noexcept;

Effects: Swaps the contents of `this` object with the other.

#### 7.3.4 `uri` iterators [class.uri.members.iterators]

    constexpr const_iterator begin() const noexcept;

Returns: A `const_iterator` to the first element in the underlying string container.

    constexpr const_iterator end() const noexcept;

Returns: A `const_iterator` to the end of the underlying string container.

    constexpr const_iterator cbegin() const noexcept;

Returns: A `const_iterator` to the first element in the underlying string container.

    constexpr const_iterator cend() const noexcept;

Returns: A `const_iterator` to the end of the underlying string container.

#### 7.3.5 `uri` accessors [class.uri.members.accessors]

    constexpr experimental::optional<string_view> scheme() const;

Returns: An `experimental::optional<string_view>` object which spans the range of the scheme in the underlying URI. If the scheme is not specified, it returns `nullopt`.

    constexpr experimental::optional<string_view> user_info() const;

Returns: An `experimental::optional<string_view>` object which spans the range of the user info in the underlying URI. If the user info is not specified, it returns `nullopt`.

    constexpr experimental::optional<string_view> host() const;

Returns: An `experimental::optional<string_view>` object which spans the range of the host in the underlying URI. If the host is not specified, it returns `nullopt`.

    constexpr experimental::optional<string_view> port() const;

Returns: An `experimental::optional<string_view>` object which spans the range of the port in the underlying URI. If the port is not specified, it returns `nullopt`.

    template <class intT>
    constexpr experimental::optional<intT> port() const;

Returns: An `experimental::optional<intT>` with the port value, if it is present. If the port is not specified, it returns `nullopt`.
Remarks: This function shall not participate in overload resolution unless `is_integral<intT>::value` is true.

    constexpr experimental::optional<string_view> path() const;

Returns: An `experimental::optional<string_view>` object which spans the range of the path in the underlying URI. If the path is not specified, it returns `nullopt`.

    constexpr experimental::optional<string_view> authority() const;

Returns: A `experimental::optional<string_view>` object which spans the range of the authority in the underlying URI. If the authority is not specified, it returns `nullopt`.

    constexpr experimental::optional<string_view> query() const;

Returns: An `experimental::optional<string_view>` object which spans the range of the query in the underlying URI. If the query is not specified, it returns `nullopt`.

    constexpr experimental::optional<string_view> fragment() const;

Returns: An `experimental::optional<string_view>` object which spans the range of the fragment in the underlying URI. If the fragment is not specified, it returns `nullopt`.

    template <class charT,
              class traits = char_traits<charT>,
              class Allocator = allocator<charT>>
    basic_string<charT, traits, Allocator>
    to_string(const Allocator& a = Allocator()) const;

Returns: A string object containing a copy of the underlying URI string. All memory allocation is performed by `a`.

Note

The name `to_string` has been chosen to be consistent with the `to_string` member function in `std::bitset` [20.5.2.34]. This, however, is inconsistent with the name (`string`) in the path class in the filesystem working draft N3940 [path.native.obs]. The same applies to all the string accessors.

    string string() const;

Returns: A string object containing a copy of the underlying URI string.
Remarks: Conversion, if any, is performed as specified by [class.uri.conversions].

    wstring wstring() const;

Returns: A wstring object containing a copy of the underlying URI string.
Remarks: Conversion, if any, is performed as specified by [class.uri.conversions].

    string u8string() const;

Returns: A UTF-8 encoded string object containing a copy of the underlying URI string.
Remarks: Conversion, if any, is performed as specified by [class.uri.conversions].

    u16string u16string() const;

Returns: A u16string object containing a copy of the underlying URI string.
Remarks: Conversion, if any, is performed as specified by [class.uri.conversions].

    u32string u32string() const;

Returns: A u32string object containing a copy of the underlying URI string.
Remarks: Conversion, if any, is performed as specified by [class.uri.conversions].

#### 7.3.6 `uri` query [class.uri.members.query]

    constexpr bool empty() const noexcept;

Returns: `true` if the underlying string object is empty, `false` otherwise.

    constexpr bool is_absolute() const noexcept;

Returns: `true` if the URI is absolute. Equivalent to `!scheme().empty()`.

    constexpr bool is_relative() const noexcept;

Returns: `true` if the URI is a relative reference. Equivalent to `!is_absolute()`.

    constexpr bool is_hierarchical() const noexcept;

Returns: `true` if the URI is absolute and its scheme is hierarchical (i.e. the scheme-specific part starts with two consecutive forward slash characters (“//”)).

    constexpr bool is_opaque() const noexcept;

Returns: `true` if the URI is absolute and its scheme is not hierarchical (i.e. the scheme-specific part does not start with two consecutive forward slash characters (“//”) and its authority is empty). Equivalent to `!is_hierarchical()`.

#### 7.3.7 `uri` transformers [class.uri.members.transformers]

This proposal specifies three transformer functions:, `normalize`, `make_relative` and `resolve`.

    uri normalize(uri_normalization_level level) const;

Effects: `normalize` returns a normalized `uri` object.
Postconditions: `u.normalize(level).compare(u, level) == 0`

    template <class Allocator>
    uri normalize(uri_normalization_level level, const Allocator& a) const;

Effects: `normalize` returns a normalized `uri` object. All memory allocation is performed by `a`.
Postconditions: `u.normalize(level).compare(u, level) == 0`

    uri normalize(uri_normalization_level level, error_code& ec) const;

Effects: `normalize` returns a normalized `uri` object. `ec` is set on error and `normalize` returns an empty `uri` object.
Postconditions: `ec || u.normalize(level).compare(u, level) == 0`

    template <class Allocator>
    uri normalize(uri_normalization_level level, const Allocator& a,
                  error_code& ec) const;

Effects: `normalize` returns a normalized `uri` object. All memory allocation is performed by `a`. `ec` is set on error and `normalize` returns an empty `uri` object.
Postconditions: `ec || u.normalize(level).compare(u, level) == 0`

    uri make_relative(const uri& u) const;

Effects: Returns a relative URI reference of `u` against `*this` as the base URI. If `*this` or `u` are opaque, or if the scheme and authority are not identical, or if the path of `*this` is not a prefix of the path in `u`, or if `*this` is a relative reference, then a `uri_error` is thrown. Making a relative URI reference is the inverse of resolving a URI, such that for two normalized `uri` objects, `u` and `v`, `u.make_relative(v).resolve(v) == u` and `u.resolve(v).make_relative(v) == u`.
Returns: A relative URI reference.
Throws: `uri_error`
Example:

    try {
      std::experimental::uri u("http://www.example.org/path/");
      std::experimental::uri v("http://www.example.org/path/to/file.html");
      std::experimental::uri w = u.make_relative(v);
      assert(w.string() == "to/file.html");
    }
    catch (const std::experimental::uri_error& e) {
      // handle error
    }

End example

    template <class Allocator>
    uri make_relative(const uri& u, const Allocator& a) const;

Effects: Returns a relative URI reference of `u` against `*this` as the base URI. If `*this` or `u` are opaque, or if the scheme and authority are not identical, or if the path of `*this` is not a prefix of the path in `u`, or if `*this` is a relative reference, then a `uri_error` is thrown. Making a relative URI reference is the inverse of resolving a URI, such that for two normalized `uri` objects, `u` and `v`, `u.make_relative(v).resolve(v) == u` and `u.resolve(v).make_relative(v) == u`. All memory allocation is performed by `a`.
Returns: A relative URI reference.
Throws: `uri_error`
Example:

    std::allocator<std::experimental::uri::value_type> a;
    try {
      std::experimental::uri u("http://www.example.org/path/", a);
      std::experimental::uri v("http://www.example.org/path/to/file.html", a);
      std::experimental::uri w = v.make_relative(u, a);
      assert(w.string() == "to/file.html");
    }
    catch (const std::experimental::uri_error& e) {
      // handle error
    }

End example

    uri make_relative(const uri& base, error_code& ec) const;

Effects: Returns a relative URI reference of `u` against `*this` as the base URI. If `*this` or `u` are opaque, or if the scheme and authority are not identical, or if the path of `*this` is not a prefix of the path in `u`, or if `*this` is a relative reference, then `ec` is set and `make_relative` returns an empty `uri` object. Making a relative URI reference is the inverse of resolving a URI, such that for two normalized `uri` objects, `u` and `v`, `u.make_relative(v).resolve(v) == u` and `u.resolve(v).make_relative(v) == u`.
Returns: A relative URI reference.
Example:

    std::experimental::uri u("http://www.example.org/path/");
    std::experimental::uri v("http://www.example.org/path/to/file.html");
    std::error_code ec;
    std::experimental::uri w = v.make_relative(u, ec);
    if (!ec) {
      assert(w.string() == "to/file.html");
    }
    else {
      // handle error
    }

End example

    template <class Allocator>
    uri make_relative(const uri& base, const Allocator &a,
                      error_code& ec) const;

Effects: Returns a relative URI reference of `u` against `*this` as the base URI. If `*this` or `u` are opaque, or if the scheme and authority are not identical, or if the path of `*this` is not a prefix of the path in `u`, or if `*this` is a relative reference, then `ec` is set and `make_relative` returns an empty `uri` object. Making a relative URI reference is the inverse of resolving a URI, such that for two normalized `uri` objects, `u` and `v`, `u.make_relative(v).resolve(v) == u` and `u.resolve(v).make_relative(v) == u`. All memory allocation is performed by `a`.
Returns: A relative URI reference.
Example:

    std::allocator<std::experimental::uri::value_type> a;
    std::experimental::uri u("http://www.example.org/path/", a);
    std::experimental::uri v("http://www.example.org/path/to/file.html", a);
    std::error_code ec;
    std::experimental::uri w = v.make_relative(u, a, ec);
    if (!ec) {
      assert(w.string() == "to/file.html");
    }
    else {
      // handle error ec
    }

End example

    uri resolve(const uri& u) const;

Effects: Resolves `u` against `*this` according to IETF RFC 3986, section 5.2.1, then transforms the reference according to IETF 3986, section 5.2.2. The resolved `uri` object is returned. A `uri_error` is thrown if `*this` is invalid (10.2 URI Reference and Resolution Errors [class.uri_errc.rar]).
Throws: `uri_error`

    template <class Allocator>
    uri resolve(const uri& u, const Allocator& a) const;

Effects: Resolves `u` against `*this` according to IETF RFC 3986, section 5.2.1, then transforms the reference according to IETF 3986, section 5.2.2. The resolved `uri` object is returned. A `uri_error` is thrown if `*this` is invalid (10.2 URI Reference and Resolution Errors [class.uri_errc.rar]). All memory allocation is performed by `a`.
Throws: `uri_error`

    uri resolve(const uri& u, error_code& ec) const;

Effects: Resolves `u` against `*this` according to IETF RFC 3986, section 5.2.1, then transforms the reference according to IETF 3986, section 5.2.2. The resolved `uri` object is returned. `ec` is set on error and `resolve` returns an empty `uri` object.

    template <class Allocator>
    uri resolve(const uri& u, const Allocator& a, error_code& ec) const;

Effects: Resolves `u` against `*this` according to IETF RFC 3986, section 5.2.1, then transforms the reference according to IETF 3986, section 5.2.2. The resolved `uri` object is returned. `ec` is set on error and `resolve` returns an empty `uri` object. All memory allocation is performed by `a`.

#### 7.3.8 `uri` comparison [class.uri.members.comparison]

    constexpr int compare(const uri& other, uri_normalization_level level) const noexcept;

Effects: Equivalent to `normalize(level) == other.normalize(level)`
Returns: -1 if the normalized value of this is lexicographically less than the normalized value `other`, given the comparison `level`; 0 if they are considered equal and 1 if this is greater.

#### 7.3.9 `uri` percent encoding [class.uri.members.percent]

    template <class InputIterator, class OutputIterator>
    static OutputIterator encode_user_info(InputIterator begin, InputIterator end,
                                           OutputIterator out);

Effects: Encodes special characters for the user_info part (IETF RFC 3986, section 2.1).
Returns: An iterator to the last element of a `user_info` string that has been encoded.

    template <class InputIterator, class OutputIterator>
    static OutputIterator encode_host(InputIterator begin, InputIterator end,
                                      OutputIterator out);

Effects: Encodes special characters for the host part (IETF RFC 3986, section 2.1).
Returns: An iterator to the last element of a `host` string that has been encoded.

    template <class InputIterator, class OutputIterator>
    static OutputIterator encode_port(InputIterator begin, InputIterator end,
                                      OutputIterator out);

Effects: Encodes special characters for the port part (IETF RFC 3986, section 2.1).
Returns: An iterator to the last element of a `port` string that has been encoded.

    template <class InputIterator, class OutputIterator>
    static OutputIterator encode_path(InputIterator begin, InputIterator end,
                                      OutputIterator out);

Effects: Encodes special characters for the path part (IETF RFC 3986, section 2.1).
Returns: An iterator to the last element of a `path` string that has been encoded.

    template <class InputIterator, class OutputIterator>
    static OutputIterator encode_query(InputIterator begin, InputIterator end,
                                       OutputIterator out);

Effects: Encodes special characters for the query part (IETF RFC 3986, section 2.1).
Returns: An iterator to the last element of a `query` string that has been encoded.

    template <class InputIterator, class OutputIterator>
    static OutputIterator encode_fragment(InputIterator begin, InputIterator end,
                                          OutputIterator out);

Effects: Encodes special characters for the fragment part (IETF RFC 3986, section 2.1).
Returns: An iterator to the last element of a `fragment` string that has been encoded.

    template <class InputIterator, class OutputIterator>
    static OutputIterator decode(InputIterator begin, InputIterator end,
                                 OutputIterator out);

Effects: Decodes special characters in the source string and returns the unencoded string (IETF RFC 3986, section 2.1)
Returns: An iterator to the last element of a `uri` string that has been decoded.
Throws: `uri_error` when the input is exhausted, the input is not a hexadecimal character or when the decoding conversion fails.

## 8 Class `uri_builder` [class.uri_builder]

    namespace std {
    namespace experimental {
    class uri_builder {

    public:

        // constructors and destructor
        uri_builder();
        explicit uri_builder(const uri& base_uri);
        template <class Source>
        explicit uri_builder(const Source& base_uri);
        template <class InputIterator>
        uri_builder(InputIterator begin, InputIterator end);
        uri_builder(const uri_builder& other);
        uri_builder(uri_builder&& other) noexcept;
        ~uri_builder();

        // assignment
        uri_builder& operator= uri_builder(const uri_builder&);
        uri_builder& operator= uri_builder(uri_builder&&) noexcept;

        // modifiers
        void swap(uri_builder& other) noexcept;

        // setters
        template <class Source>
        uri_builder& scheme(const Source& scheme);
        template <class InputIterator>
        uri_builder& scheme(InputIterator begin, InputIterator end);
        template <class Source>
        uri_builder& user_info(const Source& user_info);
        template <class InputIterator>
        uri_builder& user_info(InputIterator begin, InputIterator end);
        template <class Source>
        uri_builder& host(const Source& host);
        template <class InputIterator>
        uri_builder& host(InputIterator begin, InputIterator end);
        template <class Source>
        uri_builder& port(const Source& port);
        template <class InputIterator>
        uri_builder& port(InputIterator begin, InputIterator end);
        template <class Source>
        uri_builder& authority(const Source& authority);
        template <class InputIterator>
        uri_builder& authority(InputIterator begin, InputIterator end);
        template <class UserInfoSource, class HostSource, PortSource>
        uri_builder& authority(const UserInfoSource& user_info,
                               const HostSource& host, const PortSource& port);
        template <class Source>
        uri_builder& path(const Source& path);
        template <class InputIterator>
        uri_builder& path(InputIterator begin, InputIterator end);
        template <class Source>
        uri_builder& append_path(const Source& path);
        template <class InputIterator>
        uri_builder& append_path(InputIterator begin, InputIterator end);
        template <class Source>
        uri_builder& query(const Source& query);
        template <class InputIterator>
        uri_builder& query(InputIterator begin, InputIterator end);
        template <class KeySource, class ParamSource>
        uri_builder& append_query(const KeySource& key, const ParamSource& param);
        template <class Source>
        uri_builder& fragment(const Source& fragment);
        template <class InputIterator>
        uri_builder& fragment(InputIterator begin, InputIterator end);

        // builder
        uri uri() const;

    };
    } // namespace experimental
    } // namespace std

### 8.1 `uri_builder` requirements [class.uri_builder.requirements]

The URI shall be built according to component recomposition rules in IETF RFC 3986, section 5.3.

### 8.2 `uri_builder` constructors [class.uri_builder.constructors]

    uri_builder();

Effects: An immediate call to `uri()` will result in an empty object.

    uri_builder(const uri& base_uri);

Effects: Constructs a `uri_builder` object from a base URI [uri.definition.base-uri].
Example:

    std::experimental::uri base_uri("http://www.example.com");
    std::experimental::uri_builder builder(uri);
    builder.path("path");
    assert(builder.uri() == "http://www.example.com/path");

End example

    template <class Source>
    uri_builder(const Source& base_uri);
    template <class InputIterator>
    uri_builder(InputIterator begin, InputIterator end);

Effects: Constructs a `uri_builder` object from a base URI [uri.definition.base-uri].
Example:

    std::experimental::uri_builder builder("http://www.example.com");
    builder.path("path");
    assert(builder.uri() == "http://www.example.com/path");

End example
Throws: `uri_error` if `base_uri` is not a valid URI.

    uri_builder(const uri_builder& other);

Effects: Constructs a `uri` object with the underlying data having the original values of `other`.

    uri_builder(uri_builder&& other) noexcept;

Effects: Constructs a `uri` object with the underlying data having the original values of `other`. `other` is left in a valid, but unspecified state.

### 8.3 `uri_builder` assignment [class. uri_builder.members.assignment]

    uri_builder& operator= (const uri_builder& other);

Effects: Modifies the underlying data to have the original values of `other`. If `this` and `other` are the same object, there is no effect.

    uri_builder& operator= (uri_builder&& other) noexcept;

Effects: Modifies the underlying data to have the original values of `other`. `other` is left in a valid, but unspecified state. If `this` and `other` are the same object, there is no effect.

### 8.4 `uri_builder` members [class.uri_builder.members]

    void swap(uri_builder& other) noexcept;

Effects: Swaps the contents of `this` object with the other.

    template <class Source>
    uri_builder& scheme(const Source& scheme);
    template <class InputIterator>
    uri_builder& scheme(InputIterator begin, InputIterator end);

Effects: Sets the URI scheme.

    template <class Source>
    uri_builder& user_info(const Source& user_info);
    template <class InputIterator>
    uri_builder& user_info(InputIterator begin, InputIterator end);

Effects: Sets the URI user_info.

    template <class Source>
    uri_builder& host(const Source& host);
    template <class InputIterator>
    uri_builder& host(InputIterator begin, InputIterator end);

Effects: Sets the URI host.

    template <class Source>
    uri_builder& port(const Source& port);
    template <class InputIterator>
    uri_builder& port(InputIterator begin, InputIterator end);

Effects: Sets the URI port.

    template <class Source>
    uri_builder& authority(const Source& authority);
    template <class InputIterator>
    uri_builder& authority(InputIterator begin, InputIterator end);

Effects: Sets the URI authority.

    template <class UserInfoSource, class HostSource, class PortSource>
    uri_builder& authority(const UserInfoSource& user_info,
                           const HostSource& host, const PortSource& port);

Effects: Sets the URI user info, host and port.

    template <class Source>
    uri_builder& path(const Source& path);
    template <class InputIterator>
    uri_builder& path(InputIterator begin, InputIterator end);

Effects: Sets the URI path.

    template <class Source>
    uri_builder& append_path(const Source& path);
    template <class InputIterator>
    uri_builder& append_path(InputIterator begin, InputIterator end);

Effects: Appends an element to the `uri` object’s path.

    template <class Source>
    uri_builder& query(const Source& query);
    template <class InputIterator>
    uri_builder& query(InputIterator begin, InputIterator end);

Effects: Sets the URI query.

    template <class KeySource, class ParamSource>
    uri_builder& append_query(const KeySource& key, const ParamSource& param);

Effects: Appends a key-value pair to the `uri` object’s query.

    template <class Source>
    uri_builder& fragment(const Source& fragment);
    template <class InputIterator>
    uri_builder& fragment(InputIterator begin, InputIterator end);

Effects: Sets the URI fragment.

    uri uri() const;

Effects: Builds a URI object from the provided parts. A URI built using this method should be normalized according to syntax-based normalization. This includes case normalization, percent-encoding normalization, character normalization and path segment normalization.
Throws: `uri_error` if any of the parts are invalid and a valid uri cannot be formed.

## 9 Class `uri_error` [class.uri_error]

    namespace std {
    namespace experimental {
    class uri_error : public system_error {
    public:
        uri_error(const string& what_arg, error_code ec);
        virtual ~uri_error();
        virtual const char *what() const noexcept;
    };
    } // namespace experimental
    } // namespace std

### 9.1 `uri_error` members [class.uri_error.members]

#### 9.1.1 `uri_error` constructors [class.uri_error.constructors]

    uri_error(const string& what_arg, error_code ec);

Postconditions: `what() == what_arg.c_str() && code() == ec`

#### 9.1.2 `uri_error` accessors [class.uri_error.accessors]

    const char *what() const noexcept;

Returns: A string containing the message in the string passed as `what_arg` to the class constructor.

## 10 Enum class `uri_errc` [class.uri_errc]

    enum class uri_errc {
     // uri syntax errors
     invalid_syntax = 1,

     // uri relative reference and resolution errors
     base_uri_is_empty,
     base_uri_is_not_absolute,
     base_uri_is_opaque,
     base_uri_does_not_match,

     // builder errors
     invalid_uri,
     invalid_scheme,
     invalid_user_info,
     invalid_host,
     invalid_port,
     invalid_path,
     invalid_query,
     invalid_fragment,

     // decoding errors
     not_enough_input,
     non_hex_input,
     conversion_failed,
    };

### 10.1 URI Syntax Errors [class.uri_errc.uri_syntax]

#### 10.1.1 `invalid_syntax` [class.uri_errc.uri_syntax.invalid_syntax]

This error is set when the parser is unable to parse the given URI string.

### 10.2 URI Reference and Resolution Errors [class.uri_errc.rar]

#### 10.2.1 `base_uri_is_empty` [class.uri_errc.rar.base_uri_is_empty]

This error is set when the base URI passed to `make_relative` or `resolve` is empty.

#### 10.2.2 `base_uri_is_not_absolute` [class.uri_errc.rar.base_uri_is_not_absolute]

This error is set when the base URI passed to `make_relative` or `resolve` is not absolute (it is itself a relative reference).

#### 10.2.3 `base_uri_is_opaque` [class.uri_errc.rar.base_uri_is_opaque]

This error is set when the base URI passed to `make_relative` or `resolve` is opaque.

#### 10.2.4 `base_uri_does_not_match` [class.uri_errc.rar.base_uri_does_not_match]

This error is set when the base URI passed to `make_relative` does not match the prefix of the URI.

### 10.3 URI Builder Errors [class.uri_errc.uri_builder]

#### 10.3.1 `invalid_uri` [class.uri_errc.uri_builder.invalid_uri]

This error is set by the `uri_builder` when the builder is unable to construct a valid URI.

#### 10.3.2 `invalid_scheme` [class.uri_errc.uri_builder.invalid_scheme]

This error is set by the `uri_builder` if the scheme provided is invalid.

#### 10.3.3 `invalid_user_info` [class.uri_errc.uri_builder.invalid_user_info]

This error is set by the `uri_builder` if the user info provided is invalid.

#### 10.3.4 `invalid_host` [class.uri_errc.uri_builder.invalid_host]

This error is set by the `uri_builder` if the host provided is invalid.

#### 10.3.5 `invalid_port` [class.uri_errc.uri_builder.invalid_port]

This error is set by the `uri_builder` if the port provided is invalid.

#### 10.3.6 `invalid_path` [class.uri_errc.uri_builder.invalid_port]

This error is set by the `uri_builder` if the path provided is invalid.

#### 10.3.7 `invalid_query` [class.uri_errc.uri_builder.invalid_query]

This error is set by the `uri_builder` if the query provided is invalid.

#### 10.3.8 `invalid_fragment` [class.uri_errc.uri_builder.invalid_fragment]

This error is set by the `uri_builder` if the fragment provided is invalid.

### 10.4 Percent Decoding Errors [class.uri_errc.percent_decoding]

#### 10.4.1 `not_enough_input` [class.uri_errc.percent_decoding.not_enough_input]

This error is set when not enough input was given to the decoder to be able to decode the percent encoded string, e.g. `%2`.

#### 10.4.2 `non_hex_input` [class.uri_errc.percent_decoding.non_hex_input]

This error is set when non-hex input is given to the decoder, e.g. `%GG`.

#### 10.4.3 `conversion_failed` [class.uri_errc.percent_decoding.conversion_failed]

This error is set when the decoder was unable to convert the percent encoded string, e.g. `%80`.

## Issues

Note

Issues

1. Normalization Invariant

At the Chicago meeting, it was strongly suggested that URIs are always normalized. However, this does not play well when working with filesystem URIs, especially if they refer to symbolic links and therefore it makes sense in these circumstances to keep the URI unnormalized. Therefore, the changes made after the Chicago meeting have been reverted, and URIs can be left unnormalized. A `normalize` member function exists to provide the conversion explicitly.

2. Scheme-Specific Normalization

There needs to be an extension point in order to allow scheme- and protocol- specific normalization.

3. empty() vs. is_absolute() vs. is_opaque()

In the minutes to the Chicago meeting, there was a suggestion that the `is_` prefix is being applied inconsistently. The current way is consistent with at least the filesystem proposal, but clarification should be made with the LEWG.

4. Factory Functions

The `make_uri` factory functions are free functions, but the LEWG needs to clarify if they can remain this way or if they should be static members of `uri`.

5. Source Template Parameters

The `Source` template parameters seem overly generic, this will be taken up with the LEWG.

6. to_string() etc.

A decision needs to be taken in order to determine if the string accessors [class.uri.members.accessors] should be consistent with `std::experimental::filesystem::path`, or if they will be different by design.

7. string_view null-state

The new TS has changed basic_string_view so that it has its own null state that can be created by calling the `basic_string_view` default constructor. There may be a case to remove `optional` from the URI parts accessors. If that were to happen, the authors of this paper would recommend a more explicit accessor in `basic_string_view` to test the null state than by checking the pointer returned by `data()`.

## Acknowledgements

Note

C++ Network Library users and mailing list

Kyle Kloepper and Niklas Gustafsson for providing valuable feedback and encouragement, and for presenting different versions of this proposal at committee meetings.

The BSI C++ panel for their guidance and patience in reviewing every draft of this proposal.

Beman Dawes and his Filesystem proposal from which I was influenced strongly in the class design.

Thiago Macieira and Daniel Kruegler for important feedback on the draft proposal.

David Thaler for suggesting corrections to errors in referencing IETF standards.

Wikipedia, for being there.