diff --git a/doc/AuthorityDiagram.odg b/doc/AuthorityDiagram.odg new file mode 100644 index 00000000..4c7f783c Binary files /dev/null and b/doc/AuthorityDiagram.odg differ diff --git a/doc/PartsDiagram.odg b/doc/PartsDiagram.odg index db7c2d15..5cb8c328 100644 Binary files a/doc/PartsDiagram.odg and b/doc/PartsDiagram.odg differ diff --git a/doc/images/AuthorityDiagram.svg b/doc/images/AuthorityDiagram.svg new file mode 100644 index 00000000..3a936b55 --- /dev/null +++ b/doc/images/AuthorityDiagram.svg @@ -0,0 +1,160 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [ user ] + + + + + + + + [ “:” port ] + + + + + + + + host + + + + + + + + [ “:” password ] + + + + + + userinfo + + + + + + authority + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/doc/images/PartsDiagram.svg b/doc/images/PartsDiagram.svg index 69014c57..f0319687 100644 --- a/doc/images/PartsDiagram.svg +++ b/doc/images/PartsDiagram.svg @@ -1,12 +1,12 @@ - + - + - + @@ -155,7 +155,7 @@ - + [ scheme”:” ] @@ -163,7 +163,7 @@ - + [ “#” fragment ] @@ -171,7 +171,7 @@ - + [ “?” query ] @@ -179,7 +179,7 @@ - + path @@ -187,7 +187,7 @@ - + [ “//” authority ] diff --git a/doc/qbk/0.main.qbk b/doc/qbk/0.main.qbk index 31543a0d..2d754949 100644 --- a/doc/qbk/0.main.qbk +++ b/doc/qbk/0.main.qbk @@ -36,6 +36,7 @@ [def __rfc1738__ [@https://tools.ietf.org/html/rfc1738 rfc1738]] [/ URIs, URLs, URNs: Clarifications and Recommendations ] [def __rfc3305__ [@https://tools.ietf.org/html/rfc3305 rfc3305]] +[def __rfc7230__ [@https://tools.ietf.org/html/rfc7230 rfc7230]] [/ Named Requirements ] @@ -61,6 +62,7 @@ [def __std_string__ [@https://en.cppreference.com/w/cpp/string/basic_string `std::string`]] [def __std_tuple__ [@https://en.cppreference.com/w/cpp/utility/tuple `std::tuple`]] [def __std_get__ [@https://en.cppreference.com/w/cpp/utility/tuple/get `std::get`]] +[def __std_string_view__ [@https://en.cppreference.com/w/cpp/string/basic_string_view `std::string_view`]] [def __absolute_uri_rule__ [link url.ref.boost__urls__absolute_uri_rule `absolute_uri_rule`]] [def __authority_rule__ [link url.ref.boost__urls__authority_rule `authority_rule`]] @@ -71,12 +73,18 @@ [def __optional__ [link url.ref.boost__urls__optional `optional`]] [def __origin_form_rule__ [link url.ref.boost__urls__origin_form_rule `origin_form_rule`]] [def __parse_uri__ [link url.ref.boost__urls__parse_uri `parse_uri`]] +[def __params__ [link url.ref.boost__urls__params `params`]] +[def __params_view__ [link url.ref.boost__urls__params_view `params_view`]] +[def __params_encoded__ [link url.ref.boost__urls__params_encoded `params_encoded`]] +[def __params_encoded_view__ [link url.ref.boost__urls__params_encoded_view `encoded_params_view`]] [def __pchars__ [link url.ref.boost__urls__pchars `pchars`]] [def __pct_encoded_view__ [link url.ref.boost__urls__pct_encoded_view `pct_encoded_view`]] [def __pct_encoded_rule__ [link url.ref.boost__urls__pct_encoded_rule `pct_encoded_rule`]] [def __query_param_view__ [link url.ref.boost__urls__query_param_view `query_param_view`]] [def __result__ [link url.ref.boost__urls__result `result`]] +[def __segments__ [link url.ref.boost__urls__segments `segments`]] [def __segments_view__ [link url.ref.boost__urls__segments_view `segments_view`]] +[def __segments_encoded__ [link url.ref.boost__urls__segments_encoded `segments_encoded`]] [def __segments_encoded_view__ [link url.ref.boost__urls__segments_encoded_view `segments_encoded_view`]] [def __static_url__ [link url.ref.boost__urls__static_url `static_url`]] [def __string_view__ [link url.ref.boost__urls__string_view `string_view`]] @@ -121,37 +129,19 @@ [include 1.0.overview.qbk] [include 2.0.quicklook.qbk] -[include 2.1.HelpCard.qbk] -[include 3.0.urls.qbk] - -[section Containers] -[include 4.1.parsing.qbk] -[include 4.2.modifying.qbk] -[endsect] - -[section URL Components] -[heading Generic Syntax] -The five parts of the ['generic URI syntax] are shown below: -[$url/images/PartsDiagram.svg] - -[include 5.1.scheme.qbk] -[include 5.2.authority.qbk] -[include 5.3.path.qbk] -[include 5.4.query.qbk] -[include 5.5.fragment.qbk] -[endsect] - -[include 6.0.grammar.qbk] -[include 7.0.concepts.qbk] -[include 8.0.examples.qbk] +[include 3.0.containers.qbk] +[include 4.0.grammar.qbk] +[include 5.0.concepts.qbk] +[include 6.0.examples.qbk] [section:ref Reference] [xinclude quickref.xml] [block''''''] [include reference.qbk] [block''''''] + +[include 7.1.HelpCard.qbk] + [endsect] - - [xinclude index.xml] diff --git a/doc/qbk/1.0.overview.qbk b/doc/qbk/1.0.overview.qbk index 28415109..a2898674 100644 --- a/doc/qbk/1.0.overview.qbk +++ b/doc/qbk/1.0.overview.qbk @@ -25,14 +25,12 @@ this is a valid URL which satisfies the ['absolute-URI] grammar: https://www.example.com/path/to/file.txt?userid=1001&page=2&results=full ``` -[/ Introduction to URL ] - This library understands the various grammars related to URLs and provides functionalities for: -* validating and parsing of strings, -* manipulation of URL strings, and -* algorithms operating on URLs such as normalization and resolution. +* Validating and parsing of strings, +* Manipulation of URL strings, and +* Algorithms such as normalization and resolution. [heading Features] @@ -43,9 +41,9 @@ case where the inputs come from untrusted sources. Interfaces are provided for using error codes instead of exceptions as needed, and all algorithms provide a mechanism for avoiding memory allocations entirely -if desired. Another feature of the library is that all container mutations leave the -URL in a valid state. Code which uses Boost.URL will be easy to read, -flexible, and performant. +if desired. Another feature of the library is that all container mutations +leave the URL in a valid state. Code which uses Boost.URL will be easy to +read, flexible, and performant. Boost.URL offers these features: @@ -56,8 +54,8 @@ Boost.URL offers these features: * Allocator control, including avoiding allocation entirely * Optional header-only, without linking to a library * Supports `-fno-exceptions`, detected automatically -* Link to a built static or dynamic Boost library, or use [link header-only header-only] -* Work well on [link embedded-devices embedded devices]. +* Link to a built static or dynamic Boost library, or use header-only +* Work well on embedded devices [/-----------------------------------------------------------------------------] @@ -69,23 +67,21 @@ The library requires Boost 1.80.0 and a compiler supporting at least C++11. Boost [*1.80.0] or higher is a requirement for installation of this library proposal. ] -Aliases for standard types, such as __string_view__, use their Boost equivalents. +Aliases for standard types, such as __error_code__ or __string_view__, +use their Boost equivalents. -[#header-only] [heading Header-Only] -To use the library as header-only; that is, to eliminate the requirement to -link a program to a static or dynamic Boost.URL library, simply -place the following line in exactly one new or existing source -file in your project. +To use the library as header-only; that is, to eliminate the requirement +to link a program to a static or dynamic Boost.URL library, simply place +the following line in [*exactly one] source file in your project. [c++] ``` #include ``` -[#cmake] -[heading CMake Integration] +[heading CMake] The library can work both as a module of the Boost super-project or as an independent library that depends on Boost 1.78.0. In both cases, @@ -111,7 +107,7 @@ is designed to work without exceptions if desired. [/-----------------------------------------------------------------------------] -[section Supported Compilers] +[heading Tested Compilers] Boost.URL has been tested with the following compilers: @@ -119,26 +115,52 @@ Boost.URL has been tested with the following compilers: * gcc: 4.8, 4.9, 5, 6, 7, 8, 9, 10, 11 * msvc: 14.0, 14.1, 14.2, 14.3 -[h3 Quality Assurance] +and these architectures: x86, x64, ARM64, S390x. + +[heading Quality Assurance] The development infrastructure for the library includes these per-commit analyses: * Coverage reports -* Compilation and tests on Drone.io, Azure Pipelines, Appveyor +* Compilation and tests on Drone.io and GitHub Actions * Fuzzing using clang-llvm and machine learning +* Regular code audits for security + +[/-----------------------------------------------------------------------------] + +[section Nomenclature] + +Various names have been used historically to refer to different +flavors of resource identifiers, including ['URI], ['URL], +and ['URN]. Over time, the distinction between URIs and URLs +has disappeared when discussed in technical documents and +informal works. In this library we use the term [*URL] to +refer to all strings which are valid according to the +top-level grammar rules found in __rfc3986__. [endsect] +[heading ABNF] + +This documentation uses the Augmented +[@https://en.wikipedia.org/wiki/Backus%E2%80%93Naur_form Backus-Naur Form] +(ABNF) notation of +[@https://datatracker.ietf.org/doc/html/rfc5234 rfc5234] +to specify particular grammars used by algorithms and containers. While +a complete understanding of the notation is not a requirement for using +the library, it may help for an understanding of how valid components of +URLs are defined. In particular, this will be of interest to users who +wish to compose parsing algorithms using the combinators provided by +the library. + [/-----------------------------------------------------------------------------] [section:security_review Security Review (Bishop Fox)] To be announced [endsect] -[/-----------------------------------------------------------------------------] - -[h1 Acknowledgments] +[heading Acknowledgments] This library wouldn't be where it is today without the help of [@https://github.com/pdimov Peter Dimov] @@ -146,8 +168,4 @@ for design advice and general assistance. [/-----------------------------------------------------------------------------] -[h1 Documentation] - -Visit [@https://master.url.cpp.al/ https://master.url.cpp.al/] for complete documentation. - [endsect] diff --git a/doc/qbk/3.0.urls.qbk b/doc/qbk/1.1.nomenclature.qbk similarity index 99% rename from doc/qbk/3.0.urls.qbk rename to doc/qbk/1.1.nomenclature.qbk index 00613360..48862926 100644 --- a/doc/qbk/3.0.urls.qbk +++ b/doc/qbk/1.1.nomenclature.qbk @@ -7,7 +7,7 @@ Official repository: https://github.com/CPPAlliance/url ] -[section URLs, URIs, and URNs] +[section Nomenclature] Uniform Resource Locators (URL - __rfc1738__), also informally called "web addresses", are able to describe the name and location of a resource. A URL scheme, such as `http`, diff --git a/doc/qbk/2.0.quicklook.qbk b/doc/qbk/2.0.quicklook.qbk index f9590a07..32384efd 100644 --- a/doc/qbk/2.0.quicklook.qbk +++ b/doc/qbk/2.0.quicklook.qbk @@ -83,8 +83,7 @@ You can parse the string by calling this function: The function __parse_uri__ returns an object of type `__result__<__url_view__>` which is a container resembling a variant that holds either an error or an object. -A number of [link section.url_view functions] are available to parse different -types of URL. +A number of functions are available to parse different types of URL. We can immediately call `result::value` to obtain a __url_view__. @@ -121,27 +120,7 @@ also be used to check if the string has been parsed without errors. Accessing the parts of the URL is easy: -[table [[Code][Output]] [[ -[c++] [snippet_accessing_1] -][ -[teletype] -``` - - - url : https://user:pass@example.com:443/path/to/my%2dfile.txt?id=42&name=John%20Doe+Jingleheimer%2DSchmidt#page%20anchor - scheme : https - authority : user:pass@example.com:443 - userinfo : user:pass - user : user - password : pass - host : example.com - port : 443 - path : /path/to/my-file.txt - query : id=42&name=John Doe Jingleheimer-Schmidt - fragment : page anchor -``` -]]] URL paths can be further divided into path segments with the function [link url.ref.boost__urls__url_view.segments `url_view::segments`]. @@ -173,49 +152,13 @@ By simply referencing the relevant portion of the URL string, its components can represent percent-decoded strings without any need to allocate memory. -These functions might also return empty strings both for empty and absent -components. +These functions might also return empty strings -[table [[Code][Output]] [[ -[c++] [snippet_accessing_2a] -][ -[teletype] -``` - fragment 1 : -``` -]][[ -[c++] + +for both for empty and absent components + [snippet_accessing_2b] -][ -[teletype] -``` - fragment 2 : -``` -]]] - -To differentiate between empty and absent components, we can use -functions such as [link url.ref.boost__urls__url_view.has_fragment `has_fragment`]: - -[table [[Code][Output]] [[ -[c++] -[snippet_accessing_3a] -][ -[teletype] -``` - has fragment 1 : 0 - fragment 1 : -``` -]][[ -[c++] -[snippet_accessing_3b] -][ -[teletype] -``` - has fragment 2 : 1 - fragment 2 : -``` -]]] Many components do not have corresponding functions such as [link url.ref.boost__urls__url_view.has_authority `has_authority`] @@ -299,6 +242,9 @@ in a web server: [c++] [snippet_decoding_4a] +This allows us to easily match files in the document +root directory of a web server: + [c++] [snippet_decoding_4b] diff --git a/doc/qbk/3.0.containers.qbk b/doc/qbk/3.0.containers.qbk new file mode 100644 index 00000000..ef23f527 --- /dev/null +++ b/doc/qbk/3.0.containers.qbk @@ -0,0 +1,71 @@ +[/ + Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com) + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + Official repository: https://github.com/CPPAlliance/url +] + +[section Containers] + +All URLs conform to the ['generic syntax]. Every URL is +either ['hierarchical], or ['opaque], with the hierarchical +URLs further distinguished by whether they are ['relative] +or ['absolute]. Here are some examples of URLs and their +identification: + +[teletype] +[table URL Examples [ + [URL] + [Notes] +][ + [`https://www.boost.org/index.html`] + [Hierarchical URL with `https` protocol. Resource in the HTTP protocol.] +][ + [`ftp://host.dom/etc/motd`] + [Hierarchical URL with `ftp` scheme. Resource in the FTP protocol.] +][ + [`urn:isbn:045145052`] + [Opaque URL with `urn` scheme. Identifies `isbn` resource.] +][ + [`mailto:person@example.com`] + [Opaque URL with `mailto` scheme. Identifies e-mail address.] +][ + [`index.html`] + [URL reference. Missing scheme and host.] +][ + [`www.boost.org`] + [A Protocol-Relative Link (PRL). Not a URL.] +]] + +This library provides the following containers, which +are capable of storing any possible URL: + +* __url__: A modifiable container for a URL. +* __url_view__: A non-owning reference to a valid URL. +* __static_url__: A URL with fixed-capacity storage. + +These containers maintain a useful invariant: they +always contain a valid URL. + +[heading Generic Syntax] + +This diagram shows the generic syntax which all URLs +conform to: + +[$url/images/PartsDiagram.svg] + +In the sections that follow we discuss the main parts +of the URL, parsing strings into the provided containers, +modifying parts of the container while preserving invariants, +and how to invoke common algorithms used with URLs. + +[include 3.1.parsing.qbk] +[include 3.2.scheme.qbk] +[include 3.3.authority.qbk] +[include 3.4.path.qbk] +[include 3.5.query.qbk] +[include 3.6.fragment.qbk] + +[endsect] diff --git a/doc/qbk/3.1.parsing.qbk b/doc/qbk/3.1.parsing.qbk new file mode 100644 index 00000000..610b5e6b --- /dev/null +++ b/doc/qbk/3.1.parsing.qbk @@ -0,0 +1,134 @@ +[/ + Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) + Copyright (c) 2022 Alan de Freitas (vinnie.falco@gmail.com) + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + Official repository: https://github.com/CPPAlliance/url +] + +[section Parsing] + +Algorithms which parse URLs return a view which references the +underlying character buffer without taking ownership, avoiding +memory allocations and copies. The following example parses a +string literal containing a +[@https://datatracker.ietf.org/doc/html/rfc3986#section-3 ['URI]]: + +[c++] +[snippet_parsing_url_1] + +The function returns a __result__ which holds a __url_view__ +if the string is a valid URL. Otherwise it holds an __error_code__. +It is impossible to construct a __url_view__ which refers to an +invalid URL. + +[warning + The caller is responsible for ensuring that the lifetime + of the character buffer extends until it is no longer + referenced by the view. These are the same semantics + as that of __std_string_view__. +] + +When a view is directly constructed from a __string_view__ it parses it +according to the +[@https://datatracker.ietf.org/doc/html/rfc3986#section-4.1 ['URI-reference]] +grammar, throwing an exception upon failure: + +[snippet_parsing_url_1b] + +The URL is stored in its serialized form. Therefore, it can +always be easily output, sent, or embedded as part of a +protocol: + +[snippet_parsing_url_1bb] + +A __url__ is an allocating container which owns its character buffer. +Upon construction from __url_view__, it allocates dynamic storage +to hold a copy of the string. + +[snippet_parsing_url_1bc] + +A __static_url__ is a container which owns its character buffer for +a URL whose maximum size is known. Upon construction from +__url_view__, it does not perform any dynamic memory allocations. + +[snippet_parsing_url_1bd] + +[heading Result Type] + +In many places, functions in the library have a return type which uses the +__result__ alias template. This class allows the parsing algorithms to +report errors without referring to exceptions. + +The functions `result::has_value` and `result::has_error` can be used to +check if the result contains an error. + +[snippet_parsing_url_1] + +This ensures `result::value` will not throw an error. In contexts where +it is acceptable to throw errors, `result::value` can be used directly. + +Check the reference for __result__ for a synopsis of the type. For complete +information please consult the full +[@boost:/libs/system/doc/html/system.html#ref_resultt_e `result`] +documentation in [@boost:/libs/system/doc/html/system.html Boost.System]. + +[heading URL types] + +Parsing functions are functions which start with the word "parse", +and are suffixed with the name of the grammar applied to the string. +For example, the function +[link url.ref.boost__urls__parse_relative_ref `parse_relative_ref`] +parses the grammar +found in +[@https://datatracker.ietf.org/doc/html/rfc3986#section-4.2 4.2.Relative Reference (rfc3986)]. +A URL string can also be parsed using one of the following functions: + +[table Parsing Functions [ + [Function] + [Grammar] + [Example] +][ + [[link url.ref.boost__urls__parse_uri `parse_uri`]] + [[@https://datatracker.ietf.org/doc/html/rfc3986#section-3 ['URI]]] + [[teletype]`http://www.boost.org/index.html?field=value#downloads`] +][ + [[link url.ref.boost__urls__parse_absolute_uri `parse_absolute_uri`]] + [[@https://datatracker.ietf.org/doc/html/rfc3986#section-4.3 ['absolute-URI]]] + [[teletype]`http://www.boost.org/index.html?field=value` (Does not support fragment)] +][ + [[link url.ref.boost__urls__parse_relative_ref `parse_relative_ref`]] + [[@https://datatracker.ietf.org/doc/html/rfc3986#section-4.2 ['relative-ref]]] + [[teletype]`//www.boost.org/index.html?field=value#downloads`] +][ + [[link url.ref.boost__urls__parse_uri_reference `parse_uri_reference`]] + [[@https://datatracker.ietf.org/doc/html/rfc3986#section-4.1 ['URI-reference]]] + [[teletype]`http://www.boost.org/index.html` (Any `URI` or `relative-ref`)] +][ + [[link url.ref.boost__urls__parse_origin_form `parse_origin_form`]] + [[@https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.1 ['origin-form]]] + [[teletype]`/index.html?field=value` (Used in HTTP requests (__rfc7230__))] +]] + +The functions [link url.ref.boost__urls__parse_uri `parse_uri`] and +[link url.ref.boost__urls__parse_absolute_uri `parse_absolute_uri`] +are only valid if the URL contains the scheme component. +On the other hand, relative URI references are not required to +have a scheme. For instance, we can parse a relative URL that +only contains a path as + +[snippet_parsing_url_1c] + +These relative references can be combined with base absolute URLs: + +[snippet_parsing_url_1d] + +The [link url.ref.helpcard Help Card] provides a visual summary +of all of the member functions and types used by the library +with URL containers. In the sections that follow we discuss +each of the five major parts of the URL and how they may be +inspected and modified. + +[endsect] diff --git a/doc/qbk/3.2.scheme.qbk b/doc/qbk/3.2.scheme.qbk new file mode 100644 index 00000000..667a0d28 --- /dev/null +++ b/doc/qbk/3.2.scheme.qbk @@ -0,0 +1,142 @@ +[/ + Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + Official repository: https://github.com/CPPAlliance/url +] + +[/-----------------------------------------------------------------------------] + +[section Scheme] + +Every URL has a scheme that determines how the rest of +the URL should be interpreted, and each scheme might have +its own rules, such as mandatory components and values. +For instance, the term web address is often used informally +to describe URLs with the `https` scheme, whose semantics +are defined by +[@https://datatracker.ietf.org/doc/html/rfc7230#section-2.7.1 rfc7230]. + +[snippet_components_2a] + +In relative URL references, the scheme is implied by the context. +For instance, HTTP GET request identify resources through relative +references: + +[teletype] +``` + GET /pub/WWW/TheProject.html HTTP/1.1 +``` + +The scheme is implied as `http` or `https`, according to the +protocol being used. + +One of the conventions of the HTTP scheme is that when the port 80 is +implicitly assumed when it is not provided. Such conventions are not +part of the URL protocol. + +The scheme is the top-level component defining the semantics of +the URL. It usually represents a protocol, such as HTTP +or FTP. In these protocols, the path describes a resource +and the host describes how to access it. + +[snippet_components_2b] + +A scheme must start with a letter, and may contain only letters, +digits, plus and minus signs, and periods. It is always followed +by a colon when it appears in a URL. + +Schemes do not necessarily represent protocols. The `file` +scheme is used to identify files from within one's own +computer. + +[teletype] +``` + file:///usr/local/bin/ +``` + +Other schemes use opaque paths that only identify resources. +They usually represent resources through the path. The `mailto` +scheme is used to represent email addresses with the path +component. It is intented to produce hyperlinks that +allow users to send an email to specific addresses: + +[snippet_components_2c] + +The `urn` scheme uses an opaque path to unique identifiers +to a resource. A typical URN namespace is `isbn`, for +International Standard Book Numbers. A book can be identified +as: + +[snippet_components_2d] + +Magnet links, which use the `magnet` scheme, identify files +by their cryptographic hash value. They have empty paths +and use queries to describe the resource. The scheme +allows more fields related to the file, such as a +display name, keywords, and file sources. + +[snippet_components_2e] + +A number of +[@https://www.iana.org/assignments/uri-schemes/uri-schemes.xhtml official URL schemes] +registered with the Internet Assigned Numbers Authority (IANA) have their +own grammars. + +The function [link url.ref.boost__urls__url_view.scheme `scheme`] can +be used to obtain the scheme from a __url_view__: + +[snippet_parsing_scheme_1] + +If the URL has no scheme, this function returns an empty string. To check whether +a URL contains a scheme the function +[link url.ref.boost__urls__url_view.has_scheme `url_view::has_scheme`] might be used. + +The library also defines an enumeration of values for some well-known scheme +identifiers: + +[c++] +[snippet_parsing_scheme_3] + +These may be used instead of their corresponding strings: + +[table Scheme IDs [ + [ID] + [Description] +][ + [[link url.ref.boost__urls__scheme `scheme::ftp`]] + [File Transfer Protocol ("FTP")] +][ + [[link url.ref.boost__urls__scheme `scheme::file`]] + [File URI Scheme] +][ + [[link url.ref.boost__urls__scheme `scheme::http`]] + [Hypertext Transfer Protocol] +][ + [[link url.ref.boost__urls__scheme `scheme::https`]] + [Secure Hypertext Transfer Protocol] +][ + [[link url.ref.boost__urls__scheme `scheme::ws`]] + [WebSocket Protocol] +][ + [[link url.ref.boost__urls__scheme `scheme::wss`]] + [Secure WebSocket Protocol] +]] + +[note + None of these functions throw exceptions. If the URL has no scheme, + [link url.ref.boost__urls__url_view.scheme `scheme`] returns an empty + string. If the function + [link url.ref.boost__urls__url_view.scheme_id `scheme_id`] identifies a valid + but unknown scheme, the value [link url.ref.boost__urls__scheme `scheme::unknown`] + is returned. +] + +[note + Since schemes may contain only letters, digits, plus signs, minus signs, and periods, + there is no distinction in the functions for encoded and decoded schemes. +] + +[endsect] diff --git a/doc/qbk/3.3.authority.qbk b/doc/qbk/3.3.authority.qbk new file mode 100644 index 00000000..55f7d6cd --- /dev/null +++ b/doc/qbk/3.3.authority.qbk @@ -0,0 +1,178 @@ +[/ + Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + Official repository: https://github.com/CPPAlliance/url +] + +[/-----------------------------------------------------------------------------] + +[section Authority] + +The authority determines how a resource can be accessed. +It divides into three subcomponents: + +* The mandatory `host` can be a registered name or an IP address. +* The `port` number preceded by a colon, which can be left out. +* An optional `userinfo` with a username and password. The password can be omitted. + +[$url/images/AuthorityDiagram.svg] + +The function [link url.ref.boost__urls__url_view.authority `authority`] can +be used to obtain the __authority_view__ from a __url_view__: + +[snippet_parsing_authority_3a] + +Notice that [link url.ref.boost__urls__url_view.authority `authority`] +does not return a __pct_encoded_view__. The reason is any decoded character +`/` could make it ambiguous with the path component. The authority +is represented through an __authority_view__, a read-only container +to a non-owning character buffer containing a valid authority. + +An __authority_view__ has functions for obtaining its subcomponents: + +[snippet_parsing_authority_3b] + +These functions do not throw. If the URL has no authority, +[link url.ref.boost__urls__url_view.authority `authority`] +returns an empty __authority_view__. +The function +[link url.ref.boost__urls__url_view.has_authority `has_authority`] +can be used to check whether this empty authority means +there is no authority or an empty authority in the URL. + +In contexts where an authority can appear by itself, an __authority_view__ +can be constructed directly from a string. +For instance, the grammar for the +[@https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.1 ['request-target]] +of an `HTTP/1 CONNECT` request uses +[@https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.3 ['authority-form]]. +This is what such a request looks like: + +[teletype] +``` + CONNECT www.example.com:80 HTTP/1.1 +``` + +In that case, we have an authority that cannot be parsed directly +with __parse_uri__ as a URL. Instead, we can use the analogous function +[link url.ref.boost__urls__parse_authority `parse_authority`] to +obtain an __authority_view__. + +[snippet_parsing_authority_12] + +The authority view provides the subset of observer member functions found in +__url_view__ which are relevant to the authority. However, when an authority +is parsed on its own, the leading double slashes ("//") are not present. + +Authority string with `userinfo` are also valid for +[link url.ref.boost__urls__parse_authority `parse_authority`]: + +[snippet_parsing_authority_13] + +[heading Host] + +The host subcomponent represents where resources +are located. The functions +[link url.ref.boost__urls__url_view.host `host`] +and [link url.ref.boost__urls__url_view.port `port`] +can be used to obtain the host from a __url_view__ +or __authority_view__: + +The host might be a registered name + +[snippet_parsing_authority_8] + +or an IP address + +[snippet_parsing_authority_9] + +Although this is not mandatory, note that the encoded host is rarely +different from its encoded counterpart. + +[snippet_parsing_authority_9b] + +Registered names usually need to be handled differently from IP addresses. +The function +[link url.ref.boost__urls__url_view.host_type `host_type`] +can be used to identify which type of host is described in the URL. + +[c++] +[snippet_parsing_authority_10] + +When the [link url.ref.boost__urls__url_view.host_type `host_type`] +matches an IP address, the functions +[link url.ref.boost__urls__url_view.ipv4_address `ipv4_address`], +[link url.ref.boost__urls__url_view.ipv6_address `ipv6_address`] +can be used to obtain the decoded addresses as integers. + +[note + Note that if an authority is present, the host is always + defined even if it is the empty string (corresponding + to a zero-length ['reg-name] in the BNF). + + [snippet_parsing_authority_10a] +] + +The authority component also influences how we should +interpret the URL path. If the authority is present, +the path component must either be empty or begin with +a slash. This is a common pattern where the path is +empty: + +[snippet_parsing_authority_10b] + +When both the authority and path exist, the path +must begin with a slash: + +[snippet_parsing_authority_10c] + +This rule also affects the path "`/`": + +[snippet_parsing_authority_10d] + +When there is no authority component, the path +cannot begin with an empty segment. This means +the path cannot begin with two slashes `//` to +avoid these characters being interpreted as the +beginning of the authority component. For +instance, consider the following valid URL: + +[snippet_parsing_authority_10d] + +Note that including a double slash would make the +path be interpreted as the authority: + +[snippet_parsing_authority_10f] + +[heading Userinfo] + +In complete authority components, we can also extract +the `userinfo` and `port` subcomponents. + +[snippet_parsing_authority_11a] + +When not treated as an opaque field, the optional +`userinfo` subcomponent consists of a user name +and an optional password. Analogous functions are +provided for the userinfo subcomponents. + +[snippet_parsing_authority_11b] + +Analogous to other observers, the functions +[link url.ref.boost__urls__url_view.has_userinfo `has_userinfo`] and +[link url.ref.boost__urls__url_view.has_password `has_password`] are provided +to differentiate empty components from absent components. +Note that there is no function `has_user`. The user component is available +whenever `userinfo` exists. + +[note Although the specification allows the format `username:password`, +the password component should be used with care. + +It is not recommended to transfer password data through URLs +unless this is an empty string indicating no password.] + + +[endsect] diff --git a/doc/qbk/3.4.path.qbk b/doc/qbk/3.4.path.qbk new file mode 100644 index 00000000..6527997e --- /dev/null +++ b/doc/qbk/3.4.path.qbk @@ -0,0 +1,92 @@ +[/ + Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + Official repository: https://github.com/CPPAlliance/url +] + +[/-----------------------------------------------------------------------------] + +[section Path] + +The path contains data, usually organized hierarchically, which is combined +with the [link section.query query] to identify a resource within the scope of +the scheme and authority. + +If the authority is present, the path needs to be empty or start with a +slash `/`. + +[snippet_parsing_path_use_case_2] + +A URL always contains a path, even if it is empty: + +[snippet_parsing_path_use_case_3] + +The function [link url.ref.boost__urls__url_view.path `path`] +treats this component as an opaque substring. This is useful +in non-hierarchical paths, such as URN identifiers: + +[snippet_parsing_path_3a] + +Most schemes interpret the path as a sequence of slash delimited ['segments]. +These segments can map to file system paths, which is useful for file servers, +but do not always need to imply this relationship. The library +provides container adaptors modeling ranges of individual path segments. +The URL below contains a path with three segments: + +[snippet_parsing_path_0] + +These segment view containers are lightweight references to +the underlying path that map every path to a unique +sequence of segments. + +[warning + Ownership of the string is not + transferred; the caller is responsible for ensuring that the + lifetime of the string extends until the container is destroyed. +] + +In contexts where a path can appear by itself, such as HTTP +requests, segment views may also be constructed directly from +strings. + +[snippet_parsing_path_9] + +The semantics of a path can be absolute or relative. +An absolute path in a URL begins with `/`: + +[snippet_modifying_path_1_2] + +The complete path segments `"."` and `".."` are intended +only for use within relative references +(__rfc3986__ sec. 4.1) and are removed as part of the +reference resolution process (__rfc3986__ sec. 5.2). +Normalizing an absolute URI resolves these dot-segments +(__rfc3986__ sec. 5.2.4). + +[snippet_modifying_path_3] + +Empty segments are also possible, resulting in consecutive slashes. + +[snippet_parsing_path_use_case_6] + +The grammar for URLs places some restrictions on where and +how certain delimiters may appear in the first path segment, +to prevent ambiguities between the scheme, host, and path. +For example, a relative-ref containing a path which is not +absolute, may not have a colon in the first segment. + +When the library detects that a modification to a URL would result +in an ambiguous configuration, it adjusts the result to +maintain the same semantics while avoiding the ambiguity: + +[snippet_modifying_path_9_10] + +This ensures the result is predictable when the user +changes something the path or any segment. + +[/-----------------------------------------------------------------------------] + +[endsect] diff --git a/doc/qbk/3.5.query.qbk b/doc/qbk/3.5.query.qbk new file mode 100644 index 00000000..9e3f55c4 --- /dev/null +++ b/doc/qbk/3.5.query.qbk @@ -0,0 +1,116 @@ +[/ + Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + Official repository: https://github.com/CPPAlliance/url +] + +[/-----------------------------------------------------------------------------] + +[#section.query] +[section:query Query] + +The URL query augments the information in the path to identify a resource +within the scope of the scheme and authority. Unlike the URL path, the +query string always contains non-hierarchical data. + +Although the field is opaque and there is no mandatory syntax for +interpreting queries, its strings are usually interpreted as key-value +parameters delimited by the '&' or ';' character. In contexts where a +query is interpreted as key/value pairs, it is called the +['query parameters], ['query params], or just [*params]. +In addition to interacting with the query as a single string, the +library provides container adaptors modeling ranges of individual +query parameters. + +The URL below contains the query "[teletype]`?id=409&name=Joe&individual`" +with the three parameters "[teletype]`id=409`", "[teletype]`name=Joe`", and +"[teletype]`individual`": + +[snippet_parsing_query_0] + +If the URL has no query, [link url.ref.boost__urls__url_view.query `query`] +returns an empty string. The function +[link url.ref.boost__urls__url_view.has_query `has_query`] +can be used to determine whether this empty string means there is +no query or an empty query string in the URL. + +[snippet_parsing_query_5] + +When using the query string as parameters, note that decoded +query strings might include ambiguous `&` and `=` characters. +In the following example, the decoded query implies there are +two query parameters while there is only one parameter whose +value includes a `&` character. + +[snippet_parsing_query_7] + +The reason the decoded variant of a query is still allowed is +because protocols are also allowed to interpret queries as +opaque strings, in which case the `&` character is not ambiguous. + +When the query string represents parameters, the decoded +parameters can be accessed safely through a parameter view. + +[snippet_parsing_query_1] + +Parameter views are lightweight references to the underlying path string. +Each parameter is represented as a structure with fields to refer to the +key and value. An extra field `has_value` is used to indicate whether +the value is absent. + +[snippet_parsing_query_1a] + +[warning + Ownership of the string is not transferred; the caller is responsible for + ensuring that the lifetime of the string extends until the container is + destroyed. +] + +In addition to accessor functions which treat the query as a single string, +the library provides container adaptors modeling ranges of query parameters. + +Note that a parameter value might be either empty or absent. The +presence of a value is indicated by the presence of an equals ('=') +sign appearing after the key. This means the value may be absent, +empty, or contain characters. + +The key of a query parameter might also be empty. This means that +a query parameter may be completely empty. In this case the +parameter is said to have a zero-length or empty key, and +no value. + +The URL below demonstrates all the ways that keys and values may +appear in query parameters: + +[snippet_parsing_query_8] + +1) The regular key and value pair: + +[snippet_parsing_query_8a] + +2) A key with an empty value: + +[snippet_parsing_query_8b] + +3) A key with no value: + +[snippet_parsing_query_8c] + +4) A key with no value: + +[snippet_parsing_query_8d] + +[note + The URL reserved characters `:`, `@`, `?`, and `/` may appear + unencoded with URL queries, as they are not ambiguous with + other URL components. + + [snippet_parsing_query_9] +] + +[/-----------------------------------------------------------------------------] + +[endsect] diff --git a/doc/qbk/3.6.fragment.qbk b/doc/qbk/3.6.fragment.qbk new file mode 100644 index 00000000..c9a205c9 --- /dev/null +++ b/doc/qbk/3.6.fragment.qbk @@ -0,0 +1,43 @@ +[/ + Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) + + Distributed under the Boost Software License, Version 1.0. (See accompanying + file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + + Official repository: https://github.com/CPPAlliance/url +] + +[/-----------------------------------------------------------------------------] + +[section Fragment] + +The fragment provides a refinement of the resource specification +usually interpreted as a single string. It provides directions +to a secondary resource related to such main resource, such as +the section in an article or a time-point in a video. + +As usual, its semantics vary depending on the scheme, authority, path, +and media type of the resource. In HTML, fragments are used as internal +page references. This usage is called a "named anchor," referring to a +section within a web page. The URL below points to the anchor "section2": + +[snippet_parsing_fragment_4] + +These functions do not throw. The URL fragment might also be empty +or absent. If the URL has no fragment, these functions return an +empty string. The function +[link url.ref.boost__urls__url_view.has_fragment `has_fragment`] +can be used to determine whether this empty string means there is +no fragment or an empty fragment string in the URL. + +[snippet_parsing_fragment_5] + +The URL reserved characters `:`, `@`, `?`, and `/` may appear +unencoded with URL fragments, as they are not ambiguous with +other URL components. + +[snippet_parsing_fragment_6] + +[/-----------------------------------------------------------------------------] + +[endsect] diff --git a/doc/qbk/6.0.grammar.qbk b/doc/qbk/4.0.grammar.qbk similarity index 94% rename from doc/qbk/6.0.grammar.qbk rename to doc/qbk/4.0.grammar.qbk index b851c59c..97fcf34c 100644 --- a/doc/qbk/6.0.grammar.qbk +++ b/doc/qbk/4.0.grammar.qbk @@ -62,10 +62,10 @@ features. [import ../../test/unit/doc_grammar.cpp] -[include 6.1.rules.qbk] -[include 6.2.charset.qbk] -[include 6.3.combinators.qbk] -[include 6.4.range.qbk] -[include 6.5.rfc3986.qbk] +[include 4.1.rules.qbk] +[include 4.2.charset.qbk] +[include 4.3.combinators.qbk] +[include 4.4.range.qbk] +[include 4.5.rfc3986.qbk] [endsect] diff --git a/doc/qbk/4.1.parsing.qbk b/doc/qbk/4.1.parsing.qbk deleted file mode 100644 index 267ee2fc..00000000 --- a/doc/qbk/4.1.parsing.qbk +++ /dev/null @@ -1,278 +0,0 @@ -[/ - Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) - Copyright (c) 2022 Alan de Freitas (vinnie.falco@gmail.com) - - Distributed under the Boost Software License, Version 1.0. (See accompanying - file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - - Official repository: https://github.com/CPPAlliance/url -] - -[#section.parsing] -[#section.url_view] -[section Parsing] - -[#url_notation] -[heading Notation] - -Following the syntax in __rfc3986__, a single algorithm is used for URLs, URIs -and IRIs. When discussing particular grammars, its rules are presented -exactly as it appears in the literature. - -A URL string can be parsed using one of the parsing functions. - -[table Parsing Functions [ - [Function] - [Grammar] - [Example] - [Notes] -][ - [[link url.ref.boost__urls__parse_uri `parse_uri`]] - [[@https://datatracker.ietf.org/doc/html/rfc3986#section-3 ['URI]]] - [[teletype]`http://www.boost.org/index.html?field=value#downloads`] - [Supports fragment `#downloads`] -][ - [[link url.ref.boost__urls__parse_absolute_uri `parse_absolute_uri`]] - [[@https://datatracker.ietf.org/doc/html/rfc3986#section-4.3 ['absolute-URI]]] - [[teletype]`http://www.boost.org/index.html?field=value`] - [Does not support fragment] -][ - [[link url.ref.boost__urls__parse_origin_form `parse_origin_form`]] - [[@https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.1 ['origin-form]]] - [[teletype]`/index.html?field=value`] - [Used in HTTP requests] -][ - [[link url.ref.boost__urls__parse_relative_ref `parse_relative_ref`]] - [[@https://datatracker.ietf.org/doc/html/rfc3986#section-4.2 ['relative-ref]]] - [[teletype]`//www.boost.org/index.html?field=value#downloads`] - [Does not require scheme] -][ - [[link url.ref.boost__urls__parse_uri_reference `parse_uri_reference`]] - [[@https://datatracker.ietf.org/doc/html/rfc3986#section-4.1 ['URI-reference]]] - [[teletype]`http://www.boost.org/index.html`] - [Any `URI` or `relative-ref`] -]] - -The library uses the convention that each function `parse_` operates according -to the particular grammar rule `` specified in __rfc3986__. The document -inherits from [@https://datatracker.ietf.org/doc/html/rfc2396 rfc2396], where there are -no `URL`, `absolute-URL`, `URL-reference` rules. Thus, for consistency, the main parsing -functions also make reference to `uri`s rather than `url`s. - -The collective grammars parsed by these algorithms are specified below. - -[teletype] -``` - absolute-URI = scheme ":" hier-part [ "?" query ] - - relative-ref = relative-part [ "?" query ] [ "#" fragment ] - - URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] - - URI-reference = URI / relative-ref - - hier-part = "//" authority path-abempty - / path-absolute - / path-rootless - / path-empty - - relative-part = "//" authority path-abempty - / path-absolute - / path-noscheme - / path-empty -``` - -[heading Example] - -The following is an example URI and its main components: - -[teletype] -``` - foo://example.com:8042/over/there?name=ferret#nose - \_/ \______________/\_________/ \_________/ \__/ - | | | | | - scheme authority path query fragment -``` - -For the complete specification please refer to __rfc3986__: - -[note - This documentation refers to the Augmented Backus-Naur Form (ABNF) - notation of - [@https://tools.ietf.org/html/rfc2234 rfc2234] - to specify particular grammars used by algorithms and containers. While - a complete understanding of the notation is not a requirement for using the - library, it may help for understanding how valid components of URLs are - defined. In particular, this will be of interest to users who wish to - compose parsing algorithms using the combinators provided by the library. -] - -[heading Functions] - -All parsing functions accept a __string_view__ and return a -`__result__<__url_view__>`. The following example parses a string literal -containing a [@https://datatracker.ietf.org/doc/html/rfc3986#section-3 ['URI]]: - -[c++] -[snippet_parsing_url_1] - -The parsing function refers to the [@https://datatracker.ietf.org/doc/html/rfc3986#section-3 ['URI]] -grammar rule and the result refers to a __url_view__. The convention `parse_` -produces `parse_uri` for the [@https://datatracker.ietf.org/doc/html/rfc3986#section-3 ['URI]] -grammar rule defined in __rfc3986__. However, as the library adheres to -the [link contemporary_view Contemporary View] of URI/URL partitioning -and standardizes on the term "URL", it makes reference to the term "URL" elsewhere. - -When the input does not match the URL grammar, the error is reported through -the `__result__<__url_view__>`. The result is a variant-like object -which holds a __url_view__ or an __error_code__ in the case where the parsing -failed. - -[heading Copying] - -Like a __string_view__, the __url_view__ does not own the underlying - character buffer. Instead, it references the string passed to the - parsing function. The caller is required to ensure that the lifetime -of the string extends until the view is destroyed, or use other containers -such as __url__ and __static_url__. - -The function -[link url.ref.boost__urls__url_view.persist `url_view::persist`] -may also be used to create a copy of the underlying character buffer and attach -ownership of the buffer to a newly returned view, which is wrapped in a -shared pointer. The following code calls `persist` to create a read-only -copy: - -[c++] -[snippet_parsing_url_2] - -The interface of __url_view__ decomposes the URL into its individual parts and -allows for inspection of the various parts as well as returning metadata about -the URL itself. All the non-modifying observer operations are described in the -sections that follow. - -[table [[Code][Output]] [[ -[c++] -[snippet_accessing_1] -][ -[teletype] -``` - - - url : https://user:pass@example.com:443/path/to/my%2dfile.txt?id=42&name=John%20Doe+Jingleheimer%2DSchmidt#page%20anchor - scheme : https - authority : user:pass@example.com:443 - userinfo : user:pass - user : user - password : pass - host : example.com - port : 443 - path : /path/to/my-file.txt - query : id=42&name=John Doe Jingleheimer-Schmidt - fragment : page anchor -``` -]]] - -To create a mutable copy of the __url_view__, one can create a __url__ -or __static_url__: - -[c++] -[snippet_parsing_url_3] - -[heading Return Type] - -In many places, functions in the library have a return type which uses the -__result__ alias template. This class allows the parsing algorithms to -report errors without referring to exceptions. - -The functions `result::has_value` and `result::has_error` can be used to -check if the result contains an error. - -[snippet_parsing_url_1] - -This ensures `result::value` will not throw an error. In contexts where -it is acceptable to throw errors, `result::value` can be used directly. - -Check the reference for __result__ for a synopsis of the type. For complete -information please consult the full -[@boost:/libs/system/doc/html/system.html#ref_resultt_e `result`] -documentation in [@boost:/libs/system/doc/html/system.html Boost.System]. - -[heading Summary] - -[table [[Component][Decoded][Encoded][Check]] -[ - [authority] - [] - [[link url.ref.boost__urls__url_view.encoded_authority `encoded_authority`]] - [[link url.ref.boost__urls__url_view.has_authority `has_authority`]]] - -[ - [fragment] - [[link url.ref.boost__urls__url_view.fragment `fragment`]] - [[link url.ref.boost__urls__url_view.encoded_fragment `encoded_fragment`]] - [[link url.ref.boost__urls__url_view.has_fragment `has_fragment`]] -] -[ - [host] - [[link url.ref.boost__urls__url_view.host `host`]] - [[link url.ref.boost__urls__url_view.encoded_host `encoded_host`]] - [] -] -[ - [host_and_port] - [] - [[link url.ref.boost__urls__url_view.encoded_host_and_port `encoded_host_and_port`]] - [] -] -[ - [origin] - [] - [[link url.ref.boost__urls__url_view.encoded_origin `encoded_origin`]] - [] -] -[ - [params] - [[link url.ref.boost__urls__url_view.params `params`]] - [[link url.ref.boost__urls__url_view.encoded_params `encoded_params`]] - [] -] -[ - [password] - [[link url.ref.boost__urls__url_view.password `password`]] - [[link url.ref.boost__urls__url_view.encoded_password `encoded_password`]] - [[link url.ref.boost__urls__url_view.has_password `has_password`]] -] -[ - [path] - [] - [[link url.ref.boost__urls__url_view.encoded_path `encoded_path`]] - [] -] -[ - [query] - [[link url.ref.boost__urls__url_view.query `query`]] - [[link url.ref.boost__urls__url_view.encoded_query `encoded_query`]] - [[link url.ref.boost__urls__url_view.has_query `has_query`]] -] -[ - [segments] - [[link url.ref.boost__urls__url_view.segments `segments`]] - [[link url.ref.boost__urls__url_view.encoded_segments `encoded_segments`]] - [] -] -[ - [user] - [[link url.ref.boost__urls__url_view.user `user`]] - [[link url.ref.boost__urls__url_view.encoded_user `encoded_user`]] - [] -] -[ - [userinfo] - [[link url.ref.boost__urls__url_view.userinfo `userinfo`]] - [[link url.ref.boost__urls__url_view.encoded_userinfo `encoded_userinfo`]] - [[link url.ref.boost__urls__url_view.has_userinfo `has_userinfo`]] -] -] - -[endsect] diff --git a/doc/qbk/6.1.rules.qbk b/doc/qbk/4.1.rules.qbk similarity index 100% rename from doc/qbk/6.1.rules.qbk rename to doc/qbk/4.1.rules.qbk diff --git a/doc/qbk/6.2.charset.qbk b/doc/qbk/4.2.charset.qbk similarity index 100% rename from doc/qbk/6.2.charset.qbk rename to doc/qbk/4.2.charset.qbk diff --git a/doc/qbk/4.2.modifying.qbk b/doc/qbk/4.2.modifying.qbk deleted file mode 100644 index 57767b71..00000000 --- a/doc/qbk/4.2.modifying.qbk +++ /dev/null @@ -1,132 +0,0 @@ -[/ - Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) - Copyright (c) 2022 Alan de Freitas (alandefreitas@gmail.com) - - Distributed under the Boost Software License, Version 1.0. (See accompanying - file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - - Official repository: https://github.com/CPPAlliance/url -] - -[section Modifying] - -[heading Constructing Containers] - -The class __url__ is a container used to store and produce URLs. -The [link section.url_view URL parsing] functions can be used to create -a new container from a __url_view__: - -[snippet_modifying_1] - -All __url_view__ observers are also available for a __url__: - -[snippet_modifying_2] - -The interface of __url_view__ decomposes the URL into its individual parts and -allows for inspection of the various parts as well as returning metadata about -the URL itself. - -[heading Modifiers] - -The decoded variant of the modifier functions will encode any -characters that would be invalid for the specified component. - -[table [[Code][Output]] [[ -[c++] -[snippet_modifying_5] -][ -[teletype] -``` - http://www.my%20example.com -``` -]][[ -[c++] -[snippet_modifying_3] -][ -[teletype] -``` - https://my%20website.com/my%20file.txt?id=42&name=John%20Doe -``` -]]] - -[heading Encoded Modifiers] - -The encoded variant of the modifier functions require that the -encoded strings are valid for the specified component. The -functions will throw if the input string contains any character -invalid for the specified component. - -[table [[Code][Output]] [[ -[c++] -[snippet_modifying_4] -][ -[teletype] -``` - http://www.example.com -``` -]]] - -[heading Summary] - -For each observer function in __url_view__, an instance of __url__ provides a -corresponding `set` function to define the value of the specified component. - -[table [[Component][Decoded][Encoded]] -[ - [authority] - [] - [[link url.ref.boost__urls__url.set_encoded_authority `set_encoded_authority`]] -] -[ - [fragment] - [[link url.ref.boost__urls__url.set_fragment `set_fragment`]] - [[link url.ref.boost__urls__url.set_encoded_fragment `set_encoded_fragment`]] -] -[ - [host] - [[link url.ref.boost__urls__url.set_host `set_host`]] - [[link url.ref.boost__urls__url.set_encoded_host `set_encoded_host`]] -] -[ - [password] - [[link url.ref.boost__urls__url.set_password `set_password`]] - [[link url.ref.boost__urls__url.set_encoded_password `set_encoded_password`]] -] -[ - [path] - [[link url.ref.boost__urls__url.set_path `set_path`]] - [[link url.ref.boost__urls__url.set_encoded_path `set_encoded_path`]] -] -[ - [path_absolute] - [[link url.ref.boost__urls__url.set_path_absolute `set_path_absolute`]] - [[link url.ref.boost__urls__url.set_path_absolute `set_path_absolute`]] -] -[ - [port] - [[link url.ref.boost__urls__url.set_port `set_port`]] - [[link url.ref.boost__urls__url.set_port `set_port`]] -] -[ - [query] - [[link url.ref.boost__urls__url.set_query `set_query`]] - [[link url.ref.boost__urls__url.set_encoded_query `set_encoded_query`]] -] -[ - [scheme] - [[link url.ref.boost__urls__url.set_scheme `set_scheme`]] - [[link url.ref.boost__urls__url.set_scheme `set_scheme`]] -] -[ - [user] - [[link url.ref.boost__urls__url.set_user `set_user`]] - [[link url.ref.boost__urls__url.set_encoded_user `set_encoded_user`]] -] -[ - [userinfo] - [[link url.ref.boost__urls__url.set_userinfo `set_userinfo`]] - [[link url.ref.boost__urls__url.set_encoded_userinfo `set_encoded_userinfo`]] -] -] - -[endsect] \ No newline at end of file diff --git a/doc/qbk/6.3.combinators.qbk b/doc/qbk/4.3.combinators.qbk similarity index 100% rename from doc/qbk/6.3.combinators.qbk rename to doc/qbk/4.3.combinators.qbk diff --git a/doc/qbk/6.4.range.qbk b/doc/qbk/4.4.range.qbk similarity index 100% rename from doc/qbk/6.4.range.qbk rename to doc/qbk/4.4.range.qbk diff --git a/doc/qbk/6.5.rfc3986.qbk b/doc/qbk/4.5.rfc3986.qbk similarity index 100% rename from doc/qbk/6.5.rfc3986.qbk rename to doc/qbk/4.5.rfc3986.qbk diff --git a/doc/qbk/7.0.concepts.qbk b/doc/qbk/5.0.concepts.qbk similarity index 82% rename from doc/qbk/7.0.concepts.qbk rename to doc/qbk/5.0.concepts.qbk index e932b2f5..525ee38c 100644 --- a/doc/qbk/7.0.concepts.qbk +++ b/doc/qbk/5.0.concepts.qbk @@ -11,8 +11,8 @@ This section describes all of the concepts defined by the library. -[include 7.1.CharSet.qbk] -[include 7.1.MutableString.qbk] -[include 7.1.Rule.qbk] +[include 5.1.CharSet.qbk] +[include 5.2.MutableString.qbk] +[include 5.3.Rule.qbk] [endsect] diff --git a/doc/qbk/7.1.CharSet.qbk b/doc/qbk/5.1.CharSet.qbk similarity index 100% rename from doc/qbk/7.1.CharSet.qbk rename to doc/qbk/5.1.CharSet.qbk diff --git a/doc/qbk/5.1.scheme.qbk b/doc/qbk/5.1.scheme.qbk deleted file mode 100644 index 5969a974..00000000 --- a/doc/qbk/5.1.scheme.qbk +++ /dev/null @@ -1,267 +0,0 @@ -[/ - Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) - - Distributed under the Boost Software License, Version 1.0. (See accompanying - file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - - Official repository: https://github.com/CPPAlliance/url -] - -[/-----------------------------------------------------------------------------] - -[section Scheme] - -[heading Notation] - -The scheme is the top-level hierarchical element which defines the -syntax and semantics of the rest of the URL. The scheme identifier -is always followed by a colon when it appears in a URL. - -Here are some examples of URLs with the schemes `https` and `file`: - -[teletype] -``` - https://www.example.com/path/to/file.txt?page=2 -``` - -``` - file:///usr/local/bin/ -``` - -A scheme must start with a letter, and may contain only letters, -digits, plus and minus signs, and periods: - -[table Scheme BNF [[ -[teletype] -``` - scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) - - absolute-URI = scheme ":" hier-part [ "?" query ] - - URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] -``` -]]] - -[heading Observers] - -The function [link url.ref.boost__urls__url_view.scheme `scheme`] can -be used to obtain the scheme from a __url_view__: - -[table [[Code][Output]] [[ -[c++] -[snippet_parsing_scheme_1] -][ -[teletype] -``` - mailto -``` -]]] - -If the URL has no scheme, this function returns an empty string. To check whether -a URL contains a scheme the function -[link url.ref.boost__urls__url_view.has_scheme `url_view::has_scheme`] might be used. - -[table [[Code][Output]] [[ -[c++] -[snippet_parsing_scheme_2] -][ -[teletype] -``` - mailto -``` -]]] - -[heading Common schemes] - -The library defines an enumeration of values for some well-known scheme -identifiers. - -[c++] -[snippet_parsing_scheme_3] - -These may be used instead of their corresponding strings: - -[table Scheme IDs [ - [ID] - [Description] -][ - [[link url.ref.boost__urls__scheme `scheme::none`]] - [Indicates no scheme present] -][ - [[link url.ref.boost__urls__scheme `scheme::unknown`]] - [A valid but unknown scheme] -][ - [[link url.ref.boost__urls__scheme `scheme::ftp`]] - [File Transfer Protocol ("FTP")] -][ - [[link url.ref.boost__urls__scheme `scheme::file`]] - [File URI Scheme] -][ - [[link url.ref.boost__urls__scheme `scheme::http`]] - [Hypertext Transfer Protocol] -][ - [[link url.ref.boost__urls__scheme `scheme::https`]] - [Secure Hypertext Transfer Protocol] -][ - [[link url.ref.boost__urls__scheme `scheme::ws`]] - [WebSocket Protocol] -][ - [[link url.ref.boost__urls__scheme `scheme::wss`]] - [Secure WebSocket Protocol] -]] - - -[heading Use Cases] - -A number of schemes are used to define the semantics of URLs. For instance, -the term web address is often used informally to describe URLs with the -`http` scheme, whose semantics are defined by -[@https://datatracker.ietf.org/doc/html/rfc2616#section-3.2.2 rfc3986]. -One of the conventions of the HTTP scheme is that when the port 80 is -implicitly assumed when it is not provided. Such conventions are not -part of the URL protocol. - -Schemes are also different from protocols. Although the scheme `http` is -used to interact with resources via the HTTP protocol, the scheme `file` -has no corresponding protocol. - -Some noteworthy IANA-registered schemes are - -[table Scheme IDs [ - [Scheme] - [Resource] -][ - [[@https://tools.ietf.org/html/rfc2392 `cid`]] - [SMTP/MIME messages] -][ - [[@https://tools.ietf.org/html/rfc2397 `data`]] - [Inline data] -][ - [[@https://tools.ietf.org/html/rfc4918 `dav`]] - [WebDAV] -][ - [[@https://tools.ietf.org/html/rfc4501 `dns`]] - [Domain Name System] -][ - [[@https://tools.ietf.org/html/rfc8089 `file`]] - [File systems] -][ - [[@https://tools.ietf.org/html/rfc1738 `ftp`]] - [FTP resources] -][ - [[@https://www.iana.org/assignments/uri-schemes/prov/git `git`]] - [GIT repository] -][ - [[@https://tools.ietf.org/html/rfc7230 `http`]] - [HTTP resources] -][ - [[@https://tools.ietf.org/html/rfc7230 `https`]] - [HTTP secured using SSL/TLS] -][ - [[@https://tools.ietf.org/html/rfc6068 `mailto`]] - [SMTP email addresses] -][ - [[@https://www.bittorrent.org/beps/bep_0009.html `magnet`]] - [Identify files by content] -][ - [[@https://tools.ietf.org/html/rfc2224 `nfs`]] - [Network File System] -][ - [[@https://tools.ietf.org/html/rfc2384 `pop`]] - [POP3] -][ - [[@https://docs.aws.amazon.com/cli/latest/reference/s3/ `s3`]] - [Amazon S3] -][ - [[@https://tools.ietf.org/html/rfc5724 `sms`]] - [SMS messages] -][ - [[@https://www.iana.org/assignments/uri-schemes/prov/svn `svn`]] - [Subversion (SVN) repository] -][ - [[@https://tools.ietf.org/html/rfc2806 `tel`]] - [Telephone number] -][ - [[@https://www.iana.org/assignments/uri-schemes/prov/udp `udp`]] - [Streaming protocols over UDP] -][ - [[@https://tools.ietf.org/html/rfc2141 `urn`]] - [Uniform Resource Names] -][ - [[@https://tools.ietf.org/html/rfc6455 `ws`]] - [WebSocket Protocol] -][ - [[@https://tools.ietf.org/html/rfc6455 `wss`]] - [Secure WebSocket Protocol] -]] - -Many other valid but unofficial schemes are common: - -[table Scheme IDs [ - [Scheme] - [Resource] -][ - [[@http://tools.ietf.org/html/draft-paskin-doi-uri `doi`]] - [Digital Object Identifier] -][ - [[@https://datatracker.ietf.org/doc/html/draft-hoehrmann-javascript-scheme `javascript`]] - [Javascript Code] -][ - [[@https://datatracker.ietf.org/doc/html/draft-patrick-lambert-odbc-uri-scheme `odbc`]] - [Open Database Connectivity] -][ - [[@https://api.slack.com/reference/deep-linking `slack`]] - [Slack Client] -]] - -[/-----------------------------------------------------------------------------] - -[heading Member Functions] - -The functions for inspecting the scheme in a __url_view__ are as follows: - -[table Scheme Observers [ - [Function] - [Description] -][ - [[link url.ref.boost__urls__url_view.has_scheme `has_scheme`]] - [Return true if a scheme is present] -][ - [[link url.ref.boost__urls__url_view.scheme `scheme`]] - [Return the scheme as a string] -][ - [[link url.ref.boost__urls__url_view.scheme_id `scheme_id`]] - [Return the scheme as a known-scheme enumeration constant] -]] - -[note - None of these functions throw exceptions. If the URL has no scheme, - [link url.ref.boost__urls__url_view.scheme `scheme`] returns an empty - string. If the function - [link url.ref.boost__urls__url_view.scheme_id `scheme_id`] identifies a valid - but unknown scheme, the value [link url.ref.boost__urls__scheme `scheme::unknown`] - is returned. -] - -The functions for modifying the scheme in a __url__ are as follows: - -[table Scheme Modifiers [ - [Function] - [Description] -][ - [[link url.ref.boost__urls__url.set_scheme `set_scheme`]] - [Set the scheme] -][ - [[link url.ref.boost__urls__url.remove_scheme `remove_scheme`]] - [Set the scheme] -][ - [[link url.ref.boost__urls__url.normalize_scheme `normalize_scheme`]] - [Set the scheme] -]] - -[note - Since schemes may contain only letters, digits, plus signs, minus signs, and periods, - there is no distinction in the functions for encoded and decoded schemes. -] - -[endsect] diff --git a/doc/qbk/7.1.MutableString.qbk b/doc/qbk/5.2.MutableString.qbk similarity index 100% rename from doc/qbk/7.1.MutableString.qbk rename to doc/qbk/5.2.MutableString.qbk diff --git a/doc/qbk/5.2.authority.qbk b/doc/qbk/5.2.authority.qbk deleted file mode 100644 index 561ea6bb..00000000 --- a/doc/qbk/5.2.authority.qbk +++ /dev/null @@ -1,580 +0,0 @@ -[/ - Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) - - Distributed under the Boost Software License, Version 1.0. (See accompanying - file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - - Official repository: https://github.com/CPPAlliance/url -] - -[/-----------------------------------------------------------------------------] - -[section Authority] - -[heading Notation] - -The authority is a hierarchical element which names an entity governing -the namespace defined by the remainder of the URL. It divides into -three subcomponents: - -[teletype] -``` - authority = [userinfo "@"] host [":" port] -``` - -* The `host` subcomponent of the authority can be a registered name or an IP address. -* The optional `port` number subcomponent is preceded by a colon ":" -* The optional `userinfo` subcomponent consists of a username and an optional password - -In a URL, the authority component is always preceded by a double slash ("//"). - -[table Authority BNF [ - [ - [teletype] - ``` - authority = [ userinfo "@" ] host [ ":" port ] - - userinfo = user [ ":" [ password ] ] - - host = IP-literal / IPv4address / reg-name - - port = *DIGIT - - user = *( unreserved / pct-encoded / sub-delims ) - password = *( unreserved / pct-encoded / sub-delims / ":" ) - - IP-literal = "[" ( IPv6address / IPvFuture ) "]" - - reg-name = *( unreserved / pct-encoded / "-" / ".") - ``` - ] -]] - -[heading Observers] - -The function [link url.ref.boost__urls__url_view.authority `authority`] can -be used to obtain the authority from a __url_view__: - -[table [[Code][Output]] [[ -[c++] -[snippet_parsing_authority_3] -][ -[teletype] -``` - https://www.boost.org/users/download/ - scheme: https - has authority: 1 - authority: www.boost.org - path: /users/download/ -``` -]]] - -These functions do not throw. If the URL has no authority, -[link url.ref.boost__urls__url_view.authority `authority`] -returns an empty __authority_view__. - -The function [link url.ref.boost__urls__url_view.has_authority `has_authority`] -can be used to check whether this empty authority means there is no authority -or an empty authority in the URL. - -[table [[Code][Output]] [[ -[c++] -[snippet_parsing_authority_1] -][ -[teletype] -``` - https:///path/to_resource - scheme: https - has authority: 1 - authority: - path: /path/to_resource -``` -]] -[[ -[c++] -[snippet_parsing_authority_6] -][ -[teletype] -``` - mailto://John.Doe@example.com - scheme: mailto - has authority: 1 - authority: John.Doe@example.com - path: -``` -]]] - -Notice that the decoded counterpart of -[link url.ref.boost__urls__url_view.encoded_authority `encoded_authority`] -does not return a __pct_encoded_view__. The reason is any decoded character -`/` could make it ambiguous with the path component so the authority -is represented through an __authority_view__. - -[heading Host] - -The host subcomponent represents where resources -are located. The functions -[link url.ref.boost__urls__url_view.host `host`] -and [link url.ref.boost__urls__url_view.encoded_host `encoded_host`] -can be used to obtain the host from a __url_view__, while -[link url.ref.boost__urls__url_view.encoded_host_and_port `encoded_host_and_port`] -allows us to directly obtain the host with the corresponding port number. - -The host might be a registered name - -[table [[Code][Output]] [[ -[c++] -[snippet_parsing_authority_8] -][ -[teletype] -``` - https://john.doe@www.example.com:123/forum/questions/ - encoded host: www.example.com - host: www.example.com - host and port: www.example.com:123 - port: 123 - port number: 123 -``` -]]] - -or an IP address - -[table [[Code][Output]] [[ -[c++] -[snippet_parsing_authority_9] -][ -[teletype] -``` - https://john.doe@192.168.2.1:123/forum/questions/ - encoded host: 192.168.2.1 - host: 192.168.2.1 - host and port: 192.168.2.1:123 - port: 123 - port number: 123 -``` -]]] - -Although this is not mandatory, note that the encoded host is rarely -different from its encoded counterpart. -The function [link url.ref.boost__urls__url_view.port_number `port_number`] -returns the decoded port as an integer. - -Registered names usually need to be handled differently from IP addresses. -The function -[link url.ref.boost__urls__url_view.host_type `host_type`] -can be used to identify which type of host is described in the URL. - -[c++] -[snippet_parsing_authority_10] - -When the [link url.ref.boost__urls__url_view.host_type `host_type`] -matches an IP address, the functions -[link url.ref.boost__urls__url_view.ipv4_address `ipv4_address`], -[link url.ref.boost__urls__url_view.ipv6_address `ipv6_address`] -can be used to obtain the decoded addresses as integers. - -[heading Userinfo] - -The optional `userinfo` subcomponent consists of a user name and -an optional password. The function -[link url.ref.boost__urls__url_view.encoded_userinfo `encoded_userinfo`] -can be used to retrieve the userinfo from a __url_view__. Analogous -functions are provided for the userinfo subcomponents. - -[table [[Code][Output]] [[ -[c++] -[snippet_parsing_authority_11] -][ -[teletype] -``` - https://john.doe:123456@www.somehost.com/forum/questions/ - - has_userinfo: 1 - userinfo: john.doe:123456 - user: john.doe - - has_password: 1 - password: 123456 -``` -]]] - -Analogous to other observers, the functions -[link url.ref.boost__urls__url_view.has_userinfo `has_userinfo`] and -[link url.ref.boost__urls__url_view.has_password `has_password`] are provided -to differentiate empty components from absent components. - -Note that there is no function `has_user`. The user component is available -whenever `userinfo` exists. - -[note Although the specification allows the format `username:password`, -the password component should be used with care. - -It is not recommended to transfer password data through URLs -unless this is an empty string indicating no password.] - -[heading Authority View] - -In contexts where an authority can appear by itself, the library provides the -__authority_view__, a read-only container to a non-owning character buffer -containing a valid authority. - -As an example, the grammar for the -[@https://datatracker.ietf.org/doc/html/rfc7230#section-3.1.1 ['request-target]] -of an HTTP/1 CONNECT request uses -[@https://datatracker.ietf.org/doc/html/rfc7230#section-5.3.3 ['authority-form]]. -This is what such a request looks like: - -[teletype] -``` - CONNECT www.example.com:80 HTTP/1.1 -``` - -In that case, we have an authority that cannot be parsed directly -with __parse_uri__ as a URL. Instead, we can use the analogous function -[link url.ref.boost__urls__parse_authority `parse_authority`] to -obtain an __authority_view__. - -[table [[Code][Output]] [[ -[c++] -[snippet_parsing_authority_12] -][ -[teletype] -``` - www.example.com:80 - - host_and_port: www.example.com:80 - host: www.example.com - port: 80 - port number: 80 - - has_userinfo: 0 - userinfo: - user: - - has_password: 0 - password: -``` -]]] - -The authority view provides the subset of observer member functions found in -__url_view__ which are relevant to the authority. However, when an authority -is parsed on its own, the leading double slashes ("//") are not present. - -The following authority string is also valid for -[link url.ref.boost__urls__parse_authority `parse_authority`]: - -[teletype] -``` - user:pass@www.example.com:443 -``` - -[table [[Code][Output]] [[ -[c++] -[snippet_parsing_authority_13] -][ -[teletype] -``` - user:pass@www.example.com:443 - - encoded_host_and_port: www.example.com:443 - host: www.example.com - port: 443 - port number: 443 - - has_userinfo: 1 - userinfo: user:pass - - user: user - - has_password: 1 - password: pass -``` -]]] - - -[heading Use Cases] - -Note that if an authority is present, the host is always defined even if it -is the empty string (corresponding to a zero-length ['reg-name] in the BNF). - -[teletype] -``` - https:///path/to_resource - \____/\/\_______________/ - | | | -scheme authority path -``` - -[table - [[Component] [Value] ] - [[URL] [`https:///path/to_resource`] ] - [[Scheme] [`https`] ] - [[Has authority] [Yes] ] - [[Authority] [] ] - [[Path] [`/path/to_resource`] ] -] - -The authority component also influences how we should interpret the URL path. -If the authority is present, the path component must either be empty or begin -with a slash. - -This is a common pattern where the path is empty: - -[teletype] -``` - https://www.boost.org - \___/ \___________/ - scheme authority (path is empty) -``` - -[table - [[Component] [Value] ] - [[URL] [`https://www.boost.org`] ] - [[Scheme] [`https`] ] - [[Has authority] [Yes] ] - [[Authority] [`www.boost.org`] ] - [[Path] [] ] -] - -When both the authority and path exist, the path needs to begin with a slash: - -[teletype] -``` - https://www.boost.org/users/download/ - \___/ \___________/\______________/ - scheme authority path (begins with a slash) -``` - -[table - [[Component] [Value] ] - [[URL] [`https://www.boost.org/users/download/`] ] - [[Scheme] [`https`] ] - [[Has authority] [Yes] ] - [[Authority] [`www.boost.org`] ] - [[Path] [`/users/download/`] ] -] - -This rule also affects the path "`/`": - -[teletype] -``` - https://www.boost.org/ - \___/ \___________/\/ - scheme authority path (begins with a slash) -``` - -[table - [[Component] [Value] ] - [[URL] [`https://www.boost.org/`] ] - [[Scheme] [`https`] ] - [[Has authority] [Yes] ] - [[Authority] [`www.boost.org`] ] - [[Path] [`/`] ] -] - -When there is no authority component, the path cannot begin with an empty -segment. This means the path cannot begin with two slashes `//` to avoid these -characters being interpreted as the beginning of the authority component. - -For instance, consider the following valid URL: - -[teletype] -``` - mailto:John.Doe@example.com - \____/ \__________________/ - scheme path -``` - -[table - [[Component] [Value] ] - [[URL] [`mailto:John.Doe@example.com`] ] - [[Scheme] [`mailto`] ] - [[Has authority] [No] ] - [[Authority] [] ] - [[Path] [`John.Doe@example.com`] ] -] - -Note how including a double slash would make the path be interpreted as the authority: - -[teletype] -``` - mailto://John.Doe@example.com - \____/ \____________________/ - scheme authority -``` - -[table - [[Component] [Value] ] - [[URL] [`mailto://John.Doe@example.com`] ] - [[Scheme] [`mailto`] ] - [[Has authority] [Yes] ] - [[Authority] [`John.Doe@example.com`] ] - [[Path] [] ] -] - -In complete authority components, we can also extract the `userinfo` and `port` subcomponents. - -[teletype] -``` - userinfo host port - /------\ /-------------\ /-\ - https://john.doe@www.example.com:123/forum/questions/ - \___/ \__________________________/\_______________/ - scheme authority path -``` - -[table - [[Component] [Value] ] - [[URL] [`https://john.doe@www.example.com:123/forum/questions/`] ] - [[Scheme] [`https`] ] - [[Has authority] [Yes] ] - [[Authority] [`john.doe@www.example.com:123`] ] - [[Host] [`www.example.com`] ] - [[Userinfo] [`john.doe`] ] - [[Port] [`123`] ] - [[Path] [`/forum/questions/`] ] -] - -[heading Member Functions] - -The functions for inspecting all or part of the authority in a -__url_view__ are as follows: - -[table Userinfo Observers [ - [Function] - [Description] -][ - [[link url.ref.boost__urls__url_view.has_password `has_password`]] - [Return true if an password is present.] -][ - [[link url.ref.boost__urls__url_view.has_userinfo `has_userinfo`]] - [Return true if a userinfo is present.] -][ - [[link url.ref.boost__urls__url_view.encoded_password `encoded_password`]] - [Return the password as a percent-encoded string.] -][ - [[link url.ref.boost__urls__url_view.encoded_user `encoded_user`]] - [Return the user as a percent-encoded string.] -][ - [[link url.ref.boost__urls__url_view.encoded_userinfo `encoded_userinfo`]] - [Return the userinfo as a percent-encoded string.] -][ - [[link url.ref.boost__urls__url_view.password `password`]] - [Return the password as a string with percent-decoding applied.] -][ - [[link url.ref.boost__urls__url_view.user `user`]] - [Return the user as a string with percent-decoding applied.] -][ - [[link url.ref.boost__urls__url_view.userinfo `userinfo`]] - [Return the userinfo as a string with percent-decoding applied.] -]] - - -[table Host Observers [ - [Function] - [Description] -][ - [[link url.ref.boost__urls__url_view.encoded_host `encoded_host`]] - [Return the host as a percent-encoded string.] -][ - [[link url.ref.boost__urls__url_view.encoded_host_and_port `encoded_host_and_port`]] - [Return the host and port as a percent-encoded string.] -][ - [[link url.ref.boost__urls__url_view.has_port `has_port`]] - [Return true if an port is present.] -][ - [[link url.ref.boost__urls__url_view.host `host`]] - [Return the type of host specified, if any.] -][ - [[link url.ref.boost__urls__url_view.ipv4_address `ipv4_address`]] - [Return the IPv4 address of the host, if applicable.] -][ - [[link url.ref.boost__urls__url_view.ipv6_address `ipv6_address`]] - [Return the IPv6 address of the host, if applicable.] -][ - [[link url.ref.boost__urls__url_view.ipvfuture `ipvfuture`]] - [Return the IPvFuture address of the host, if applicable.] -][ - [[link url.ref.boost__urls__url_view.port `port`]] - [Return the port string of the host, if applicable.] -][ - [[link url.ref.boost__urls__url_view.port_number `port_number`]] - [Return the port number of the host, if applicable.] -]] - -[table Authority Observers [ - [Function] - [Description] -][ - [[link url.ref.boost__urls__url_view.has_authority `has_authority`]] - [Return true if an authority is present.] -][ - [[link url.ref.boost__urls__url_view.encoded_authority `encoded_authority`]] - [Return the authority as a percent-encoded string.] -]] - -The functions for modifying all or part of the authority in a -__url__ are as follows: - -[table Userinfo Modifiers [ - [Function] - [Description] -][ - [[link url.ref.boost__urls__url.set_userinfo `set_userinfo`]] - [Set the userinfo.] -][ - [[link url.ref.boost__urls__url.set_encoded_userinfo `set_encoded_userinfo`]] - [Set the encoded userinfo.] -][ - [[link url.ref.boost__urls__url.remove_userinfo `remove_userinfo`]] - [Remove the userinfo.] -][ - [[link url.ref.boost__urls__url.set_user `set_user`]] - [Set the user.] -][ - [[link url.ref.boost__urls__url.set_encoded_user `set_encoded_user`]] - [Set the encoded user.] -][ - [[link url.ref.boost__urls__url.set_password `set_password`]] - [Set the password.] -][ - [[link url.ref.boost__urls__url.set_encoded_password `set_encoded_password`]] - [Set the encoded password.] -][ - [[link url.ref.boost__urls__url.remove_password `remove_password`]] - [Remove the password.] -]] - - -[table Host Modifiers [ - [Function] - [Description] -][ - [[link url.ref.boost__urls__url.set_host `set_host`]] - [Set the host.] -][ - [[link url.ref.boost__urls__url.set_encoded_host `set_encoded_host`]] - [Set the encoded host.] -][ - [[link url.ref.boost__urls__url.set_port `set_port`]] - [Set the port.] -][ - [[link url.ref.boost__urls__url.remove_port `remove_port`]] - [Remove the port.] -]] - -[table Authority Modifiers [ - [Function] - [Description] -][ - [[link url.ref.boost__urls__url.set_encoded_authority `set_encoded_authority`]] - [Set the encoded authority.] -][ - [[link url.ref.boost__urls__url.remove_authority `remove_authority`]] - [Remove the authority.] -][ - [[link url.ref.boost__urls__url.normalize_authority `normalize_authority`]] - [Normalize the authority.] -]] - -[endsect] diff --git a/doc/qbk/7.1.Rule.qbk b/doc/qbk/5.3.Rule.qbk similarity index 100% rename from doc/qbk/7.1.Rule.qbk rename to doc/qbk/5.3.Rule.qbk diff --git a/doc/qbk/5.3.path.qbk b/doc/qbk/5.3.path.qbk deleted file mode 100644 index 9238bae9..00000000 --- a/doc/qbk/5.3.path.qbk +++ /dev/null @@ -1,396 +0,0 @@ -[/ - Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) - - Distributed under the Boost Software License, Version 1.0. (See accompanying - file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - - Official repository: https://github.com/CPPAlliance/url -] - -[/-----------------------------------------------------------------------------] - -[section Path] - -[heading Notation] - -The path contains data, usually organized hierarchically, which is combined -with the [link section.query query] to identify a resource within the scope of -the scheme and authority. - -Most schemes interpret the path as a sequence of slash delimited ['segments]. -These segments can map to file system paths, which is useful for file servers, -but do not always need to imply this relationship. - -In addition to interacting with the path as a single string, the library -provides container adaptors modeling ranges of individual path segments. - -The URL below contains a path `/path/to/file.txt` with the three segments -`path`, `to`, and `file.txt`: - -[teletype] -``` - http://www.example.com/path/to/file.txt -``` - -Depending on the type of URL, there are various syntactic rules for how the -path may be formulated in a URL. The BNF for these formulations is defined: - -[table Path BNF [[ -[teletype] -``` - path = path-abempty ; begins with "/" or is empty - / path-absolute ; begins with "/" but not "//" - / path-noscheme ; begins with a non-colon segment - / path-rootless ; begins with a segment - / path-empty ; zero characters - - path-abempty = *( "/" segment ) - path-absolute = "/" [ segment-nz *( "/" segment ) ] - path-noscheme = segment-nz-nc *( "/" segment ) - path-rootless = segment-nz *( "/" segment ) - path-empty = 0 -``` -]]] - -[heading Observers] - -The functions [link url.ref.boost__urls__url_view.path `path`] and -[link url.ref.boost__urls__url_view.encoded_path `encoded_path`] can -be used to obtain the path from a __url_view__: - -[table [[Code][Output]] [[ -[c++] -[snippet_parsing_path_1] -][ -[teletype] -``` - https://www.boost.org/doc/libs/ - path: /doc/libs/ - encoded_path: /doc/libs/ - segments: /doc/libs/ - encoded segments: /doc/libs/ -``` -]]] - -These functions do not throw. There is no function analogous to `has_path` because -all URLs have valid paths, even when the path is empty. - -[table [[Code][Output]] [[ -[c++] -[snippet_parsing_path_3] -][ -[teletype] -``` - https://www.boost.org - path: -``` -]]] - -Notice that there the decoded counterpart for -[link url.ref.boost__urls__url_view.encoded_path `encoded_path`] -should be used with care when the path segments represents a -hierarchy as any decoded character `/` could form an ambiguous -path segment. In these use cases, segment views are the most -appropriate to access individual decoded path segments. - -[heading Segments View] - -These segment view containers are lightweight references to the underlying path - string. Ownership of the string is not transferred; the caller is responsible for -ensuring that the lifetime of the string extends until the container is -destroyed. - -[table [[Code][Output]] [[ -[c++] -[snippet_parsing_path_2] -][ -[teletype] -``` - 2 segments - segment: doc - segment: libs -``` -]]] - -In contexts where a path can appear by itself, such as HTTP requests, -segment views may not be constructed directly from strings. Instead, -we can use the analogous function -[link url.ref.boost__urls__parse_path `parse_path`] to obtain a -__segments_view__ or a __segments_encoded_view__. - -[table [[Code][Output]] [[ -[c++] -[snippet_parsing_path_9] -][ -[teletype] -``` - path: /doc/libs - 2 segments - segment: doc - segment: libs -``` -]]] - -[heading Path Semantics] - -A path can be absolute or relative. An absolute path begins with `/`: - -[table - [[URL] [Path Type] ] - [[[c++][snippet_modifying_path_1]] [Relative path `""` with 0 segments] ] - [[[c++][snippet_modifying_path_2]] [Absolute path `"/"` with 0 segments]] -] - -The complete path segments "." and ".." are intended only for use -within relative references (__rfc3986__ sec. 4.1) and are removed as part of -the reference resolution process (__rfc3986__ sec. 5.2). Normalizing a URI -resolves these dot-segments (__rfc3986__ sec. 5.2.4). - -[table - [[URL] [Normalized URL] [Path] ] - [[[c++][snippet_modifying_path_3]] [`"https://www.boost.org/b"`] [Absolute path `"/b"` with segments `{"b"}`]] -] - -These rules imply a path with the prefix `":"` or `"/"` could be in conflict with -the scheme and authority components of the URL, since they end with these -characters. For instance, attempting to create a path with the prefix `//`, -i.e. a path whose first segment is empty, could be interpreted as an empty -authority: - -[table - [[URL] [Authority] [Path] ] - [[[c++][snippet_modifying_path_4]] [(no authority)] [Relative path `"path/to/file.txt"` with segments `{"path", "to", "file.txt"}`] ] - [[[c++][snippet_modifying_path_5]] [(no authority)] [Absolute path `"/path/to/file.txt"` with segments `{"path", "to", "file.txt"}`]] - [[[c++][snippet_modifying_path_6]] [`"path"`] [Absolute path `"/to/file.txt"` with segments `{"to", "file.txt"}`] ] -] - -Likewise, attempting to create a relative path whose first segment contains a `":"` -could be interpreted as another scheme and a path: - -[table - [[URL] [Scheme] [Path] ] - [[[c++][snippet_modifying_path_7]] [(no scheme)] [Relative path `"path-to/file.txt"` with segments `{"path-to", "file.txt"}`]] - [[[c++][snippet_modifying_path_8]] [`"path"`] [Relative path `"to/file.txt"` with segments `{"to", "file.txt"}`] ] -] - -Modifying functions will properly adjust paths with malleable null prefixes -so that paths maintain their semantics without conflicting with the scheme -or authority components: - -[table - [[Code] [URL] [Path] ] - [[[c++][snippet_modifying_path_9]] [`"https:/.//path/to/file.txt"`] [Absolute path `"/.//path/to/file.txt"` with segments `{"", "path", "to", "file.txt"}`]] - [[[c++][snippet_modifying_path_10]] [`"./path:to/file.txt"`] [Relative path `"./path:to/file.txt"` with segments `{"path:to", "file.txt"}`] ] -] - -Given relative or absolute path, note that all algorithms preserve the path -semantics in lossless round-trip conversions between the URL path and their -segment container representations. Modifying functions will also adjust path -suffixes if a delimiter to the existing path segments would be missing: - -[table - [[Code] [URL] [Path] ] - [[[c++][snippet_modifying_path_11]] [`"path/to/file.txt"`] [Relative path `"path/to/file.txt"` with segments `{"path", "to", "file.txt"}`]] -] - -[heading Use Cases] - -The path comes after the URL authority, including the initial slash `/`: - -[teletype] -[table - [[Component] [Value] ] - [[URL] [`https://www.boost.org/doc/libs/`] ] - [[Path] [`/doc/libs/`] ] -] - -In this example, the path has three segments: - -[table - [[Component] [Value] ] - [[URL] [`https://www.boost.org/doc/libs/`] ] - [[Segment 1] [`doc`] ] - [[Segment 2] [`libs`] ] - [[Segment 3] [(empty segment)] ] -] - -Note that the final slash in `/doc/libs/` implies an extra -empty segment that would not exist in the path `/doc/libs`: - -[table - [[Component] [Value] ] - [[URL] [`https://www.boost.org/doc/libs`] ] - [[Segment 1] [`doc`] ] - [[Segment 2] [`libs`] ] -] - -A URL always contains a path, even if it is empty: - -[table - [[Component] [Value] ] - [[URL] [`https://www.boost.org`] ] - [[Path] [] ] -] - -Empty segments are also possible, resulting in consecutive slashes. - -[table - [[Component] [Value] ] - [[URL] [`https://www.boost.org//doc///libs`] ] - [[Path] [`//doc///libs`] ] - [[Segment 1] [(empty)] ] - [[Segment 2] [`doc`] ] - [[Segment 3] [(empty)] ] - [[Segment 4] [(empty)] ] - [[Segment 5] [`libs`] ] -] - -If the authority is present, the path needs to be empty or start with a -slash `/`. - -[table - [[Component] [Value] ] - [[URL] [`https://www.boost.org`] ] - [[Host] [`www.boost.org`] ] - [[Path] [] ] - [[Segments] [0] ] -] - -[table - [[Component] [Value] ] - [[URL] [`https://www.boost.org/`] ] - [[Host] [`www.boost.org`] ] - [[Path] [\/] ] - [[Segments] [0] ] -] - -[table - [[Component] [Value] ] - [[URL] [`https://www.boost.org//`] ] - [[Host] [`www.boost.org`] ] - [[Path] [\//] ] - [[Segments] [2] ] -] - -A path might begin with two slashes to indicate its first segment is empty. - -[table - [[Component] [Value] ] - [[URL] [`https://www.boost.org//doc/libs/`] ] - [[Authority] [`www.boost.org`] ] - [[Path] [`//doc/libs/`] ] - [[Segment 1] [(empty)] ] - [[Segment 2] [`doc`] ] - [[Segment 3] [`libs`] ] - [[Segment 4] [(empty)] ] -] - -However, beginning the path with double slashes is not possible when the -authority is absent, as the first segment path would be interpreted as the -authority. - -[table - [[Component] [Value] ] - [[URL] [`https://doc/libs/`] ] - [[Authority] [`doc`] ] - [[Path] [`/libs/`] ] - [[Segment 1] [`libs`] ] - [[Segment 2] [(empty)] ] -] - -For this reason, paths beginning with two slashes are typically avoided -altogether. - -Of the reserved character set for URLs, `":"` and `"@"` may appear unencoded within -paths. - -[table - [[Component] [Value] ] - [[URL] [`https://www.boost.org/doc@folder/libs:boost`] ] - [[Authority] [`www.boost.org`] ] - [[Path] [`/doc@folder/libs:boost`] ] - [[Segment 1] [`doc@folder`] ] - [[Segment 2] [`libs:boost`] ] -] - -[heading Member Functions] - -The functions for interacting with the path in a __url_view__ are as follows: - -[table Path Observers [ - [Function] - [Description] -][ - [[link url.ref.boost__urls__url_view.path `path`]] - [Return the path as a percent-decoded string] -][ - [[link url.ref.boost__urls__url_view.encoded_path `encoded_path`]] - [Return the path as a percent-encoded string] -][ - [[link url.ref.boost__urls__url_view.encoded_segments `encoded_segments`]] - [Return the path segments as a read-only container of percent-encoded strings.] -]] - -A URL path is usually interpreted as segments. The library -provides two read-only containers for interacting with the segments -in a URL's path: - -[table Segment Observers [ - [Type] - [Description] -][ - [[link url.ref.boost__urls__segments_view `segments_view`]] - [A read-only forward range of path segments returned as strings with percent-decoding applied.] -][ - [[link url.ref.boost__urls__segments_encoded_view `segments_encoded_view`]] - [A read-only forward range of path segments returned as percent-encoded strings.] -]] - -Segment views can be directly created by the parsing functions below. This provides -the guarantee that all constructed views contain valid path segments: - -[table Path Parsing Functions [ - [Function] - [Grammar] -][ - [[link url.ref.boost__urls__parse_path `parse_path`]] - [['any path]] -]] - -The functions for modifying paths in a __url__ are as follows: - -[table Path Modifiers [ - [Function] - [Description] -][ - [[link url.ref.boost__urls__url.set_path `set_path`]] - [Set the path] -][ - [[link url.ref.boost__urls__url.set_encoded_path `set_encoded_path`]] - [Set the encoded path] -][ - [[link url.ref.boost__urls__url.set_path_absolute `set_path_absolute`]] - [Set whether the path is absolute] -][ - [[link url.ref.boost__urls__url.normalize_path `normalize_path`]] - [Normalize path] -]] - -A URL path is usually interpreted as segments. A __url__ -provides two modifiable containers for interacting with the segments -in a URL's path: - -[table Segment View Types [ - [Type] - [Description] -][ - [[link url.ref.boost__urls__segments `segments`]] - [A forward range of path segments returned as strings with percent-decoding applied.] -][ - [[link url.ref.boost__urls__segments_encoded `segments_encoded`]] - [A forward range of path segments returned as percent-encoded strings.] -]] - -[/-----------------------------------------------------------------------------] - -[endsect] diff --git a/doc/qbk/5.4.query.qbk b/doc/qbk/5.4.query.qbk deleted file mode 100644 index aa67f50a..00000000 --- a/doc/qbk/5.4.query.qbk +++ /dev/null @@ -1,312 +0,0 @@ -[/ - Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) - - Distributed under the Boost Software License, Version 1.0. (See accompanying - file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - - Official repository: https://github.com/CPPAlliance/url -] - -[/-----------------------------------------------------------------------------] - -[#section.query] -[section:query Query] - -[heading Notation] - -The query component of a URL augments the information in the path to identify -a resource within the scope of the URL's scheme and authority. Unlike the URL -path, the query string contains non-hierarchical data. - -Although there is no mandatory syntax for interpreting queries, its strings -are often interpreted as key-value parameters delimited by the '&' or ';' -character. In addition to interacting with the query as a single string, -the library provides container adaptors modeling ranges of individual query -parameters. - -The URL below contains the query "[teletype]`?id=409&name=Joe&individual`" -with the three parameters "[teletype]`id=409`", "[teletype]`name=Joe`", and -"[teletype]`individual`": - -[teletype] -``` - https://www.example.com/get-customer.php?id=409&name=Joe&individual -``` - -A query is indicated by a leading question mark ('?') character as seen in -the BNF below: - -[table Query BNF [[ -``` - query = *( pchar / "/" / "?" ) - - absolute-URI = scheme ":" hier-part [ "?" query ] - - relative-ref = relative-part [ "?" query ] [ "#" fragment ] - - URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] - - URI-reference = URI / relative-ref -``` -]]] - -This table shows the BNF for a query string interpreted as parameters: - -[table Query Params BNF [[ -``` - query-params = query-param *( "&" query-param ) - - query-param = key [ "=" value ] - - key = *qpchar - value = *( qpchar / "=" ) - - qpchar = unreserved - / pct-encoded - / "!" / "$" / "'" / "(" / ")" - / "*" / "+" / "," / ";" - / ":" / "@" / "/" / "?" -``` -]]] - -[heading Observers] - -The function [link url.ref.boost__urls__url_view.query `query`] and -[link url.ref.boost__urls__url_view.encoded_query `encoded_query`] can -be used to obtain the query string from a __url_view__: - -[table [[Code][Output]] [[ -[c++] -[snippet_parsing_query_4] -][ -[teletype] -``` - https://www.example.com/get-customer.php?name=joe - encoded query: name=joe -``` -]]] - -These functions do not throw. If the URL has no query, -[link url.ref.boost__urls__url_view.query `query`] and -[link url.ref.boost__urls__url_view.encoded_query `encoded_query`] -return an empty string. The function -[link url.ref.boost__urls__url_view.has_query `has_query`] -can be used to determine whether this empty string means there is -no query or an empty query string in the URL. - -[table [[Code][Output]] [[ -[c++] -[snippet_parsing_query_5] -][ -[teletype] -``` - https://www.example.com/get-customer.php - has query: 0 - encoded query: -``` -]]] - -When using the query string as parameters, note that decoded -query strings might include ambiguous `&` and `=` characters. - -[table [[Code][Output]] [[ -[c++] -[snippet_parsing_query_7] -][ -[teletype] -``` - https://www.example.com/get-customer.php?name=John%26Doe - has query: 1 - encoded query: name=John%26Doe - query: name=John&Doe -``` -]]] - -In this example, the decoded query seems to imply there are -two query parameters while there is only one parameter whose -value includes a `&` character. In this case, the decoded -parameters can be accessed safely through a parameter view. - -The reason the decoded variant of query string is still allowed -is because query strings are not required to be interpreted as -query parameters, in which case the `&` character is not ambiguous. - -[heading Parameter View] - -Parameter views are lightweight references to the underlying path string. -Ownership of the string is not transferred; the caller is responsible for -ensuring that the lifetime of the string extends until the container is -destroyed. - -[table [[Code][Output]] [[ -[c++] -[snippet_parsing_query_1] -][ -[teletype] -``` - https://www.example.com/get-customer.php?id=409&name=Joe&individual - has query: 1 - query: id=409&name=Joe&individual - 3 parameters - parameter: - parameter: - parameter: individual -``` -]]] - -Each parameter is represented as a structure with fields to refer to the -key and value. An extra field `has_value` is used to indicate whether -the value is absent. - -[heading Use Cases] - -The most common formulation for the query in a URL is to define a set of -key and value pairs of percent-encoded strings, using the ampersand ('&') -character to delimit each pair after the first. In contexts where a query -is interpreted as key/value pairs, it is called the ['query parameters], -['query params], or just [*params]. - -In addition to accessor functions which treat the query as a single string, -the library provides container adaptors modeling ranges of query parameters. -The following URL contains three query parameters: - -[table - [[Component] [Value] ] - [[URL] [`https://www.example.com/get-customer.php?id=409&name=Joe&individual`] ] - [[Has Query] [Yes] ] - [[Query] [`id=409&name=Joe&individual`] ] - [[Parameter 1] [Key `id`, Value `409`] ] - [[Parameter 2] [Key `name`, Value `Joe`] ] - [[Parameter 3] [Key `individual`, No value] ] -] - -Note that a parameter value might be either empty or absent. The -presence of a value is indicated by the presence of an equals ('=') -sign appearing after the key. This means the value may be absent, -empty, or contain characters. - -The key of a query parameter might also be empty. This means that -a query parameter may be completely empty. In this case the -parameter is said to have a zero-length or empty key, and -no value. - -The URL below demonstrate all the ways that keys and values may -appear in query parameters: - -[table - [[Component] [Value] ] - [[URL] [`https://www.example.com/get-customer.php?key-1=value-1&key-2=&key-3&&=value-5`] ] - [[Has Query] [Yes] ] - [[Query] [`key-1=value-1&key-2=&key-3&&=value-5`] ] - [[Parameter 1] [Key `key-1`, Value `value-1`] ] - [[Parameter 2] [Key `key-2`, Value (empty)] ] - [[Parameter 3] [Key `key-3`, No value] ] - [[Parameter 4] [Key (empty), No value] ] - [[Parameter 5] [Key (empty), Value `value-5`] ] -] - -The URL reserved characters `:`, `@`, `?`, and `/` may appear -unencoded with URL queries, as they are not ambiguous with -other URL components. - -[table - [[Component] [Value] ] - [[URL] [`https://www.example.com/get-customer.php?email=joe@email.com&code=a:2@/!`] ] - [[Has Query] [Yes] ] - [[Query] [`email=joe@email.com&code=a:2@/!`] ] - [[Parameter 1] [Key `email`, Value `joe@email.com`] ] - [[Parameter 2] [Key `code`, Value `a:2@/!`] ] -] - -[heading Member Functions] - -The functions for interacting with the query in a __url_view__ are as follows: - -[table Query Observers [ - [Function] - [Description] -][ - [[link url.ref.boost__urls__url_view.has_query `has_query`]] - [Return true if a query is present] -][ - [[link url.ref.boost__urls__url_view.query `query`]] - [Return the query as a string with percent-decoding applied.] -][ - [[link url.ref.boost__urls__url_view.encoded_query `encoded_query`]] - [Return the percent-encoded query.] -]] - -A URL query is usually interpreted as parameters. A __url_view__ -provides two observers and read-only containers for interacting -with the parameters in a URL's query: - -[table Query Params Observers [ - [Function] - [Description] -][ - [[link url.ref.boost__urls__url_view.encoded_params `encoded_params`]] - [Return the query parameters as a read-only container of percent-encoded strings.] -][ - [[link url.ref.boost__urls__url_view.params `params`]] - [Return the query parameters as a read-only container of strings with percent-decoding applied.] -]] - -[table Params View Types [ - [Type] - [Description] -][ - [[link url.ref.boost__urls__params_view `params_view`]] - [A read-only forward range of query parameters returned as strings with percent-decoding applied.] -][ - [[link url.ref.boost__urls__params_encoded_view `params_encoded_view`]] - [A read-only forward range of query parameters returned as percent-encoded strings.] -]] - -The functions for modifying the query in a __url__ are as follows: - -[table Query Modifiers [ - [Function] - [Description] -][ - [[link url.ref.boost__urls__url.set_query `set_query`]] - [Set query] -][ - [[link url.ref.boost__urls__url.set_encoded_query `set_encoded_query`]] - [Set encoded query] -][ - [[link url.ref.boost__urls__url.remove_query `remove_query`]] - [Remove query] -][ - [[link url.ref.boost__urls__url.normalize_query `normalize_query`]] - [Normalize query] -]] - -A URL query is usually interpreted as parameters. A __url__ -provides two modifiable containers for interacting with the parameters -in a URL's query: - -[table Query Params Modifiers [ - [Function] - [Description] -][ - [[link url.ref.boost__urls__url.params `params`]] - [Return the query parameters as a modifiable container of strings with percent-decoding applied.] -][ - [[link url.ref.boost__urls__url.encoded_params `encoded_params`]] - [Return the query parameters as a modifiable container of percent-encoded strings.] -]] - -[table Params View Types [ - [Type] - [Description] -][ - [[link url.ref.boost__urls__params `params`]] - [A modifiable forward range of query parameters returned as strings with percent-decoding applied.] -][ - [[link url.ref.boost__urls__params_encoded `params_encoded`]] - [A modifiable forward range of query parameters returned as percent-encoded strings.] -]] - -[/-----------------------------------------------------------------------------] - -[endsect] diff --git a/doc/qbk/5.5.fragment.qbk b/doc/qbk/5.5.fragment.qbk deleted file mode 100644 index ac64c835..00000000 --- a/doc/qbk/5.5.fragment.qbk +++ /dev/null @@ -1,194 +0,0 @@ -[/ - Copyright (c) 2019 Vinnie Falco (vinnie.falco@gmail.com) - - Distributed under the Boost Software License, Version 1.0. (See accompanying - file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt) - - Official repository: https://github.com/CPPAlliance/url -] - -[/-----------------------------------------------------------------------------] - -[section Fragment] - -[heading Notation] - -The fragment identifier in a URL provides further refinement of the -specification of the resource, including additional identifying information. -It provides directions to a secondary resource related to such main resource, -such as the section in an article or a time-point in a video. - -As usual, its semantics vary depending on the scheme, authority, path, -and media type of the resource. In HTML, fragments are used as internal -page references. This usage is called a "named anchor," referring to a -section within a web page. - -The URL below contains the fragment "section2": - -[teletype] -``` - https://www.example.com/index.html#section2 - \____/\_______________/\_________/\_______/ - scheme authority path fragment -``` - -A fragment appearing in a URL is always preceded by the number sign ('#'). -This makes a URL with a fragment of zero length distinguishable from a URL -with no fragment. - -The fragment grammar is defined as follows: - -[table Fragment BNF [[ -[teletype] -``` - fragment = *( pchar / "/" / "?" ) - - relative-ref = relative-part [ "?" query ] [ "#" fragment ] - - URI = scheme ":" hier-part [ "?" query ] [ "#" fragment ] - - URI-reference = URI / relative-ref -``` -]]] - -[heading Observers] - -Analogous to other components, the functions -[link url.ref.boost__urls__url_view.encoded_fragment `fragment`] and -[link url.ref.boost__urls__url_view.encoded_fragment `encoded_fragment`] -can be used to obtain the fragment from a __url_view__: - -[table [[Code][Output]] [[ -[c++] -[snippet_parsing_fragment_1] -][ -[teletype] -``` - https://www.example.com/index.html#section%202 - has fragment: 1 - fragment: section 2 - encoded fragment: section%202 -``` -]]] - -These functions do not throw. If the URL has no fragment, they -return an empty string. The function -[link url.ref.boost__urls__url_view.has_fragment `has_fragment`] -can be used to determine whether this empty string means there is -no fragment or an empty fragment string in the URL. - -[table [[Code][Output]] [[ -[c++] -[snippet_parsing_fragment_2_a] -][ -[teletype] -``` - https://www.example.com/index.html# - has fragment: 1 - fragment: -``` -]] -[[ -[c++] -[snippet_parsing_fragment_2_b] -][ -[teletype] -``` - https://www.example.com/index.html - has fragment: 0 - fragment: -``` -]][[ -[c++] -[snippet_parsing_fragment_3] -][ -[teletype] -``` - https://www.example.com/index.html - has fragment: 1 - fragment: code :a@b?c/d -``` -]]] - -[heading Use Cases] - -URL fragments are usually interpreted as a single string. - -[table - [[Component] [Value] ] - [[URL] [`https://www.example.com/index.html#section%202`] ] - [[Has Fragment] [Yes] ] - [[Encoded Fragment] [`section%202`] ] - [[Fragment] [`section 2`] ] -] - -The URL fragment might also be empty or absent. - -[table - [[Component] [Value] ] - [[URL] [`https://www.example.com/index.html#`] ] - [[Has Fragment] [Yes] ] - [[Encoded Fragment] [(empty)] ] - [[Fragment] [(empty)] ] -] - -[table - [[Component] [Value] ] - [[URL] [`https://www.example.com/index.html`] ] - [[Has Fragment] [No] ] - [[Encoded Fragment] [(No fragment)] ] - [[Fragment] [(No fragment)] ] -] - -The URL reserved characters `:`, `@`, `?`, and `/` may appear -unencoded with URL fragments, as they are not ambiguous with -other URL components. - -[table - [[Component] [Value] ] - [[URL] [`https://www.example.com/index.html#code%20:a@b?c/d`] ] - [[Has Fragment] [Yes] ] - [[Encoded Fragment] [`code%20:a@b?c/d`] ] - [[Fragment] [`code :a@b?c/d`] ] -] - -[heading Member Functions] - -The functions for inspecting the fragment in a __url_view__ are as follows: - -[table Fragment Observers[ - [Function] - [Description] -][ - [[link url.ref.boost__urls__url_view.has_fragment `has_fragment`]] - [Return true if a fragment is present] -][ - [[link url.ref.boost__urls__url_view.fragment `fragment`]] - [Return the fragment as a string with percent-decoding applied.] -][ - [[link url.ref.boost__urls__url_view.encoded_fragment `encoded_fragment`]] - [Return the fragment as a percent-encoded string.] -]] - -The functions for modifying the fragment in a __url__ are as follows: - -[table Fragment Observers[ - [Function] - [Description] -][ - [[link url.ref.boost__urls__url.set_fragment `set_fragment`]] - [Set fragment] -][ - [[link url.ref.boost__urls__url.set_encoded_fragment `set_encoded_fragment`]] - [Set encoded fragment] -][ - [[link url.ref.boost__urls__url.remove_fragment `remove_fragment`]] - [Remove fragment] -][ - [[link url.ref.boost__urls__url.normalize_fragment `normalize_fragment`]] - [Normalize fragment] -]] - -[/-----------------------------------------------------------------------------] - -[endsect] diff --git a/doc/qbk/8.0.examples.qbk b/doc/qbk/6.0.examples.qbk similarity index 100% rename from doc/qbk/8.0.examples.qbk rename to doc/qbk/6.0.examples.qbk diff --git a/doc/qbk/2.1.HelpCard.qbk b/doc/qbk/7.1.HelpCard.qbk similarity index 91% rename from doc/qbk/2.1.HelpCard.qbk rename to doc/qbk/7.1.HelpCard.qbk index f89c5148..eebf2d9c 100644 --- a/doc/qbk/2.1.HelpCard.qbk +++ b/doc/qbk/7.1.HelpCard.qbk @@ -7,7 +7,7 @@ Official repository: https://github.com/CPPAlliance/url ] -[section Help Card] +[section:helpcard Help Card] [$url/images/HelpCard.svg] diff --git a/example/magnet/magnet.cpp b/example/magnet/magnet.cpp index 26b5b7ed..aa07d91d 100644 --- a/example/magnet/magnet.cpp +++ b/example/magnet/magnet.cpp @@ -24,12 +24,12 @@ namespace urls = boost::urls; -/// Functor to identify a magnet "exact topic" +/// Callable to identify a magnet "exact topic" /** - This functor evaluates if a query parameter + This callable evaluates if a query parameter represents a magnet "exact topic". - This functor is used as a filter for + This callable is used as a filter for the topics_view. */ struct is_exact_topic { @@ -37,16 +37,16 @@ struct is_exact_topic { operator()(urls::query_param_view p); }; -/// Functor to identify a magnet url parameter +/// Callable to identify a magnet url parameter /** - This functor evaluates if a query parameter + This callable evaluates if a query parameter has a given key and a url as its value. These urls are percent-encoded twice, which means we need to decode it once before attempting to parse it. - This functor is used as a filter for + This callable is used as a filter for the keys_view. */ template @@ -65,12 +65,12 @@ public: operator()(urls::query_param_view p); }; -/// Functor to convert param values to urls +/// Callable to convert param values to urls /** - This functor converts the value of a + This callable converts the value of a query parameter into a urls::url_view. - This functor is used as a transform + This callable is used as a transform function for the topics_view. */ struct to_url { @@ -78,12 +78,12 @@ struct to_url { operator()(urls::query_param_view p); }; -/// Functor to convert param values to urls::pct_encoded_view +/// Callable to convert param values to urls::pct_encoded_view /** - This functor converts the value of a + This callable converts the value of a query parameter into a urls::pct_encoded_view. - This functor is used as a transform + This callable is used as a transform function for the keys_view. */ struct to_decoded_value { @@ -94,16 +94,16 @@ struct to_decoded_value { } }; -/// Functor to convert param values to info_hashes +/// Callable to convert param values to info_hashes /** - This functor converts the value of a + This callable converts the value of a query parameter into a urls::string_view with its infohash. The infohash hash is a parameter of an exact topic field in the magnet link. - This functor is used as a transform + This callable is used as a transform function for the info_hashes_view. */ struct to_infohash { @@ -111,16 +111,16 @@ struct to_infohash { operator()(urls::query_param_view p); }; -/// Functor to convert param values to protocols +/// Callable to convert param values to protocols /** - This functor converts the value of a + This callable converts the value of a query parameter into a urls::string_view with its protocol. The protocol is a parameter of an exact topic field in the magnet link. - This functor is used as a transform + This callable is used as a transform function for the protocols_view. */ struct to_protocol { diff --git a/include/boost/url/url.hpp b/include/boost/url/url.hpp index 93f61c07..1a34cef0 100644 --- a/include/boost/url/url.hpp +++ b/include/boost/url/url.hpp @@ -79,7 +79,7 @@ public: invalidated. */ BOOST_URL_DECL - ~url(); + virtual ~url(); /** Constructor diff --git a/test/unit/CMakeLists.txt b/test/unit/CMakeLists.txt index b1562341..0041eebf 100644 --- a/test/unit/CMakeLists.txt +++ b/test/unit/CMakeLists.txt @@ -104,9 +104,12 @@ target_link_libraries(boost_url_tests PRIVATE Boost::unordered) add_test(NAME boost_url_tests COMMAND boost_url_tests) add_dependencies(boost_url_all_tests boost_url_tests) -if (TARGET boost_filesystem AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") - get_target_property(FS_IS_IMPORTED boost_filesystem IMPORTED) - if (FS_IS_IMPORTED) - target_compile_options(boost_filesystem PUBLIC -Wno-error=restrict) +if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + target_compile_options(boost_url_tests PUBLIC -Wno-error=unused-but-set-variable) + if (TARGET boost_filesystem AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + get_target_property(FS_IS_IMPORTED boost_filesystem IMPORTED) + if (FS_IS_IMPORTED) + target_compile_options(boost_filesystem PUBLIC -Wno-error=restrict) + endif() endif() endif() \ No newline at end of file diff --git a/test/unit/snippets.cpp b/test/unit/snippets.cpp index af5e5f43..78ce06a8 100644 --- a/test/unit/snippets.cpp +++ b/test/unit/snippets.cpp @@ -55,42 +55,47 @@ using_url_views() //] } - url_view u = parse_uri( s ).value(); - - //[snippet_accessing_1 - std::cout << - "url : " << u << "\n" - "scheme : " << u.scheme() << "\n" - "authority : " << u.authority() << "\n" - "userinfo : " << u.userinfo() << "\n" - "user : " << u.user() << "\n" - "password : " << u.password() << "\n" - "host : " << u.host() << "\n" - "port : " << u.port() << "\n" - "path : " << u.path() << "\n" - "query : " << u.query() << "\n" - "fragment : " << u.fragment() << "\n"; - //] + { + //[snippet_accessing_1 + string_view s = "https://user:pass@example.com:443/path/to/my%2dfile.txt?id=42&name=John%20Doe+Jingleheimer%2DSchmidt#page%20anchor"; + url_view u( s ); + assert(u.scheme() == "https"); + assert(u.authority().string() == "user:pass@example.com:443"); + assert(u.userinfo() == "user:pass"); + assert(u.user() == "user"); + assert(u.password() == "pass"); + assert(u.host() == "example.com"); + assert(u.port() == "443"); + assert(u.path() == "/path/to/my-file.txt"); + assert(u.query() == "id=42&name=John Doe Jingleheimer-Schmidt"); + assert(u.fragment() == "page anchor"); + //] + } + url_view u( s ); //[snippet_accessing_1b for (auto seg: u.segments()) std::cout << seg << "\n"; std::cout << "\n"; + for (auto param: u.params()) std::cout << param.key << ": " << param.value << "\n"; + std::cout << "\n"; //] { //[snippet_accessing_2a url_view u1 = parse_uri( "http://www.example.com" ).value(); - std::cout << "fragment 1 : " << u1.fragment() << "\n\n"; + assert(u1.fragment().empty()); + assert(!u1.has_fragment()); //] } { //[snippet_accessing_2b url_view u2 = parse_uri( "http://www.example.com/#" ).value(); - std::cout << "fragment 2 : " << u2.fragment() << "\n\n"; + assert(u2.fragment().empty()); + assert(u2.has_fragment()); //] } @@ -274,18 +279,56 @@ using_urls() void parsing_urls() { - //[snippet_parsing_url_1 - result< url_view > r = parse_uri( "https://www.example.com/path/to/file.txt" ); - if( r.has_value() ) // parsing was successful { - url_view u = r.value(); // extract the url_view - std::cout << u << "\n"; // format the URL to cout + //[snippet_parsing_url_1 + result< url_view > r = parse_uri( "https://www.example.com/path/to/file.txt" ); + //] + boost::ignore_unused(r); } - else + { - std::cout << r.error().message(); // parsing failure; print error + //[snippet_parsing_url_1b + url_view u( "https://www.example.com/path/to/file.txt" ); + //] + + //[snippet_parsing_url_1bb + std::cout << u; + //] + } + + { + //[snippet_parsing_url_1bc + result< url > rv = parse_uri_reference( "https://www.example.com/path/to/file.txt" ); + + static_assert( std::is_convertible< result< url_view >, result< url > >::value, "" ); + //] + boost::ignore_unused(rv); + } + + { + //[snippet_parsing_url_1bd + result< static_url<1024> > rv = parse_uri_reference( "https://www.example.com/path/to/file.txt" ); + + static_assert( std::is_convertible< result< static_url<1024> >, result< url > >::value, "" ); + //] + boost::ignore_unused(rv); + } + + { + //[snippet_parsing_url_1c + result< url_view > r0 = parse_relative_ref( "/path/to/file.txt" ); + assert( r0.has_value() ); + //] + //[snippet_parsing_url_1d + result< url_view > r1 = parse_uri( "https://www.example.com" ); + assert( r1.has_value() ); + url dest; + error_code ec; + resolve(r1.value(), r0.value(), dest, ec); + assert(dest.string() == "https://www.example.com/path/to/file.txt"); + //] + boost::ignore_unused(dest); } - //] //[snippet_parsing_url_2 // This will hold our copy @@ -323,42 +366,85 @@ parsing_urls() std::cout << v << "\n"; // and it's mutable - v.set_encoded_fragment("anchor"); + v.set_fragment("anchor"); + // path/to/file.txt#anchor std::cout << v << "\n"; //] } } +void +parsing_components() +{ + { + //[snippet_components_1 + string_view s = "https://user:pass@example.com:443/path/to/my%2dfile.txt?id=42&name=John%20Doe+Jingleheimer%2DSchmidt#page%20anchor"; + url_view u( s ); + assert(u.scheme() == "https"); + assert(u.authority().string() == "user:pass@example.com:443"); + assert(u.path() == "/path/to/my-file.txt"); + assert(u.query() == "id=42&name=John Doe Jingleheimer-Schmidt"); + assert(u.fragment() == "page anchor"); + //] + } + { + //[snippet_components_2a + url_view u( "https://www.ietf.org/rfc/rfc2396.txt" ); + assert(u.scheme() == "https"); + assert(u.host() == "www.ietf.org"); + assert(u.path() == "/rfc/rfc2396.txt"); + //] + } + { + //[snippet_components_2b + url_view u( "ftp://ftp.is.co.za/rfc/rfc1808.txt" ); + assert(u.scheme() == "ftp"); + assert(u.host() == "ftp.is.co.za"); + assert(u.path() == "/rfc/rfc1808.txt"); + //] + } + { + //[snippet_components_2c + url_view u( "mailto:John.Doe@example.com" ); + assert(u.scheme() == "mailto"); + assert(u.path() == "John.Doe@example.com"); + //] + } + { + //[snippet_components_2d + url_view u( "urn:isbn:096139210x" ); + assert(u.scheme() == "urn"); + assert(u.path() == "isbn:096139210x"); + //] + } + { + //[snippet_components_2e + url_view u( "magnet:?xt=urn:btih:d2474e86c95b19b8bcfdb92bc12c9d44667cfa36" ); + assert(u.scheme() == "magnet"); + assert(u.path() == ""); + assert(u.query() == "xt=urn:btih:d2474e86c95b19b8bcfdb92bc12c9d44667cfa36"); + //] + } +} + void parsing_scheme() { { //[snippet_parsing_scheme_1 - string_view s = "mailto:name@email.com"; - url_view u = parse_uri( s ).value(); - std::cout << u.scheme() << "\n"; - //] - } - { - string_view s = "mailto:name@email.com"; - //[snippet_parsing_scheme_2 - url_view u = parse_uri( s ).value(); - if (u.has_scheme()) - { - std::cout << u.scheme() << "\n"; - } + url_view u("mailto:name@email.com" ); + assert( u.has_scheme() ); + assert( u.scheme() == "mailto" ); //] + boost::ignore_unused(u); } { //[snippet_parsing_scheme_3 - string_view s = "file://host/path/to/file"; - url_view u = parse_uri( s ).value(); - if (u.scheme_id() == scheme::file) - { - // handle file - } + url_view u("file://host/path/to/file" ); + assert( u.scheme_id() == scheme::file ); //] + boost::ignore_unused(u); } } @@ -367,19 +453,15 @@ parsing_authority() { { //[snippet_parsing_authority_1 - string_view s = "https:///path/to_resource"; - url_view u = parse_uri( s ).value(); - std::cout << u << "\n" - "scheme: " << u.scheme() << "\n" - "has authority: " << u.has_authority() << "\n" - "authority: " << u.authority() << "\n" - "path: " << u.encoded_path() << "\n"; + url_view u( "https:///path/to_resource" ); + assert( u.authority().string() == ""); + assert( u.has_authority() ); + assert( u.path() == "/path/to_resource" ); //] } { //[snippet_parsing_authority_2 - string_view s = "https://www.boost.org"; - url_view u = parse_uri( s ).value(); + url_view u("https://www.boost.org" ); std::cout << "scheme: " << u.scheme() << "\n" "has authority: " << u.has_authority() << "\n" "authority: " << u.authority() << "\n" @@ -387,20 +469,18 @@ parsing_authority() //] } { - //[snippet_parsing_authority_3 - string_view s = "https://www.boost.org/users/download/"; - url_view u = parse_uri( s ).value(); - std::cout << u << "\n" - "scheme: " << u.scheme() << "\n" - "has authority: " << u.has_authority() << "\n" - "authority: " << u.authority() << "\n" - "path: " << u.path() << "\n"; + //[snippet_parsing_authority_3a + url_view u( "https://www.boost.org/users/download/" ); + assert(u.has_authority()); + authority_view a = u.authority(); + //] + //[snippet_parsing_authority_3b + assert(a.host() == "www.boost.org"); //] } { //[snippet_parsing_authority_4 - string_view s = "https://www.boost.org/"; - url_view u = parse_uri( s ).value(); + url_view u( "https://www.boost.org/" ); std::cout << "scheme: " << u.scheme() << "\n" "has authority: " << u.has_authority() << "\n" "authority: " << u.authority() << "\n" @@ -409,8 +489,7 @@ parsing_authority() } { //[snippet_parsing_authority_5 - string_view s = "mailto:John.Doe@example.com"; - url_view u = parse_uri( s ).value(); + url_view u( "mailto:John.Doe@example.com" ); std::cout << "scheme: " << u.scheme() << "\n" "has authority: " << u.has_authority() << "\n" "authority: " << u.authority() << "\n" @@ -419,8 +498,7 @@ parsing_authority() } { //[snippet_parsing_authority_6 - string_view s = "mailto://John.Doe@example.com"; - url_view u = parse_uri( s ).value(); + url_view u( "mailto://John.Doe@example.com" ); std::cout << u << "\n" "scheme: " << u.scheme() << "\n" "has authority: " << u.has_authority() << "\n" @@ -430,8 +508,7 @@ parsing_authority() } { //[snippet_parsing_authority_7 - string_view s = "https://john.doe@www.example.com:123/forum/questions/"; - url_view u = parse_uri( s ).value(); + url_view u( "https://john.doe@www.example.com:123/forum/questions/" ); std::cout << "scheme: " << u.scheme() << "\n" "has authority: " << u.has_authority() << "\n" "authority: " << u.authority() << "\n" @@ -443,96 +520,131 @@ parsing_authority() } { //[snippet_parsing_authority_8 - string_view s = "https://john.doe@www.example.com:123/forum/questions/"; - url_view u = parse_uri( s ).value(); - std::cout << u << "\n" - "host: " << u.host() << "\n" - "host and port: " << u.encoded_host_and_port() << "\n" - "port: " << u.port() << "\n" - "port number: " << u.port_number() << "\n"; + url_view u( "https://john.doe@www.example.com:123/forum/questions/" ); + assert(u.host() == "www.example.com"); + assert(u.port() == "123"); //] } { //[snippet_parsing_authority_9 - string_view s = "https://john.doe@192.168.2.1:123/forum/questions/"; - url_view u = parse_uri( s ).value(); - std::cout << u << "\n" - "host: " << u.host() << "\n" - "host and port: " << u.encoded_host_and_port() << "\n" - "port: " << u.port() << "\n" - "port number: " << u.port_number() << "\n"; + url_view u( "https://john.doe@192.168.2.1:123/forum/questions/" ); + assert(u.host() == "192.168.2.1"); + assert(u.port() == "123"); //] } { + //[snippet_parsing_authority_9b + url_view u( "https://www.example.com" ); + assert(u.host() == "www.example.com"); + assert(u.host() == u.encoded_host()); + //] + } + { + struct resolve_f { + pct_encoded_view + operator()(pct_encoded_view h) + { + return h; + } + } resolve; + struct write_request_f { + void operator()(pct_encoded_view) {} + void operator()(ipv4_address) {} + void operator()(ipv6_address) {} + } write_request; + //[snippet_parsing_authority_10 - string_view s = "https://www.boost.org/users/download/"; - url_view u = parse_uri( s ).value(); + url_view u( "https://www.boost.org/users/download/" ); switch (u.host_type()) { case host_type::name: - // resolve name - case host_type::ipv4: - case host_type::ipv6: - case host_type::ipvfuture: - // connect to ip + write_request(resolve(u.host())); break; - case host_type::none: - // handle empty host URL + case host_type::ipv4: + write_request(u.ipv4_address()); + break; + case host_type::ipv6: + write_request(u.ipv6_address()); + break; + default: break; } //] } { - //[snippet_parsing_authority_11 - string_view s = "https://john.doe:123456@www.somehost.com/forum/questions/"; - url_view u = parse_uri( s ).value(); - std::cout << u << "\n\n" - "has_userinfo: " << u.has_userinfo() << "\n" - "userinfo: " << u.userinfo() << "\n" - "user: " << u.user() << "\n\n" - "has_password: " << u.has_password() << "\n" - "password: " << u.password() << "\n"; + //[snippet_parsing_authority_10a + url_view u( "https:///path/to_resource" ); + assert( u.has_authority() ); + assert( u.authority().string().empty() ); + assert( u.path() == "/path/to_resource" ); + //] + } + { + //[snippet_parsing_authority_10b + url_view u( "https://www.boost.org" ); + assert( u.host() == "www.boost.org" ); + assert( u.path().empty() ); + //] + } + { + //[snippet_parsing_authority_10c + url_view u( "https://www.boost.org/users/download/" ); + assert( u.host() == "www.boost.org" ); + assert( u.path() == "/users/download/" ); + //] + } + { + //[snippet_parsing_authority_10d + url_view u( "https://www.boost.org/" ); + assert( u.host() == "www.boost.org" ); + assert( u.path() == "/" ); + //] + } + { + //[snippet_parsing_authority_10e + url_view u( "mailto:John.Doe@example.com" ); + assert( !u.has_authority() ); + assert( u.path() == "John.Doe@example.com" ); + //] + } + { + //[snippet_parsing_authority_10f + url_view u( "mailto://John.Doe@example.com" ); + assert( u.authority().string() == "John.Doe@example.com" ); + assert( u.path().empty() ); + //] + } + { + //[snippet_parsing_authority_11a + url_view u( "https://john.doe@www.example.com:123/forum/questions/" ); + assert(u.userinfo() == "john.doe"); + assert(u.port() == "123"); + //] + } + { + //[snippet_parsing_authority_11b + url_view u( "https://john.doe:123456@www.somehost.com/forum/questions/" ); + assert(u.userinfo() == "john:doe"); + assert(u.user() == "john"); + assert(u.password() == "doe"); //] } { - std::cout << "snippet_parsing_authority_12\n"; //[snippet_parsing_authority_12 - string_view s = "www.example.com:80"; - authority_view a = parse_authority( s ).value(); - std::cout << a << "\n\n" - // host and port - "host_and_port: " << a.encoded_host_and_port() << "\n" - "host: " << a.host() << "\n" - "port: " << a.port() << "\n" - "port number: " << a.port_number() << "\n\n" - // userinfo - "has_userinfo: " << a.has_userinfo() << "\n" - "userinfo: " << a.userinfo() << "\n" - // user - "user: " << a.user() << "\n\n" - // password - "has_password: " << a.has_password() << "\n" - "password: " << a.password() << "\n"; + authority_view a = parse_authority( "www.example.com:80" ).value(); + assert(!a.has_userinfo()); + assert(a.host() == "www.example.com"); + assert(a.port() == "80"); //] } { //[snippet_parsing_authority_13 - string_view s = "user:pass@www.example.com:443"; - authority_view a = parse_authority( s ).value(); - std::cout << a << "\n\n" - // host and port - "host_and_port: " << a.encoded_host_and_port() << "\n" - "host: " << a.host() << "\n" - "port: " << a.port() << "\n" - "port number: " << a.port_number() << "\n\n" - // userinfo - "has_userinfo: " << a.has_userinfo() << "\n" - "userinfo: " << a.userinfo() << "\n\n" - // user - "user: " << a.user() << "\n\n" - // password - "has_password: " << a.has_password() << "\n" - "password: " << a.password() << "\n"; + authority_view a = parse_authority( "user:pass@www.example.com:443" ).value(); + assert(a.userinfo() == "user:pass"); + assert(a.user() == "user"); + assert(a.password() == "pass"); + assert(a.host() == "www.example.com"); + assert(a.port() == "443"); //] } } @@ -540,60 +652,61 @@ parsing_authority() void parsing_path() { + { + //[snippet_parsing_path_0 + url_view u("http://www.example.com/path/to/file.txt"); + assert(u.path() == "/path/to/file.txt"); + segments_view segs = u.segments(); + auto it = segs.begin(); + assert( *it++ == "path" ); + assert( *it++ == "to" ); + assert( *it == "file.txt" ); + //] + boost::ignore_unused(it); + } { //[snippet_parsing_path_1 - string_view s = "https://www.boost.org/doc/libs/"; - url_view u = parse_uri(s).value(); - std::cout << u << "\n" - << "path: " << u.path() << "\n" - << "path: " << u.encoded_path() << "\n" - << "segments: " << u.segments() << "\n" - << "encoded_segments: " << u.encoded_segments() << "\n"; + url_view u("https://www.boost.org/doc/the%20libs/"); + assert(u.path() == "/doc/the libs/"); + assert(u.encoded_path() == "/doc/the%20libs/"); //] //[snippet_parsing_path_1_b std::cout << u.encoded_segments().size() << " segments\n"; for (auto seg: u.encoded_segments()) - { std::cout << "segment: " << seg << "\n"; - } //] } - { //[snippet_parsing_path_2 - string_view s = "https://www.boost.org/doc/libs"; - url_view u = parse_uri(s).value(); + url_view u("https://www.boost.org/doc/libs"); std::cout << u.segments().size() << " segments\n"; for (auto seg: u.segments()) - { std::cout << "segment: " << seg << "\n"; - } //] } - { //[snippet_parsing_path_3 - string_view s = "https://www.boost.org"; - url_view u = parse_uri(s).value(); - std::cout << u << "\n" - << "path: " << u.encoded_path() << "\n"; + url_view u("https://www.boost.org"); + assert(u.path().empty()); + assert(u.encoded_path().empty()); + //] + } + { + //[snippet_parsing_path_3a + assert( url_view("urn:isbn:096139210x").path() == "isbn:096139210x" ); //] } - { //[snippet_parsing_path_4 - string_view s = "https://www.boost.org//doc///libs"; - url_view u = parse_uri(s).value(); + url_view u("https://www.boost.org//doc///libs"); std::cout << u << "\n" "path: " << u.encoded_path() << "\n" "encoded segments: " << u.encoded_segments() << "\n" "segments: " << u.segments() << "\n"; std::cout << u.encoded_segments().size() << " segments\n"; for (auto seg: u.encoded_segments()) - { std::cout << "segment: " << seg << "\n"; - } //] } @@ -601,7 +714,7 @@ parsing_path() { //[snippet_parsing_path_5_a string_view s = "https://www.boost.org"; - url_view u = parse_uri(s).value(); + url_view u(s); std::cout << u << "\n" << "path: " << u.encoded_host() << "\n" << "path: " << u.encoded_path() << "\n" @@ -611,7 +724,7 @@ parsing_path() { //[snippet_parsing_path_5_b string_view s = "https://www.boost.org/"; - url_view u = parse_uri(s).value(); + url_view u(s); std::cout << u << "\n" << "host: " << u.encoded_host() << "\n" << "path: " << u.encoded_path() << "\n" @@ -621,7 +734,7 @@ parsing_path() { //[snippet_parsing_path_5_c string_view s = "https://www.boost.org//"; - url_view u = parse_uri(s).value(); + url_view u(s); std::cout << u << "\n" << "host: " << u.encoded_host() << "\n" << "path: " << u.encoded_path() << "\n" @@ -632,60 +745,121 @@ parsing_path() { //[snippet_parsing_path_6 - string_view s = "https://www.boost.org//doc/libs/"; - url_view u = parse_uri(s).value(); + url_view u("https://www.boost.org//doc/libs/"); std::cout << u << "\n" "authority: " << u.encoded_authority() << "\n" "path: " << u.encoded_path() << "\n"; std::cout << u.encoded_segments().size() << " segments\n"; for (auto seg: u.encoded_segments()) - { std::cout << "segment: " << seg << "\n"; - } //] } { //[snippet_parsing_path_7 - string_view s = "https://doc/libs/"; - url_view u = parse_uri(s).value(); + url_view u("https://doc/libs/"); std::cout << u << "\n" "authority: " << u.encoded_authority() << "\n" "path: " << u.encoded_path() << "\n"; std::cout << u.encoded_segments().size() << " segments\n"; for (auto seg: u.encoded_segments()) - { std::cout << "segment: " << seg << "\n"; - } //] } { //[snippet_parsing_path_8 - string_view s = "https://www.boost.org/doc@folder/libs:boost"; - url_view u = parse_uri(s).value(); + url_view u("https://www.boost.org/doc@folder/libs:boost"); std::cout << u << "\n" "authority: " << u.encoded_authority() << "\n" "path: " << u.encoded_path() << "\n"; std::cout << u.encoded_segments().size() << " segments\n"; for (auto seg: u.encoded_segments()) - { std::cout << "segment: " << seg << "\n"; - } //] } { //[snippet_parsing_path_9 - string_view s = "/doc/libs"; - segments_view p = parse_path(s).value(); - std::cout << "path: " << p << "\n"; - std::cout << p.size() << " segments\n"; - for (auto seg: p) - { - std::cout << "segment: " << seg << "\n"; - } + segments_view segs = parse_path("/doc/libs").value(); + assert( segs.size() == 2 ); //] + boost::ignore_unused(segs); + } + + { + //[snippet_parsing_path_use_case_1 + url_view u("https://www.boost.org/doc/libs/"); + assert(u.host() == "www.boost.org"); + assert(u.path() == "/doc/libs/"); + //] + boost::ignore_unused(u); + } + { + //[snippet_parsing_path_use_case_2 + assert( parse_uri("https://www.boost.org").has_value() ); + assert( parse_uri("https://www.boost.org/").has_value() ); + assert( parse_uri("https://www.boost.org//").has_value() ); + //] + } + { + //[snippet_parsing_path_use_case_3 + assert( url_view("https://www.boost.org").path().empty() ); + //] + } + { + //[snippet_parsing_path_use_case_4 + url_view u("https://www.boost.org/doc@folder/libs:boost"); + assert(u.path() == "/doc@folder/libs:boost"); + //] + boost::ignore_unused(u); + } + { + //[snippet_parsing_path_use_case_5 + url_view u("https://www.boost.org/doc/libs/"); + segments_view segs = u.segments(); + auto it = segs.begin(); + assert(*it++ == "doc"); + assert(*it++ == "libs"); + assert(*it == ""); + //] + boost::ignore_unused(it); + } + { + //[snippet_parsing_path_use_case_6 + url_view u("https://www.boost.org//doc///libs"); + segments_view segs = u.segments(); + auto it = segs.begin(); + assert(*it++ == ""); + assert(*it++ == "doc"); + assert(*it++ == ""); + assert(*it++ == ""); + assert(*it == "libs"); + //] + boost::ignore_unused(it); + } + { + //[snippet_parsing_path_use_case_7 + url_view u("https://www.boost.org//doc/libs/"); + segments_view segs = u.segments(); + auto it = segs.begin(); + assert(*it++ == ""); + assert(*it++ == "doc"); + assert(*it++ == "libs"); + assert(*it == ""); + //] + boost::ignore_unused(it); + } + { + //[snippet_parsing_path_use_case_8 + url_view u("https://doc/libs/"); + assert(u.host() == "doc"); + segments_view segs = u.segments(); + auto it = segs.begin(); + assert(*it++ == "libs"); + assert(*it == ""); + //] + boost::ignore_unused(it); } } @@ -693,31 +867,33 @@ void parsing_query() { { - //[snippet_parsing_query_1 - string_view s = "https://www.example.com/get-customer.php?id=409&name=Joe&individual"; - url_view u = parse_uri(s).value(); - std::cout << u << "\n" - "has query: " << u.has_query() << "\n" - "query: " << u.query() << "\n"; - std::cout << u.params().size() << " parameters\n"; - - for (auto p: u.params()) - { - if (p.has_value) - { - std::cout << - "parameter: <" << p.key << - ", " << p.value << ">\n"; - } else { - std::cout << "parameter: " << p.key << "\n"; - } - } + //[snippet_parsing_query_0 + url_view u("https://www.example.com/get-customer.php?id=409&name=Joe&individual"); + assert( u.query() == "id=409&name=Joe&individual" ); //] } + { + //[snippet_parsing_query_1 + url_view u("https://www.example.com/get-customer.php?id=409&name=Joe&individual"); + params_view ps = u.params(); + assert(ps.size() == 3); + //] + //[snippet_parsing_query_1a + auto it = ps.begin(); + assert((*it).key == "id"); + assert((*it).value == "409"); + ++it; + assert((*it).key == "name"); + assert((*it).value == "Joe"); + ++it; + assert((*it).key == "individual"); + assert(!(*it).has_value); + //] + boost::ignore_unused(it); + } { //[snippet_parsing_query_2 - string_view s = "https://www.example.com/get-customer.php?key-1=value-1&key-2=&key-3&&=value-2"; - url_view u = parse_uri(s).value(); + url_view u("https://www.example.com/get-customer.php?key-1=value-1&key-2=&key-3&&=value-2"); std::cout << u << "\n" "has query: " << u.has_query() << "\n" "encoded query: " << u.encoded_query() << "\n" @@ -738,8 +914,7 @@ parsing_query() } { //[snippet_parsing_query_3 - string_view s = "https://www.example.com/get-customer.php?email=joe@email.com&code=a:2@/!"; - url_view u = parse_uri(s).value(); + url_view u("https://www.example.com/get-customer.php?email=joe@email.com&code=a:2@/!"); std::cout << u << "\n" "has query: " << u.has_query() << "\n" "encoded query: " << u.encoded_query() << "\n" @@ -760,25 +935,20 @@ parsing_query() } { //[snippet_parsing_query_4 - string_view s = "https://www.example.com/get-customer.php?name=joe"; - url_view u = parse_uri(s).value(); + url_view u("https://www.example.com/get-customer.php?name=joe"); std::cout << u << "\n" "query: " << u.query() << "\n"; //] } { //[snippet_parsing_query_5 - string_view s = "https://www.example.com/get-customer.php"; - url_view u = parse_uri(s).value(); - std::cout << u << "\n" - "has query: " << u.has_query() << "\n" - "query: " << u.query() << "\n"; + assert(url_view("https://www.example.com/get-customer.php?").has_query()); + assert(!url_view("https://www.example.com/get-customer.php").has_query()); //] } { //[snippet_parsing_query_6 - string_view s = "https://www.example.com/get-customer.php?name=John%20Doe"; - url_view u = parse_uri(s).value(); + url_view u("https://www.example.com/get-customer.php?name=John%20Doe"); std::cout << u << "\n" "has query: " << u.has_query() << "\n" "encoded query: " << u.encoded_query() << "\n" @@ -787,12 +957,42 @@ parsing_query() } { //[snippet_parsing_query_7 - string_view s = "https://www.example.com/get-customer.php?name=John%26Doe"; - url_view u = parse_uri(s).value(); - std::cout << u << "\n" - "has query: " << u.has_query() << "\n" - "encoded query: " << u.encoded_query() << "\n" - "query: " << u.query() << "\n"; + url_view u("https://www.example.com/get-customer.php?name=John%26Doe"); + assert(u.query() == "name=John&Doe"); + //] + } + { + //[snippet_parsing_query_8 + url_view u("https://www.example.com/get-customer.php?key-1=value-1&key-2=&key-3&&=value-4"); + params_view ps = u.params(); + assert(ps.size() == 5); + //] + //[snippet_parsing_query_8a + auto it = ps.begin(); + assert((*it).key == "key-1"); + assert((*it).value == "value-1"); + //] + //[snippet_parsing_query_8b + ++it; + assert((*it).key == "key-2"); + assert((*it).value == ""); + assert((*it).has_value); + //] + //[snippet_parsing_query_8c + ++it; + assert((*it).key == "key-3"); + assert(!(*it).has_value); + //] + //[snippet_parsing_query_8d + ++it; + assert((*it).key == ""); + assert((*it).value == "value-4"); + //] + } + { + //[snippet_parsing_query_9 + url_view u("https://www.example.com/get-customer.php?email=joe@email.com&code=a:2@/!"); + assert(u.has_query()); //] } } @@ -802,8 +1002,7 @@ parsing_fragment() { { //[snippet_parsing_fragment_1 - string_view s = "https://www.example.com/index.html#section%202"; - url_view u = parse_uri(s).value(); + url_view u("https://www.example.com/index.html#section%202"); std::cout << u << "\n" "has fragment: " << u.has_fragment() << "\n" "fragment: " << u.fragment() << "\n" @@ -812,8 +1011,7 @@ parsing_fragment() } { //[snippet_parsing_fragment_2_a - string_view s = "https://www.example.com/index.html#"; - url_view u = parse_uri(s).value(); + url_view u("https://www.example.com/index.html#"); std::cout << u << "\n" "has fragment: " << u.has_fragment() << "\n" "fragment: " << u.fragment() << "\n"; @@ -821,8 +1019,7 @@ parsing_fragment() } { //[snippet_parsing_fragment_2_b - string_view s = "https://www.example.com/index.html"; - url_view u = parse_uri(s).value(); + url_view u("https://www.example.com/index.html"); std::cout << u << "\n" "has fragment: " << u.has_fragment() << "\n" "fragment: " << u.fragment() << "\n"; @@ -830,13 +1027,30 @@ parsing_fragment() } { //[snippet_parsing_fragment_3 - string_view s = "https://www.example.com/index.html#code%20:a@b?c/d"; - url_view u = parse_uri(s).value(); + url_view u("https://www.example.com/index.html#code%20:a@b?c/d"); std::cout << u << "\n" "has fragment: " << u.has_fragment() << "\n" "fragment: " << u.fragment() << "\n"; //] } + { + //[snippet_parsing_fragment_4 + url_view u("https://www.example.com/index.html#section2"); + assert(u.fragment() == "section2"); + //] + } + { + //[snippet_parsing_fragment_5 + assert(url_view("https://www.example.com/index.html#").has_fragment()); + assert(!url_view("https://www.example.com/index.html").has_fragment()); + //] + } + { + //[snippet_parsing_fragment_6 + url_view u("https://www.example.com/index.html#code%20:a@b?c/d"); + assert(u.fragment() == "code :a@b?c/d"); + //] + } } void @@ -844,34 +1058,29 @@ using_modifying() { { //[snippet_modifying_1 - string_view s = "https://www.example.com"; - url_view u = parse_uri(s).value(); + url_view u("https://www.example.com"); url v(u); //] //[snippet_modifying_2 - std::cout << v << "\n" - "scheme: " << v.scheme() << "\n" - "has authority: " << v.has_authority() << "\n" - "authority: " << v.encoded_authority() << "\n" - "path: " << v.encoded_path() << "\n"; + assert(v.scheme() == "https"); + assert(v.has_authority()); + assert(v.encoded_authority() == "www.example.com"); + assert(v.encoded_path() == ""); //] //[snippet_modifying_3 v.set_host("my website.com"); v.set_path("my file.txt"); v.set_query("id=42&name=John Doe"); - std::cout << v << "\n"; + assert(v.string() == "https://my%20website.com/my%20file.txt?id=42&name=John%20Doe"); //] //[snippet_modifying_4 v.set_scheme("http"); - std::cout << v << "\n"; - //] - - //[snippet_modifying_5 - v.set_host("www.my example.com"); - std::cout << v << "\n"; + assert(v.string() == "http://my%20website.com/my%20file.txt?id=42&name=John%20Doe"); + v.set_encoded_host("www.my%20example.com"); + assert(v.string() == "http://my%20example.com/my%20file.txt?id=42&name=John%20Doe"); //] @@ -1028,34 +1237,40 @@ modifying_path() { { //[snippet_modifying_path_1 - url_view u = parse_uri("https://www.boost.org").value(); + url_view u("https://www.boost.org"); + //] BOOST_TEST_NOT(u.is_path_absolute()); BOOST_TEST_EQ(u.encoded_segments().size(), 0u); } - { //[snippet_modifying_path_2 - url_view u = parse_uri("https://www.boost.org/").value(); + url_view u("https://www.boost.org/"); //] BOOST_TEST(u.is_path_absolute()); BOOST_TEST_EQ(u.encoded_segments().size(), 0u); } + { + //[snippet_modifying_path_1_2 + assert( !url_view("https://www.boost.org").is_path_absolute() ); + assert( url_view("https://www.boost.org/").is_path_absolute() ); + //] + } { //[snippet_modifying_path_3 - url u = parse_uri("https://www.boost.org/./a/../b").value(); + url u("https://www.boost.org/./a/../b"); u.normalize(); + assert(u.string() == "https://www.boost.org/b"); //] BOOST_TEST(u.is_path_absolute()); BOOST_TEST_EQ(u.string(), "https://www.boost.org/b"); BOOST_TEST_EQ(u.encoded_segments().size(), 1u); } - { //[snippet_modifying_path_4 // scheme and a relative path - url_view u = parse_uri("https:path/to/file.txt").value(); + url_view u("https:path/to/file.txt"); //] BOOST_TEST_EQ(u.scheme(), "https"); BOOST_TEST_NOT(u.has_authority()); @@ -1066,7 +1281,7 @@ modifying_path() { //[snippet_modifying_path_5 // scheme and an absolute path - url_view u = parse_uri("https:/path/to/file.txt").value(); + url_view u("https:/path/to/file.txt"); //] BOOST_TEST_EQ(u.scheme(), "https"); BOOST_TEST_NOT(u.has_authority()); @@ -1077,7 +1292,7 @@ modifying_path() { //[snippet_modifying_path_6 // "//path" will be considered the authority component - url_view u = parse_uri("https://path/to/file.txt").value(); + url_view u("https://path/to/file.txt"); //] BOOST_TEST_EQ(u.scheme(), "https"); BOOST_TEST(u.has_authority()); @@ -1085,6 +1300,29 @@ modifying_path() BOOST_TEST_EQ(u.encoded_segments().size(), 2u); } + { + //[snippet_modifying_path_4_5_6 + // scheme and a relative path + url_view u1("https:path/to/file.txt"); + assert(!u1.has_authority()); + assert(!u1.is_path_absolute()); + assert(u1.path() == "path/to/file.txt"); + + // scheme and an absolute path + url_view u2("https:/path/to/file.txt"); + assert(!u2.has_authority()); + assert(u2.is_path_absolute()); + assert(u2.path() == "/path/to/file.txt"); + + // "//path" will be considered the authority component + url_view u3("https://path/to/file.txt"); + assert(u3.has_authority()); + assert(u3.authority().string() == "path"); + assert(u3.is_path_absolute()); + assert(u3.path() == "/to/file.txt"); + //] + } + { //[snippet_modifying_path_7 // only a relative path @@ -1108,6 +1346,21 @@ modifying_path() BOOST_TEST_EQ(u.encoded_segments().size(), 2u); } + { + //[snippet_modifying_path_7_8 + // only a relative path + url_view u1 = parse_uri_reference("path-to/file.txt").value(); + assert(!u1.has_scheme()); + assert(u1.path() == "path-to/file.txt"); + + // "path:" will be considered the scheme component + // instead of a substring of the first segment + url_view u2 = parse_uri_reference("path:to/file.txt").value(); + assert(u2.has_scheme()); + assert(u2.path() == "to/file.txt"); + //] + } + { //[snippet_modifying_path_9 // "path" should not become the authority component @@ -1131,13 +1384,20 @@ modifying_path() BOOST_TEST_NOT(u.is_path_absolute()); BOOST_TEST_EQ(u.encoded_segments().size(), 2u); } - + { + //[snippet_modifying_path_9_10 + url u1("https:path/to/file.txt" ); + u1.set_encoded_path("//path/to/file.txt"); + assert(u1.string() == "https:/.//path/to/file.txt"); + //] + } { //[snippet_modifying_path_11 // should not insert as "pathto/file.txt" url u = parse_uri_reference("to/file.txt").value(); segments segs = u.segments(); segs.insert(segs.begin(), "path"); + assert(u.string() == "path/to/file.txt"); //] BOOST_TEST_NOT(u.has_scheme()); BOOST_TEST_NOT(u.has_authority()); @@ -1161,7 +1421,8 @@ public: { ignore_unused(&using_url_views); ignore_unused(&using_urls); - ignore_unused(&parsing_urls); + parsing_urls(); + parsing_components(); ignore_unused(&parsing_scheme); ignore_unused(&parsing_authority); ignore_unused(&parsing_path);