/* * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. * * Copyright 2015, 2017, 2021 Danny Robson */ #pragma once #include "debug/assert.hpp" #include "view.hpp" #include #include #include #include #include #include namespace cruft { // parsing of rfc3986 uniform resource identifiers // // does not currently perform normalisation (scheme or protocol), // comparison, or other associated operations. though these should be // added in the future. // // note that the parsed results may not always conform to expectations // for some protocols. eg, mailto identifiers are complex to parse // reliably and would require a specialised parser to be reliable. // // not all fields will be present for all protocols (or all instances of // any given protocol). eg, the "tel" is unlikely to have port numbers. class uri { public: explicit uri (std::string &&); uri& operator= (uri &&) noexcept; uri (uri const&); uri& operator= (uri const&); explicit uri (const std::string&); explicit uri (const char *); explicit uri (view); uri ( std::string_view scheme, std::string_view authority, std::string_view path, std::string_view query, std::string_view fragment ); class parse_error : public std::runtime_error { using runtime_error::runtime_error; }; // URI: 'https://user:password@example.com:80/path/to?foo=bar#fragment' // // SCHEME: 'https' // HIERARCHICAL: 'user:password@example.com:80/path/to' // AUTHORITY: 'user:password@example.com:80' // USER: 'user:password' // HOST: 'example.com' // PORT: '80' // PATH: '/path/to' // QUERY: 'foo=bar' // FRAGMENT: 'fragment' enum component { /* 0 */ SCHEME, /* 1 */ HIERARCHICAL, /* 2 */ AUTHORITY, /* 3 */ USER, /* 4 */ HOST, /* 5 */ PORT, /* 6 */ PATH, /* 7 */ QUERY, /* 8 */ FRAGMENT, NUM_COMPONENTS }; std::string_view get (component c) const&; void set (component c, std::string_view); std::string_view all (void) const& { return m_value; } std::string const& value (void) const& { return m_value; } std::string_view scheme (void) const& { return get (SCHEME); } std::string_view heirarchical (void) const& { return get (HIERARCHICAL); } std::string_view authority (void) const& { return get (AUTHORITY); } std::string_view user (void) const& { return get (USER); } std::string_view host (void) const& { return get (HOST); } std::string_view port (void) const& { return get (PORT); } std::string_view path (void) const& { return get (PATH); } std::string_view query (void) const& { return get (QUERY); } std::string_view fragment (void) const& { return get (FRAGMENT); } // void clear (component); void clear_fragment (void); auto components (void) const& noexcept { return m_views; } static std::string percent_decode (view); private: void parse (void); std::array, NUM_COMPONENTS> m_views; std::string m_value; }; /// Break a query string into a sequence of key-value pairs. /// Duplicates are possible. /// vector is used to that order can be preserved /// The is the inverse of vector_to_query std::vector> query_to_vector (std::string_view); /// Convert a sequence of key-value pairs into a query string /// All pairs, including duplicates, are serialised in the provided order. /// This is the inverse of query_to_vector std::string vector_to_query (std::vector> const&); bool operator== (uri const&, uri const&) noexcept; cruft::uri resolve (cruft::uri const &base, cruft::uri const &child); cruft::uri normalise (cruft::uri const &); std::ostream& operator<< (std::ostream&, uri const&); std::ostream& operator<< (std::ostream&, uri::component); }