2
0
mirror of https://github.com/boostorg/url.git synced 2026-02-14 01:02:17 +00:00
This commit is contained in:
Vinnie Falco
2021-09-11 18:43:28 -07:00
parent b57db1f14c
commit ad308be3fb
24 changed files with 1081 additions and 669 deletions

View File

@@ -124,7 +124,7 @@ parse_string(
Tn&&... tn)
{
error_code ec;
if(parse(s, ec,
if(parse_string(s, ec,
std::forward<T0>(t0),
std::forward<Tn>(tn)...))
{

View File

@@ -20,7 +20,7 @@ namespace detail {
BOOST_URL_DECL void BOOST_NORETURN throw_bad_alloc(source_location const& loc);
BOOST_URL_DECL void BOOST_NORETURN throw_invalid_argument(char const* what, source_location const& loc);
//BOOST_URL_DECL void BOOST_NORETURN throw_length_error(char const* what, source_location const& loc);
BOOST_URL_DECL void BOOST_NORETURN throw_length_error(char const* what, source_location const& loc);
BOOST_URL_DECL void BOOST_NORETURN throw_out_of_range(source_location const& loc);
BOOST_URL_DECL void BOOST_NORETURN throw_system_error(error_code const& ec, source_location const& loc);
//BOOST_URL_DECL void BOOST_NORETURN throw_system_error(error e, source_location const& loc);

View File

@@ -27,7 +27,6 @@ throw_bad_alloc(
std::bad_alloc(), loc);
}
#if 0
void
throw_length_error(
char const* what,
@@ -36,7 +35,6 @@ throw_length_error(
throw_exception(
std::length_error(what), loc);
}
#endif
void
throw_invalid_argument(

View File

@@ -85,7 +85,7 @@ apply_authority(
// leading "//" for authority
p.resize(
part::id_user,
u.username.str.size() + 2);
u.user.str.size() + 2);
if(u.password.has_value())
{

View File

@@ -11,6 +11,7 @@
#define BOOST_URL_DETAIL_PARTS_HPP
#include <boost/url/host_type.hpp>
#include <boost/url/scheme.hpp>
#include <cstdint>
#include <cstring>
@@ -43,7 +44,17 @@ struct parts
std::uint16_t port_number = 0;
urls::host_type host_type =
urls::host_type::none;
urls::scheme scheme =
urls::scheme::none;
// size excluding null
std::size_t
len() const noexcept
{
return offset[id_end];
}
// size of id
std::size_t
len(int id) const noexcept
{
@@ -51,6 +62,7 @@ struct parts
offset[id];
}
// size of [begin, end)
std::size_t
len(
int begin,
@@ -62,6 +74,7 @@ struct parts
offset[begin];
}
// return id as string
string_view
get(int id,
char const* s) const noexcept
@@ -72,6 +85,7 @@ struct parts
offset[id] };
}
// return [begin, end) as string
string_view
get(int begin,
int end,
@@ -83,6 +97,7 @@ struct parts
offset[begin] };
}
// change id to size n
void
resize(
int id,
@@ -100,7 +115,8 @@ struct parts
int id,
std::size_t n) noexcept
{
BOOST_ASSERT(id < detail::id_end - 1);
BOOST_ASSERT(
id < detail::id_end - 1);
BOOST_ASSERT(n <= len(id));
offset[id + 1] = offset[id] +
static_cast<std::size_t>(n);

View File

@@ -138,14 +138,9 @@ pct_decode_size(
++n;
continue;
}
if(opt.non_normal_is_error)
{
// reserved character in input
ec = error::illegal_reserved_char;
break;
}
++n;
++it;
// reserved character in input
ec = error::illegal_reserved_char;
break;
}
return n;
}

View File

@@ -23,6 +23,9 @@ string_to_scheme(
using bnf::ascii_tolower;
switch(s.size())
{
case 0: // none
return scheme::none;
case 2: // ws
if( ascii_tolower(s[0]) == 'w' &&
ascii_tolower(s[1]) == 's')
@@ -97,11 +100,11 @@ to_string(scheme s) noexcept
case scheme::https: return "https";
case scheme::ws: return "ws";
case scheme::wss: return "wss";
case scheme::none: return {};
default:
break;
}
return "unknown";
return "<unknown>";
}
} // urls

View File

@@ -12,11 +12,16 @@
#include <boost/url/url.hpp>
#include <boost/url/error.hpp>
#include <boost/url/pct_encoding.hpp>
#include <boost/url/scheme.hpp>
#include <boost/url/url_view.hpp>
#include <boost/url/bnf/parse.hpp>
#include <boost/url/detail/except.hpp>
#include <boost/url/detail/pct_encoding.hpp>
#include <boost/url/rfc/char_sets.hpp>
#include <boost/url/rfc/scheme_bnf.hpp>
#include <cstring>
#include <iostream>
#include <stdexcept>
#include <utility>
@@ -70,21 +75,21 @@ copy(
char const* s,
detail::parts const& pt)
{
auto n = pt.len(
id_scheme, id_end);
auto n = pt.len();
if(n == 0 && ! s_)
return;
if(cap_ < n)
{
auto cap = growth_impl(
cap_, n);
auto p = alloc_impl(cap);
auto s1 = alloc_impl(cap);
if(s_)
free_impl(s_);
s_ = p;
s_ = s1;
cap_ = cap;
}
std::memcpy(s_, s, n);
if(n != 0)
std::memcpy(s_, s, n);
s_[n] = 0;
pt_ = pt;
}
@@ -109,19 +114,24 @@ growth_impl(
std::size_t cap,
std::size_t new_size)
{
if(new_size >= std::size_t(-1))
detail::throw_bad_alloc(
if(new_size > max_size())
detail::throw_length_error(
"url::reserve",
BOOST_CURRENT_LOCATION);
BOOST_ASSERT(new_size > cap);
if(cap == 0)
{
// minimum
if( new_size < 24)
return 24;
return new_size;
}
// 50% growth factor
auto n = cap + (cap >> 1);
auto n = cap + cap / 2;
if(n < cap)
{
// overflow
return std::size_t(-1)
- 1; // for null
return max_size();
}
if(n < new_size)
return new_size;
@@ -198,9 +208,7 @@ operator=(url_view const& u)
}
//------------------------------------------------
//************************************************
//************************************************
//************************************************
//------------------------------------------------
//------------------------------------------------
//------------------------------------------------
@@ -213,8 +221,7 @@ bool
url::
empty() const noexcept
{
return len(
id_scheme, id_end) == 0;
return pt_.len() == 0;
}
//------------------------------------------------
@@ -262,6 +269,13 @@ scheme() const noexcept
return s;
}
urls::scheme
url::
scheme_id() const noexcept
{
return pt_.scheme;
}
//----------------------------------------------------------
//
// authority
@@ -329,7 +343,7 @@ encoded_userinfo() const noexcept
string_view
url::
encoded_username() const noexcept
encoded_user() const noexcept
{
auto s = get(id_user);
if(! s.empty())
@@ -585,9 +599,7 @@ encoded_fragment() const noexcept
}
//------------------------------------------------
//************************************************
//************************************************
//************************************************
//------------------------------------------------
//------------------------------------------------
string_view
@@ -688,36 +700,290 @@ set_encoded_origin(
//
//------------------------------------------------
void
url::
assert_scheme() const noexcept
{
BOOST_ASSERT(
(len(id_scheme) == 0) ||
(len(id_scheme) > 1 &&
get(id_scheme).ends_with(':')));
}
url&
url::
set_scheme(
string_view s)
set_scheme(string_view s)
{
#if 0
if(s.empty())
{
resize_impl(id_scheme, 0);
return *this;
}
scheme_bnf b;
bnf::parse(s, b);
auto const n = s.size();
auto const dest =
resize_impl(id_scheme, n + 1);
s.copy(dest, n);
dest[n] = ':';
#endif
set_scheme_impl(
s, string_to_scheme(s));
return *this;
}
#if 0
url&
url::
set_scheme(urls::scheme id)
{
if(id == urls::scheme::unknown)
detail::throw_invalid_argument(
"url::set_scheme",
BOOST_CURRENT_LOCATION);
if(id == urls::scheme::none)
{
set_scheme_impl("", id);
return *this;
}
set_scheme_impl(
to_string(id), id);
return *this;
}
void
url::
set_scheme_impl(
string_view s,
urls::scheme id)
{
assert_scheme();
if(s.empty())
{
if(len(id_scheme) == 0)
return;
// remove scheme
// The complicated case is changing
// path-rootless to path-noscheme
bool const need_dot = [this]
{
if(has_authority())
return false;
auto s = get(id_path);
if(s.empty())
return false;
if(s.starts_with('/'))
return false;
auto const p = static_cast<
url const*>(this)->path();
BOOST_ASSERT(! p.empty());
auto it = p.begin();
s = it->encoded_segment();
return s.find_first_of(':') !=
string_view::npos;
}();
if(! need_dot)
{
// just remove the scheme
resize_impl(id_scheme, 0);
pt_.scheme = id;
assert_scheme();
return;
}
// remove the scheme but add "./"
// to the beginning of the path
auto dest = resize_impl(
id_scheme, 2);
dest[0] = '.';
dest[1] = '/';
pt_.split(id_scheme, 0);
pt_.scheme = id;
assert_scheme();
return;
}
scheme_bnf b;
error_code ec;
bnf::parse_string(s, ec, b);
if(ec.failed())
detail::throw_invalid_argument(
"url::set_scheme",
BOOST_CURRENT_LOCATION);
auto n = s.size();
auto dest = resize_impl(
id_scheme, n + 1);
s.copy(dest, n);
dest[n] = ':';
pt_.scheme = id;
assert_scheme();
return;
}
//------------------------------------------------
//
// authority
//
//------------------------------------------------
void
url::
assert_userinfo() const noexcept
{
BOOST_ASSERT(
len(id_user) == 0 ||
get(id_user).starts_with("//"));
BOOST_ASSERT(
len(id_pass) == 0 ||
get(id_user).starts_with("//"));
BOOST_ASSERT(
(len(id_pass) == 0) ||
(len(id_pass) == 1 &&
get(id_pass) == "@") ||
(len(id_pass) == 2 &&
get(id_pass) == ":@") ||
(len(id_pass) > 2 &&
get(id_pass).starts_with(':') &&
get(id_pass).ends_with('@')));
}
//------------------------------------------------
char*
url::
set_user_impl(std::size_t n)
{
assert_userinfo();
if(len(id_pass) != 0)
{
// keep "//"
auto dest = resize_impl(
id_user, 2 + n);
assert_userinfo();
return dest + 2;
}
// add authority
auto dest = resize_impl(
id_user, 2 + n + 1);
pt_.split(id_user, 2 + n);
dest[0] = '/';
dest[1] = '/';
dest[2 + n] = '@';
assert_userinfo();
return dest + 2;
}
url&
url::
clear_user() noexcept
{
assert_userinfo();
if(len(id_user) == 0)
{
// no authority
}
else if(len(id_pass) == 1)
{
// no password, remove '@'
resize_impl(
id_user, id_host, 2);
}
else
{
// keep password
resize_impl(id_user, 2);
}
assert_userinfo();
return *this;
}
url&
url::
set_user(string_view s)
{
masked_char_set<
unsub_char_mask> cs;
auto const n =
pct_encode_size(s, cs);
auto dest = set_user_impl(n);
dest = detail::pct_encode(
dest, get(id_pass).data(),
s, {}, cs);
BOOST_ASSERT(dest ==
get(id_pass).data());
assert_userinfo();
return *this;
}
url&
url::
set_encoded_user(
string_view s)
{
if(s.empty())
{
// remove user
set_user_impl(0);
return *this;
}
error_code ec;
masked_char_set<
unsub_char_mask> cs;
pct_decode_size(s, ec, cs);
if(ec)
detail::throw_invalid_argument(
"url::set_encoded_user",
BOOST_CURRENT_LOCATION);
auto dest = set_user_impl(s.size());
BOOST_ASSERT(dest != nullptr);
std::memcpy(dest, s.data(), s.size());
return *this;
}
//------------------------------------------------
char*
url::
set_password_impl(
std::size_t n)
{
assert_userinfo();
if(len(id_user) != 0)
{
// already have authority
auto const dest = resize_impl(
id_pass, 1 + n + 1);
dest[0] = ':';
dest[n + 1] = '@';
return dest + 1;
}
// add authority
auto const dest =
resize_impl(
id_user, id_host,
2 + 1 + n + 1);
pt_.split(id_user, 2);
dest[0] = '/';
dest[1] = '/';
dest[2] = ':';
dest[2 + n + 1] = '@';
assert_userinfo();
return dest + 3;
}
url&
url::
clear_password() noexcept
{
assert_userinfo();
auto const n =
len(id_pass);
if(n == 0)
return *this;
if(len(id_user) == 2)
{
// remove '@'
resize_impl(id_pass, 0);
return *this;
}
// retain '@'
auto dest =
resize_impl(id_pass, 1);
dest[0] = '@';
return *this;
}
#if 0
url&
url::
set_encoded_authority(
@@ -803,246 +1069,6 @@ set_encoded_userinfo(
return *this;
}
url&
url::
set_userinfo_part(
string_view s)
{
if(! s.empty())
{
if(s.back() != '@')
invalid_part::raise();
s.remove_suffix(1);
}
return set_encoded_userinfo(s);
}
url&
url::
set_user(
string_view s)
{
if(s.empty())
{
if(pt_.len(
id_user) == 0)
return *this;
BOOST_ASSERT(pt_.get(
id_pass, s_).back() == '@');
BOOST_ASSERT(pt_.get(
id_user, s_).size() >= 2);
BOOST_ASSERT(pt_.get(
id_user, s_)[0] == '/');
BOOST_ASSERT(pt_.get(
id_user, s_)[1] == '/');
if(pt_.len(
id_pass) == 1)
{
// remove '@'
resize_impl(
id_user,
id_host, 2);
}
else
{
resize_impl(id_user, 2);
}
return *this;
}
auto const e =
detail::userinfo_nc_pct_set();
if(pt_.len(
id_pass) != 0)
{
BOOST_ASSERT(pt_.get(
id_pass, s_).back() == '@');
// preserve "//"
auto const dest = resize_impl(
id_user,
2 + e.encoded_size(s));
e.encode(dest + 2, s);
return *this;
}
auto const n = e.encoded_size(s);
auto const dest = resize_impl(
id_user, 2 + n + 1);
dest[0] = '/';
dest[1] = '/';
dest[2 + n] = '@';
pt_.split(
id_user,
2 + n);
e.encode(dest + 2, s);
return *this;
}
url&
url::
set_encoded_user(
string_view s)
{
if(s.empty())
return set_user(s);
auto const e =
detail::userinfo_nc_pct_set();
e.validate(s);
auto const n = s.size();
if(pt_.len(id_pass) != 0)
{
BOOST_ASSERT(pt_.get(
id_pass, s_).back() == '@');
// preserve "//"
auto const dest = resize_impl(
id_user, 2 + n);
s.copy(dest + 2, n);
return *this;
}
// add '@'
auto const dest = resize_impl(
id_user,
2 + n + 1);
dest[0] = '/';
dest[1] = '/';
dest[2 + n] = '@';
pt_.split(
id_user,
2 + n);
s.copy(dest + 2, n);
return *this;
}
url&
url::
set_password(
string_view s)
{
if(s.empty())
{
auto const n = pt_.len(
id_pass);
if(n == 0)
return *this;
BOOST_ASSERT(pt_.get(
id_pass, s_).back() == '@');
BOOST_ASSERT(pt_.get(
id_user, s_).size() >= 2);
BOOST_ASSERT(pt_.get(
id_user, s_)[0] == '/');
BOOST_ASSERT(pt_.get(
id_user, s_)[1] == '/');
if(pt_.len(id_user) == 2)
{
// remove '@'
resize_impl(id_pass, 0);
return *this;
}
// retain '@'
*resize_impl(id_pass, 1) = '@';
return *this;
}
auto const e =
detail::userinfo_pct_set();
auto const n =
e.encoded_size(s);
if(pt_.len(id_user) != 0)
{
auto const dest = resize_impl(
id_pass, 1 + n + 1);
dest[0] = ':';
dest[n + 1] = '@';
e.encode(dest + 1, s);
return *this;
}
auto const dest = resize_impl(
id_user,
id_host,
2 + 1 + n + 1);
dest[0] = '/';
dest[1] = '/';
dest[2] = ':';
dest[2 + n + 1] = '@';
e.encode(dest + 3, s);
pt_.split(id_user, 2);
return *this;
}
url&
url::
set_encoded_password(
string_view s)
{
if(s.empty())
return set_password(s);
auto const e =
detail::userinfo_pct_set();
if(s[0] == ':')
invalid_part::raise();
e.validate(s);
auto const n = s.size();
if(pt_.len(id_user) != 0)
{
auto const dest = resize_impl(
id_pass, 1 + n + 1);
dest[0] = ':';
dest[n + 1] = '@';
s.copy(dest + 1, n);
return *this;
}
auto const dest = resize_impl(
id_user,
id_host,
2 + 1 + n + 1);
dest[0] = '/';
dest[1] = '/';
dest[2] = ':';
dest[2 + n + 1] = '@';
s.copy(dest + 3, n);
pt_.split(id_user, 2);
return *this;
}
url&
url::
set_password_part(
string_view s)
{
if(s.empty())
return set_password(s);
if(s.size() == 1)
{
if(s.front() != ':')
invalid_part::raise();
if(pt_.len(
id_user) != 0)
{
auto const dest = resize_impl(
id_pass, 2);
dest[0] = ':';
dest[1] = '@';
return *this;
}
auto const dest = resize_impl(
id_user,
id_host, 4);
dest[0] = '/';
dest[1] = '/';
dest[2] = ':';
dest[3] = '@';
pt_.split(
id_user, 2);
}
set_encoded_password(
s.substr(1));
return *this;
}
//------------------------------------------------
//
// host
@@ -2060,6 +2086,7 @@ operator[](string_view key) const
}
//------------------------------------------------
#endif
void
url::
@@ -2068,17 +2095,19 @@ resize_impl(
{
if(new_size > cap_)
{
#if 0
// reallocate
auto p = static_cast<char*>(
sp_->allocate(new_size + 1));
if(s_)
{
BOOST_ASSERT(cap_ != 0);
std::memcpy(p, s_, size() + 1);
std::memcpy(p, s_, pt_.len() + 1);
sp_->deallocate(s_, cap_ + 1, 1);
}
s_ = p;
cap_ = new_size;
#endif
}
s_[new_size] = '\0';
@@ -2100,81 +2129,96 @@ resize_impl(
int last,
std::size_t new_len)
{
auto const len =
auto const n0 =
pt_.len(first, last);
if(new_len == 0 && len == 0)
if(new_len == 0 && n0 == 0)
{
// VFALCO This happens
//BOOST_ASSERT(s_ != nullptr);
BOOST_ASSERT(s_ != nullptr);
return s_ + pt_.offset[first];
}
if(new_len <= len)
if(new_len <= n0)
{
// shrinking
auto const n = static_cast<
std::size_t>(len - new_len);
auto const pos = pt_.offset[last];
std::size_t n = n0 - new_len;
auto const pos =
pt_.offset[last];
// adjust chars
std::memmove(
s_ + pos - n,
s_ + pos,
pt_.offset[
id_end] - pos + 1);
// collapse [first, last)
for(auto i = first + 1;
i < last; ++i)
i < last; ++i)
pt_.offset[i] =
pt_.offset[last] - n;
// shift [last, end) left
for(auto i = last;
i <= id_end; ++i)
i <= id_end; ++i)
pt_.offset[i] -= n;
s_[size()] = '\0';
s_[pt_.len()] = '\0';
return s_ + pt_.offset[first];
}
// growing
auto const n = static_cast<
std::size_t>(new_len - len);
std::size_t n = new_len - n0;
// check for exceeding max size
if(n > (
(std::size_t)-1)/*max_size()*/ - size())
too_large::raise();
if(n > max_size() - pt_.len())
detail::throw_length_error(
"url::resize",
BOOST_CURRENT_LOCATION);
if(cap_ < size() + n)
if(cap_ < pt_.len() + n)
{
// reallocate
auto p = static_cast<char*>(
sp_->allocate(cap_ + n + 1));
auto new_cap = growth_impl(
cap_, pt_.len() + n);
auto s1 = alloc_impl(new_cap);
if(s_)
{
BOOST_ASSERT(cap_ != 0);
std::memcpy(p, s_, size() + 1);
sp_->deallocate(s_, cap_ + 1, 1);
std::memcpy(s1, s_, pt_.len() + 1);
free_impl(s_);
}
s_ = p;
cap_ = cap_ + n;
s_ = s1;
cap_ = new_cap;
}
auto const pos =
pt_.offset[last];
// adjust chars
std::memmove(
s_ + pos + n,
s_ + pos,
pt_.offset[id_end] -
pos + 1);
// collapse [first, last)
for(auto i = first + 1;
i < last; ++i)
pt_.offset[i] =
pt_.offset[last] + n;
// shift [last, end) right
for(auto i = last;
i <= id_end; ++i)
pt_.offset[i] += n;
s_[size()] = '\0';
s_[pt_.len()] = '\0';
return s_ + pt_.offset[first];
}
#endif
//------------------------------------------------
std::ostream&
operator<<(
std::ostream& os,
url const& u)
{
auto const s = u.str();
os.write(s.data(), s.size());
return os;
}
} // urls
} // boost

View File

@@ -96,19 +96,11 @@ bool
url_view::
empty() const noexcept
{
return len(
id_scheme, id_end) == 0;
return pt_.len() == 0;
}
//------------------------------------------------
string_view
url_view::
str() const
{
return get(id_scheme, id_end);
}
string_view
url_view::
encoded_origin() const noexcept
@@ -152,6 +144,13 @@ scheme() const noexcept
return s;
}
urls::scheme
url_view::
scheme_id() const noexcept
{
return pt_.scheme;
}
//----------------------------------------------------------
//
// authority
@@ -219,7 +218,7 @@ encoded_userinfo() const noexcept
string_view
url_view::
encoded_username() const noexcept
encoded_user() const noexcept
{
auto s = get(id_user);
if(! s.empty())
@@ -472,6 +471,17 @@ encoded_fragment() const noexcept
return s.substr(1);
}
//------------------------------------------------
//------------------------------------------------
//------------------------------------------------
string_view
url_view::
str() const
{
return get(id_scheme, id_end);
}
//------------------------------------------------
url_view
@@ -487,6 +497,7 @@ parse_uri(
detail::parts p;
// scheme
p.scheme = t.scheme.id;
p.resize(
detail::part::id_scheme,
t.scheme.str.size() + 1);

View File

@@ -54,11 +54,6 @@ namespace urls {
parameter is omitted, the default options
will be used.
@param a An optional allocator the returned
string will use. If this parameter is omitted,
the default allocator is used, and the return
type of the function becomes `std::string`.
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-2.1">
2.1. Percent-Encoding (rfc3986)</a>

View File

@@ -33,7 +33,7 @@ parse(
pct_encoded_bnf<
masked_char_set<
unsub_char_mask>>{
t.username}))
t.user}))
return false;
if( it != end &&
*it == ':')

View File

@@ -23,9 +23,9 @@ namespace urls {
@par BNF
@code
userinfo = username [ ":" [ password ] ]
userinfo = user [ ":" [ password ] ]
username = *( unreserved / pct-encoded / sub-delims )
user = *( unreserved / pct-encoded / sub-delims )
password = *( unreserved / pct-encoded / sub-delims / ":" )
@endcode
@@ -35,7 +35,7 @@ namespace urls {
struct userinfo_bnf
{
string_view str;
pct_encoded_str username;
pct_encoded_str user;
optional<pct_encoded_str> password;
BOOST_URL_DECL

View File

@@ -20,9 +20,13 @@ namespace urls {
*/
enum class scheme : unsigned char
{
/** Indicates that no scheme is present
*/
none = 0,
/** Indicates the scheme is not a well-known scheme
*/
unknown = 0,
unknown,
/** File Transfer Protocol (FTP)

View File

@@ -12,6 +12,7 @@
#include <boost/url/detail/config.hpp>
#include <boost/url/url.hpp>
#include <boost/static_assert.hpp>
namespace boost {
namespace urls {
@@ -73,6 +74,9 @@ class static_url
{
char buf_[Capacity + 1];
BOOST_STATIC_ASSERT(
Capacity < max_size());
public:
~static_url()
{

View File

@@ -15,9 +15,11 @@
#include <boost/url/ipv6_address.hpp>
#include <boost/url/path_view.hpp>
#include <boost/url/query_params_view.hpp>
#include <boost/url/scheme.hpp>
#include <boost/url/detail/parts.hpp>
#include <boost/url/detail/pct_encoding.hpp>
#include <cstdint>
#include <iosfwd>
#include <memory>
#include <string>
#include <utility>
@@ -46,7 +48,9 @@ class url_view;
@li Functions which throw offer the strong
exception safety guarantee.
@see @li <a href="https://tools.ietf.org/html/rfc3986">Uniform Resource Identifier (URI): Generic Syntax</a>
@par Specification
@li <a href="https://tools.ietf.org/html/rfc3986">
Uniform Resource Identifier (URI): Generic Syntax (rfc3986)</a>
*/
class BOOST_SYMBOL_VISIBLE url
{
@@ -140,12 +144,26 @@ public:
url&
operator=(url_view const& u);
//--------------------------------------------
//--------------------------------------------
//--------------------------------------------
//--------------------------------------------
//
// classification
//
//--------------------------------------------
/** An integer for the maximum size string that can be represented
*/
static
constexpr
std::size_t
max_size()
{
return 0x7ffffffe;
}
/** Return true if the URL is empty
An empty URL is a relative-ref with
@@ -170,17 +188,35 @@ public:
//--------------------------------------------
/** Return true if a scheme exists
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.1">
3.1. Scheme (rfc3986)</a>
*/
BOOST_URL_DECL
bool
has_scheme() const noexcept;
/** Return the scheme
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.1">
3.1. Scheme (rfc3986)</a>
*/
BOOST_URL_DECL
string_view
scheme() const noexcept;
/** Return a known-scheme constant if a scheme is present
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.1">
3.1. Scheme (rfc3986)</a>
*/
BOOST_URL_DECL
urls::scheme
scheme_id() const noexcept;
//--------------------------------------------
//
// authority
@@ -222,7 +258,7 @@ public:
/** Return the userinfo if it exists, or an empty string
Returns the userinfo of the URL as an encoded
string. The userinfo includes the username and
string. The userinfo includes the user and
password, with a colon separating the components
if the password is not empty.
@@ -263,11 +299,11 @@ public:
encoded_userinfo(), {}, a);
}
/** Return the username if it exists, or an empty string
/** Return the user if it exists, or an empty string
This function returns the username portion of
This function returns the user portion of
the userinfo if present, as an encoded string.
The username portion is defined by all of the
The user portion is defined by all of the
characters in the userinfo up to but not
including the first colon (':"), or the
entire userinfo if no colon is present.
@@ -278,13 +314,13 @@ public:
*/
BOOST_URL_DECL
string_view
encoded_username() const noexcept;
encoded_user() const noexcept;
/** Return the username if it exists, or an empty string
/** Return the user if it exists, or an empty string
This function returns the username portion of
This function returns the user portion of
the userinfo if present, as a decoded string.
The username portion is defined by all of the
The user portion is defined by all of the
characters in the userinfo up to but not
including the first colon (':"), or the
entire userinfo if no colon is present.
@@ -306,11 +342,11 @@ public:
class Allocator =
std::allocator<char>>
string_type<Allocator>
username(
user(
Allocator const& a = {}) const
{
return detail::pct_decode_unchecked(
encoded_username(), {}, a);
encoded_user(), {}, a);
}
/** Return true if a password exists
@@ -651,8 +687,6 @@ public:
pt_.decoded[id_frag], {}, a);
}
//--------------------------------------------
//--------------------------------------------
//--------------------------------------------
//--------------------------------------------
//--------------------------------------------
@@ -697,52 +731,16 @@ public:
void
reserve(std::size_t n);
//------------------------------------------------------
/** Set the URL.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@param s The URL to set. The contents must
meet the syntactic requirements of a
<em>URI-reference</em>.
@throw std::exception parsing error.
*/
BOOST_URL_DECL
url&
set_encoded_url(
string_view s);
/** Set the origin to the specified value.
The origin consists of the everything from the
beginning of the URL up to but not including
the path.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@param s The origin to set. Special characters
must be percent-encoded, or an exception is
thrown.
*/
BOOST_URL_DECL
url&
set_encoded_origin(
string_view s);
//------------------------------------------------------
//
// scheme
//
//------------------------------------------------------
private:
void assert_scheme() const noexcept;
public:
/** Set the scheme.
This function sets the scheme to the specified
@@ -756,157 +754,137 @@ public:
contain a valid scheme. A trailing colon is
automatically added.
@par ABNF
@par Example
@code
url u;
u.set_scheme( "http" ); // produces "http:"
u.set_scheme( "" ); // produces ""
u.set_scheme( "1forall"); // throws, invalid scheme
@endcode
@par BNF
@code
scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
@endcode
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@return A reference to the object, for chaining.
@param s The scheme to set. This string must
not include a trailing colon, otherwise an
exception is thrown.
@throw std::exception invalid scheme.
@throw std::invalid_argument invalid scheme.
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.1">
3.1. Scheme (rfc3986)</a>
*/
BOOST_URL_DECL
url&
set_scheme(string_view s);
/** Set the scheme.
This function sets the scheme to the specified
string:
@li If `id` is @ref scheme::none, any existing
scheme is removed along with the trailing
colon (':'), otherwise:
@li The scheme is set to `id`, which must
not be equal to @ref scheme::unknown.
@par Example
@code
url u;
u.set_scheme( scheme::http ); // produces "http:"
u.set_scheme( scheme::none ); // produces ""
u.set_scheme( scheme::unknown); // throws, invalid scheme
@endcode
@par BNF
@code
scheme = ALPHA *( ALPHA / DIGIT / "+" / "-" / "." )
@endcode
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@return A reference to the object, for chaining.
@param id The scheme to set.
@throw std::invalid_argument `id == scheme::unknown`
*/
BOOST_URL_DECL
url&
set_scheme(urls::scheme id);
private:
void set_scheme_impl(string_view s, urls::scheme id);
public:
//------------------------------------------------------
//
// authority
//
//------------------------------------------------------
/** Set the authority.
private:
void assert_userinfo() const noexcept;
char* set_user_impl(std::size_t n);
public:
/** Clear the user.
If a user is present, it is removed. If the
user was the only component present in the
userinfo, then the userinfo is removed without
removing the authority.
@par Exception Safety
Does not throw.
Strong guarantee.
Calls to allocate may throw.
@return A reference to the object, for chaining.
@param s The authority to set. This string
must meed the syntactic requirements for
the components of the authority, otherwise
an exception is thrown.
@throw std::exception invalid authority.
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.1">
3.2.1. User Information (rfc3986)</a>
*/
BOOST_URL_DECL
url&
set_encoded_authority(
string_view s);
//------------------------------------------------------
//
// userinfo
//
//------------------------------------------------------
/** Set the userinfo.
Sets the userinfo of the URL to the given
encoded string:
@li If the string is empty, the userinfo is
cleared, else
@li If the string is not empty, then the userinfo
is set to the given string. The user is set to
the characters up to the first colon if any,
while the password is set to the remaining
characters if any.
If the URL previously did not have an authority
(@ref has_authority returns `false`), a double
slash ("//") is prepended to the userinfo.
The string must meet the syntactic requirements
of <em>userinfo</em> otherwise an exception is
thrown.
@par ABNF
@code
userinfo = [ [ user ] [ ':' password ] ]
user = *( unreserved / pct-encoded / sub-delims )
password = *( unreserved / pct-encoded / sub-delims / ":" )
@endcode
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@param s The string to set.
*/
BOOST_URL_DECL
url&
set_encoded_userinfo(
string_view s);
/** Set the userinfo.
Sets the userinfo of the URL to the given
encoded string:
@li If the string is empty, the userinfo is
cleared, else
@li If the string is not empty, then the userinfo
is set to the given string. The user is set to
the characters up to the first colon if any,
while the password is set to the remaining
characters if any.
If the URL previously did not have an authority
(@ref has_authority returns `false`), a double
slash ("//") is prepended to the userinfo.
The string must meet the syntactic requirements
of <em>userinfo-part</em> otherwise an exception
is thrown.
@par ABNF
@code
userinfo-part = [ [ user ] [ ':' password ] '@' ]
user = *( unreserved / pct-encoded / sub-delims )
password = *( unreserved / pct-encoded / sub-delims / ":" )
@endcode
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@param s The string to set.
*/
BOOST_URL_DECL
url&
set_userinfo_part(
string_view s);
clear_user() noexcept;
/** Set the user.
The user is set to the specified string,
replacing any previous user:
replacing any previous user. If a userinfo
was not present it is added, even if the
user string is empty. The resulting URL
will have an authority if it did not have
one previously.
@li If the string is empty, the user is cleared.
@li If the string is not empty then the
user is set to the new string.
Any special or reserved characters in the
string are automatically percent-encoded.
If the URL previously did not have an authority
(@ref has_authority returns `false`), a double
slash ("//") is prepended to the userinfo.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@return A reference to the object, for chaining.
@param s The string to set. This string may
contain any characters, including nulls.
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.2.1">
3.2.1. User Information (rfc3986)</a>
*/
BOOST_URL_DECL
url&
@@ -915,28 +893,25 @@ public:
/** Set the user.
The user is set to the specified encoded
string, replacing any previous user:
The user is set to the specified string,
replacing any previous user. If a userinfo
was not present it is added, even if the
user string is empty. The resulting URL
will have an authority if it did not have
one previously.
@li If the string is empty, the user is cleared.
The string must be a valid percent-encoded
string for the user field, otherwise an
exception is thrown.
@li If the string is not empty then the
user is set to the given string.
If the URL previously did not have an authority
(@ref has_authority returns `false`), a double
slash ("//") is prepended to the userinfo.
The string must meet the syntactic requirements
of <em>user</em> otherwise an exception is
thrown.
@li
@par ABNF
@par BNF
@code
user = *( unreserved / pct-encoded / sub-delims )
@endcode
@par Exception Safety
@return A reference to the object, for chaining.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@@ -947,6 +922,14 @@ public:
set_encoded_user(
string_view s);
private:
char* set_password_impl(std::size_t n);
public:
BOOST_URL_DECL
url&
clear_password() noexcept;
/** Set the password.
This function sets the password to the specified
@@ -1012,28 +995,69 @@ public:
set_encoded_password(
string_view s);
/** Set the password.
/** Set the origin to the specified value.
The password part is set to the encoded string
`s`, replacing any previous password:
The origin consists of the everything from the
beginning of the URL up to but not including
the path.
@li If the string is empty, the password is
cleared, and the first occurring colon (':') is
removed from the userinfo if present, otherwise
@par Exception Safety
@li If ths string is not empty then the password
is set to the new string, which must include a
leading colon.
Strong guarantee.
Calls to allocate may throw.
@param s The origin to set. Special characters
must be percent-encoded, or an exception is
thrown.
*/
BOOST_URL_DECL
url&
set_encoded_origin(
string_view s);
/** Set the authority.
@par Exception Safety
Strong guarantee.
Calls to allocate may throw.
@param s The authority to set. This string
must meed the syntactic requirements for
the components of the authority, otherwise
an exception is thrown.
@throw std::invalid_argument invalid authority
*/
BOOST_URL_DECL
url&
set_encoded_authority(
string_view s);
/** Set the userinfo.
Sets the userinfo of the URL to the given
encoded string:
@li If the string is empty, the userinfo is
cleared, else
@li If the string is not empty, then the userinfo
is set to the given string. The user is set to
the characters up to the first colon if any,
while the password is set to the remaining
characters if any.
If the URL previously did not have an authority
(@ref has_authority returns `false`), a double
slash ("//") is prepended to the userinfo.
The string must meet the syntactic requirements
of <em>password-part</em> otherwise an exception is
of <em>userinfo</em> otherwise an exception is
thrown.
@par ANBF
@par BNF
@code
password-part = [ ':' *( unreserved / pct-encoded / sub-delims / ":" ) ]
userinfo = [ [ user ] [ ':' password ] ]
user = *( unreserved / pct-encoded / sub-delims )
password = *( unreserved / pct-encoded / sub-delims / ":" )
@endcode
@par Exception Safety
@@ -1045,7 +1069,7 @@ public:
*/
BOOST_URL_DECL
url&
set_password_part(
set_encoded_userinfo(
string_view s);
//------------------------------------------------------
@@ -1089,7 +1113,7 @@ public:
and `s` is not empty, then the authority is added
including a leading double slash ("//").
@par ABNF
@par BNF
@code
IPv4address = dec-octet "." dec-octet "." dec-octet "." dec-octet
@@ -1139,7 +1163,7 @@ public:
then the authority is added including the
leading double slash ("//").
@par ABNF
@par BNF
@code
host = IP-literal / IPv4address / reg-name
@@ -1217,7 +1241,7 @@ public:
of <em>port</em> otherwise an exception is
thrown.
@par ABNF
@par BNF
@code
port = *DIGIT
@endcode
@@ -1254,7 +1278,7 @@ public:
of <em>port-part</em> otherwise an exception is
thrown.
@par ABNF
@par BNF
@code
port-part = [ ':' *DIGIT ]
@endcode
@@ -1302,7 +1326,7 @@ public:
If the path does not meet the syntactic
requirements, an exception is thrown.
@par ABNF
@par BNF
@code
path = path-abempty ; begins with "/" or is empty
/ path-absolute ; begins with "/" but not "//"
@@ -1399,7 +1423,7 @@ public:
of <em>query</em> otherwise an exception is
thrown.
@par ABNF
@par BNF
@code
query = *( pchar / "/" / "?" )
@endcode
@@ -1433,7 +1457,7 @@ public:
of <em>query-part</em> otherwise an exception
is thrown.
@par ABNF
@par BNF
@code
query-part = [ "#" *( pchar / "/" / "?" ) ]
@endcode
@@ -1519,7 +1543,7 @@ public:
of <em>fragment</em> otherwise an exception is
thrown.
@par ABNF
@par BNF
@code
fragment = *( pchar / "/" / "?" )
@endcode
@@ -1555,7 +1579,7 @@ public:
of <em>fragment-part</em> otherwise an exception
is thrown.
@par ABNF
@par BNF
@code
fragment-part = [ "#" *( pchar / "/" / "?" ) ]
@endcode
@@ -2159,6 +2183,10 @@ private:
parse() noexcept;
};
BOOST_URL_DECL
std::ostream&
operator<<(std::ostream& os, url const& u);
} // urls
} // boost

View File

@@ -35,4 +35,34 @@
</Expand>
</Type>
<Type Name="boost::urls::url">
<DisplayString>{s_,[pt_.offset[detail::part::id_end]]s}</DisplayString>
<Expand>
<Synthetic Name="scheme">
<DisplayString>{s_,[pt_.offset[detail::part::id_user]]s}</DisplayString>
</Synthetic>
<Synthetic Name="user">
<DisplayString>{s_+pt_.offset[detail::id_user],[pt_.offset[detail::part::id_pass]-pt_.offset[detail::part::id_user]]s}</DisplayString>
</Synthetic>
<Synthetic Name="pass">
<DisplayString>{s_+pt_.offset[detail::id_pass],[pt_.offset[detail::part::id_host]-pt_.offset[detail::part::id_pass]]s}</DisplayString>
</Synthetic>
<Synthetic Name="host">
<DisplayString>{s_+pt_.offset[detail::id_host],[pt_.offset[detail::part::id_port]-pt_.offset[detail::part::id_host]]s}</DisplayString>
</Synthetic>
<Synthetic Name="port">
<DisplayString>{s_+pt_.offset[detail::id_port],[pt_.offset[detail::part::id_path]-pt_.offset[detail::part::id_port]]s}</DisplayString>
</Synthetic>
<Synthetic Name="path">
<DisplayString>{s_+pt_.offset[detail::id_path],[pt_.offset[detail::part::id_query]-pt_.offset[detail::part::id_path]]s}</DisplayString>
</Synthetic>
<Synthetic Name="query">
<DisplayString>{s_+pt_.offset[detail::id_query],[pt_.offset[detail::part::id_frag]-pt_.offset[detail::part::id_query]]s}</DisplayString>
</Synthetic>
<Synthetic Name="frag">
<DisplayString>{s_+pt_.offset[detail::id_frag],[pt_.offset[detail::part::id_end]-pt_.offset[detail::part::id_frag]]s}</DisplayString>
</Synthetic>
</Expand>
</Type>
</AutoVisualizer>

View File

@@ -15,6 +15,7 @@
#include <boost/url/ipv6_address.hpp>
#include <boost/url/path_view.hpp>
#include <boost/url/query_params_view.hpp>
#include <boost/url/scheme.hpp>
#include <boost/url/detail/parts.hpp>
#include <cstdint>
#include <iosfwd>
@@ -106,12 +107,26 @@ public:
url_view const>
collect() const;
//--------------------------------------------
//--------------------------------------------
//--------------------------------------------
//--------------------------------------------
//
// classification
//
//--------------------------------------------
/** An integer for the maximum size string that can be represented
*/
static
constexpr
std::size_t
max_size()
{
return 0x7ffffffe;
}
/** Return true if the URL is empty
An empty URL is a relative-ref with
@@ -123,12 +138,6 @@ public:
//--------------------------------------------
/** Return the complete encoded URL
*/
BOOST_URL_DECL
string_view
str() const;
/** Return the origin
*/
BOOST_URL_DECL
@@ -142,17 +151,35 @@ public:
//--------------------------------------------
/** Return true if a scheme exists
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.1">
3.1. Scheme (rfc3986)</a>
*/
BOOST_URL_DECL
bool
has_scheme() const noexcept;
/** Return the scheme
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.1">
3.1. Scheme (rfc3986)</a>
*/
BOOST_URL_DECL
string_view
scheme() const noexcept;
/** Return a known-scheme constant if a scheme is present
@par Specification
@li <a href="https://datatracker.ietf.org/doc/html/rfc3986#section-3.1">
3.1. Scheme (rfc3986)</a>
*/
BOOST_URL_DECL
urls::scheme
scheme_id() const noexcept;
//--------------------------------------------
//
// authority
@@ -194,7 +221,7 @@ public:
/** Return the userinfo if it exists, or an empty string
Returns the userinfo of the URL as an encoded
string. The userinfo includes the username and
string. The userinfo includes the user and
password, with a colon separating the components
if the password is not empty.
@@ -235,11 +262,11 @@ public:
encoded_userinfo(), {}, a);
}
/** Return the username if it exists, or an empty string
/** Return the user if it exists, or an empty string
This function returns the username portion of
This function returns the user portion of
the userinfo if present, as an encoded string.
The username portion is defined by all of the
The user portion is defined by all of the
characters in the userinfo up to but not
including the first colon (':"), or the
entire userinfo if no colon is present.
@@ -250,13 +277,13 @@ public:
*/
BOOST_URL_DECL
string_view
encoded_username() const noexcept;
encoded_user() const noexcept;
/** Return the username if it exists, or an empty string
/** Return the user if it exists, or an empty string
This function returns the username portion of
This function returns the user portion of
the userinfo if present, as a decoded string.
The username portion is defined by all of the
The user portion is defined by all of the
characters in the userinfo up to but not
including the first colon (':"), or the
entire userinfo if no colon is present.
@@ -278,11 +305,11 @@ public:
class Allocator =
std::allocator<char>>
string_type<Allocator>
username(
user(
Allocator const& a = {}) const
{
return detail::pct_decode_unchecked(
encoded_username(), {}, a);
encoded_user(), {}, a);
}
/** Return true if a password exists
@@ -623,6 +650,16 @@ public:
pt_.decoded[id_frag], {}, a);
}
//--------------------------------------------
//--------------------------------------------
//--------------------------------------------
/** Return the complete encoded URL
*/
BOOST_URL_DECL
string_view
str() const;
//--------------------------------------------
//
// free functions