mirror of
https://github.com/boostorg/url.git
synced 2026-01-19 04:42:15 +00:00
feat: zone_id setters
This commit is contained in:
@@ -384,6 +384,10 @@ public:
|
||||
static_url& set_host_ipv4(ipv4_address const& addr) { url_base::set_host_ipv4(addr); return *this; }
|
||||
/// @copydoc url_base::set_host_ipv6
|
||||
static_url& set_host_ipv6(ipv6_address const& addr) { url_base::set_host_ipv6(addr); return *this; }
|
||||
/// @copydoc url_base::set_zone_id
|
||||
static_url& set_zone_id(core::string_view s) { url_base::set_zone_id(s); return *this; }
|
||||
/// @copydoc url_base::set_encoded_zone_id
|
||||
static_url& set_encoded_zone_id(pct_string_view const& s) { url_base::set_encoded_zone_id(s); return *this; }
|
||||
/// @copydoc url_base::set_host_ipvfuture
|
||||
static_url& set_host_ipvfuture(core::string_view s) { url_base::set_host_ipvfuture(s); return *this; }
|
||||
/// @copydoc url_base::set_host_name
|
||||
|
||||
@@ -450,6 +450,10 @@ public:
|
||||
url& set_host_ipv4(ipv4_address const& addr) { url_base::set_host_ipv4(addr); return *this; }
|
||||
/// @copydoc url_base::set_host_ipv6
|
||||
url& set_host_ipv6(ipv6_address const& addr) { url_base::set_host_ipv6(addr); return *this; }
|
||||
/// @copydoc url_base::set_zone_id
|
||||
url& set_zone_id(core::string_view s) { url_base::set_zone_id(s); return *this; }
|
||||
/// @copydoc url_base::set_encoded_zone_id
|
||||
url& set_encoded_zone_id(pct_string_view const& s) { url_base::set_encoded_zone_id(s); return *this; }
|
||||
/// @copydoc url_base::set_host_ipvfuture
|
||||
url& set_host_ipvfuture(core::string_view s) { url_base::set_host_ipvfuture(s); return *this; }
|
||||
/// @copydoc url_base::set_host_name
|
||||
|
||||
@@ -1355,6 +1355,63 @@ public:
|
||||
set_host_ipv6(
|
||||
ipv6_address const& addr);
|
||||
|
||||
/** Set the zone ID for an IPv6 address.
|
||||
|
||||
This function sets the zone ID for the host if the host is an IPv6 address.
|
||||
Reserved characters in the string are percent-escaped in the result.
|
||||
|
||||
@par Example
|
||||
@code
|
||||
assert( u.set_host_ipv6( ipv6_address( "fe80::1" ) ).set_zone_id( "eth0" ).buffer() == "https://[fe80::1%25eth0]" );
|
||||
@endcode
|
||||
|
||||
@par Complexity
|
||||
Linear in `this->size()`.
|
||||
|
||||
@par Exception Safety
|
||||
Strong guarantee. Calls to allocate may throw.
|
||||
|
||||
@param s The zone ID to set.
|
||||
@return `*this`
|
||||
|
||||
@par Specification
|
||||
@li <a href="https://datatracker.ietf.org/doc/html/rfc6874">RFC 6874</a>
|
||||
|
||||
*/
|
||||
url_base&
|
||||
set_zone_id(core::string_view s);
|
||||
|
||||
/** Set the zone ID for an IPv6 address (percent-encoded).
|
||||
|
||||
This function sets the zone ID for the host if the host is an IPv6 address.
|
||||
Escapes in the string are preserved, and reserved characters in the string
|
||||
are percent-escaped in the result.
|
||||
|
||||
@par Example
|
||||
@code
|
||||
assert( u.set_host_ipv6( ipv6_address( "fe80::1" ) ).set_encoded_zone_id( "eth0" ).buffer() == "https://[fe80::1%25eth0]" );
|
||||
@endcode
|
||||
|
||||
@par Complexity
|
||||
Linear in `this->size()`.
|
||||
|
||||
@par Exception Safety
|
||||
Strong guarantee. Calls to allocate may throw.
|
||||
Exceptions thrown on invalid input.
|
||||
|
||||
@throw system_error
|
||||
`s` contains an invalid percent-encoding.
|
||||
|
||||
@param s The zone ID to set.
|
||||
@return `*this`
|
||||
|
||||
@par Specification
|
||||
@li <a href="https://datatracker.ietf.org/doc/html/rfc6874">RFC 6874</a>
|
||||
|
||||
*/
|
||||
url_base&
|
||||
set_encoded_zone_id(pct_string_view s);
|
||||
|
||||
/** Set the host to an address
|
||||
|
||||
The host is set to the specified IPvFuture
|
||||
@@ -2861,6 +2918,16 @@ private:
|
||||
char* set_port_impl(std::size_t n, op_t& op);
|
||||
char* set_path_impl(std::size_t n, op_t& op);
|
||||
|
||||
void
|
||||
set_host_ipv6_and_zone_id(
|
||||
ipv6_address const& addr,
|
||||
core::string_view zone_id);
|
||||
|
||||
void
|
||||
set_host_ipv6_and_encoded_zone_id(
|
||||
ipv6_address const& addr,
|
||||
pct_string_view zone_id);
|
||||
|
||||
core::string_view
|
||||
first_segment() const noexcept;
|
||||
|
||||
|
||||
@@ -736,7 +736,7 @@ public:
|
||||
encoding_opts opt;
|
||||
opt.space_as_plus = false;
|
||||
return encoded_userinfo().decode(
|
||||
opt, std::move(token));
|
||||
opt, std::forward<StringToken>(token));
|
||||
}
|
||||
|
||||
/** Return the userinfo
|
||||
@@ -836,7 +836,7 @@ public:
|
||||
encoding_opts opt;
|
||||
opt.space_as_plus = false;
|
||||
return encoded_user().decode(
|
||||
opt, std::move(token));
|
||||
opt, std::forward<StringToken>(token));
|
||||
}
|
||||
|
||||
/** Return the user
|
||||
@@ -935,7 +935,7 @@ public:
|
||||
encoding_opts opt;
|
||||
opt.space_as_plus = false;
|
||||
return encoded_password().decode(
|
||||
opt, std::move(token));
|
||||
opt, std::forward<StringToken>(token));
|
||||
}
|
||||
|
||||
/** Return the password
|
||||
@@ -1064,7 +1064,7 @@ public:
|
||||
encoding_opts opt;
|
||||
opt.space_as_plus = false;
|
||||
return encoded_host().decode(
|
||||
opt, std::move(token));
|
||||
opt, std::forward<StringToken>(token));
|
||||
}
|
||||
|
||||
/** Return the host
|
||||
@@ -1162,7 +1162,7 @@ public:
|
||||
encoding_opts opt;
|
||||
opt.space_as_plus = false;
|
||||
return encoded_host_address().decode(
|
||||
opt, std::move(token));
|
||||
opt, std::forward<StringToken>(token));
|
||||
}
|
||||
|
||||
/** Return the host
|
||||
@@ -1383,7 +1383,7 @@ public:
|
||||
encoding_opts opt;
|
||||
opt.space_as_plus = false;
|
||||
return encoded_host_name().decode(
|
||||
opt, std::move(token));
|
||||
opt, std::forward<StringToken>(token));
|
||||
}
|
||||
|
||||
/** Return the host name
|
||||
@@ -1468,7 +1468,7 @@ public:
|
||||
encoding_opts opt;
|
||||
opt.space_as_plus = false;
|
||||
return encoded_zone_id().decode(
|
||||
opt, std::move(token));
|
||||
opt, std::forward<StringToken>(token));
|
||||
}
|
||||
|
||||
/** Return the IPv6 Zone ID
|
||||
@@ -1732,7 +1732,7 @@ public:
|
||||
encoding_opts opt;
|
||||
opt.space_as_plus = false;
|
||||
return encoded_path().decode(
|
||||
opt, std::move(token));
|
||||
opt, std::forward<StringToken>(token));
|
||||
}
|
||||
|
||||
/** Return the path
|
||||
@@ -1977,7 +1977,7 @@ public:
|
||||
encoding_opts opt;
|
||||
opt.space_as_plus = false;
|
||||
return encoded_query().decode(
|
||||
opt, std::move(token));
|
||||
opt, std::forward<StringToken>(token));
|
||||
}
|
||||
|
||||
/** Return the query
|
||||
@@ -2220,7 +2220,7 @@ public:
|
||||
encoding_opts opt;
|
||||
opt.space_as_plus = false;
|
||||
return encoded_fragment().decode(
|
||||
opt, std::move(token));
|
||||
opt, std::forward<StringToken>(token));
|
||||
}
|
||||
|
||||
/** Return the fragment
|
||||
|
||||
@@ -57,7 +57,7 @@ parse(
|
||||
grammar::delim_rule(']'))));
|
||||
if(! rv)
|
||||
{
|
||||
// IPv6addrz
|
||||
// IPv6addrz: https://datatracker.ietf.org/doc/html/rfc6874
|
||||
it = it0;
|
||||
auto rv2 = grammar::parse(
|
||||
it, end,
|
||||
|
||||
@@ -810,24 +810,97 @@ url_base::
|
||||
set_host_ipv6(
|
||||
ipv6_address const& addr)
|
||||
{
|
||||
op_t op(*this);
|
||||
char buf[2 +
|
||||
urls::ipv6_address::max_str_len];
|
||||
auto s = addr.to_buffer(
|
||||
buf + 1, sizeof(buf) - 2);
|
||||
buf[0] = '[';
|
||||
buf[s.size() + 1] = ']';
|
||||
auto const n = s.size() + 2;
|
||||
set_host_ipv6_and_encoded_zone_id(addr, encoded_zone_id());
|
||||
return *this;
|
||||
}
|
||||
|
||||
url_base&
|
||||
url_base::
|
||||
set_zone_id(core::string_view s)
|
||||
{
|
||||
set_host_ipv6_and_zone_id(host_ipv6_address(), s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
url_base&
|
||||
url_base::
|
||||
set_encoded_zone_id(pct_string_view s)
|
||||
{
|
||||
set_host_ipv6_and_encoded_zone_id(host_ipv6_address(), s);
|
||||
return *this;
|
||||
}
|
||||
|
||||
void
|
||||
url_base::
|
||||
set_host_ipv6_and_zone_id(
|
||||
ipv6_address const& addr,
|
||||
core::string_view zone_id)
|
||||
{
|
||||
op_t op(*this, &zone_id);
|
||||
char ipv6_str_buf[urls::ipv6_address::max_str_len];
|
||||
auto ipv6_str = addr.to_buffer(ipv6_str_buf, sizeof(ipv6_str_buf));
|
||||
bool const has_zone_id = !zone_id.empty();
|
||||
encoding_opts opt;
|
||||
auto const ipn = ipv6_str.size();
|
||||
auto const zn = encoded_size(zone_id, unreserved_chars, opt);
|
||||
auto const n = ipn + 2 + has_zone_id * (3 + zn);
|
||||
auto dest = set_host_impl(n, op);
|
||||
std::memcpy(dest, buf, n);
|
||||
impl_.decoded_[id_host] = n;
|
||||
*dest++ = '[';
|
||||
std::memcpy(dest, ipv6_str.data(), ipn);
|
||||
dest += ipn;
|
||||
if (has_zone_id)
|
||||
{
|
||||
*dest++ = '%';
|
||||
*dest++ = '2';
|
||||
*dest++ = '5';
|
||||
encode(dest, zn, zone_id, unreserved_chars, opt);
|
||||
dest += zn;
|
||||
}
|
||||
*dest++ = ']';
|
||||
// ipn + |"["| + |"]"| + (has_zone_id ? |"%"| + zn : 0)
|
||||
impl_.decoded_[id_host] = ipn + 2 + has_zone_id * (1 + zone_id.size());
|
||||
impl_.host_type_ = urls::host_type::ipv6;
|
||||
auto bytes = addr.to_bytes();
|
||||
std::memcpy(
|
||||
impl_.ip_addr_,
|
||||
bytes.data(),
|
||||
bytes.size());
|
||||
}
|
||||
|
||||
void
|
||||
url_base::
|
||||
set_host_ipv6_and_encoded_zone_id(
|
||||
ipv6_address const& addr,
|
||||
pct_string_view zone_id)
|
||||
{
|
||||
op_t op(*this, &detail::ref(zone_id));
|
||||
char ipv6_str_buf[urls::ipv6_address::max_str_len];
|
||||
auto ipv6_str = addr.to_buffer(ipv6_str_buf, sizeof(ipv6_str_buf));
|
||||
bool const has_zone_id = !zone_id.empty();
|
||||
auto const ipn = ipv6_str.size();
|
||||
auto const zn = detail::re_encoded_size_unsafe(zone_id, unreserved_chars);
|
||||
auto const n = ipn + 2 + has_zone_id * (3 + zn);
|
||||
auto dest = set_host_impl(n, op);
|
||||
*dest++ = '[';
|
||||
std::memcpy(dest, ipv6_str.data(), ipn);
|
||||
dest += ipn;
|
||||
std::size_t dzn = 0;
|
||||
if (has_zone_id)
|
||||
{
|
||||
*dest++ = '%';
|
||||
*dest++ = '2';
|
||||
*dest++ = '5';
|
||||
dzn = detail::re_encode_unsafe(dest, dest + zn, zone_id, unreserved_chars);
|
||||
}
|
||||
*dest++ = ']';
|
||||
// ipn + |"["| + |"]"| + (has_zone_id ? |"%"| + zn : 0)
|
||||
impl_.decoded_[id_host] = ipn + 2 + has_zone_id * (1 + dzn);
|
||||
impl_.host_type_ = urls::host_type::ipv6;
|
||||
auto bytes = addr.to_bytes();
|
||||
std::memcpy(
|
||||
impl_.ip_addr_,
|
||||
bytes.data(),
|
||||
bytes.size());
|
||||
return *this;
|
||||
}
|
||||
|
||||
url_base&
|
||||
|
||||
@@ -1192,6 +1192,41 @@ struct url_base_test
|
||||
|
||||
set_host_ipv6("1::6:c0a8:1", "//[1::6:c0a8:1]");
|
||||
|
||||
// set_zone_id
|
||||
{
|
||||
// Round-trip: set and get zone id
|
||||
url u;
|
||||
BOOST_TEST_NO_THROW(u.set_host_ipv6(ipv6_address("fe80::1")));
|
||||
BOOST_TEST_NO_THROW(u.set_zone_id("eth0"));
|
||||
BOOST_TEST_EQ(u.host_ipv6_address().to_string(), "fe80::1");
|
||||
BOOST_TEST_EQ(u.zone_id(), "eth0");
|
||||
BOOST_TEST_EQ(u.buffer(), "//[fe80::1%25eth0]");
|
||||
|
||||
// set_zone_id when no IPv6 host: should create default
|
||||
// constructed IPv6
|
||||
url u2;
|
||||
BOOST_TEST_NO_THROW(u2.set_zone_id("zone42"));
|
||||
BOOST_TEST_EQ(u2.host_type(), host_type::ipv6);
|
||||
BOOST_TEST_EQ(u2.zone_id(), "zone42");
|
||||
BOOST_TEST_EQ(u2.buffer(), "//[::%25zone42]");
|
||||
|
||||
// set_encoded_zone_id: round-trip
|
||||
url u3;
|
||||
BOOST_TEST_NO_THROW(u3.set_host_ipv6(ipv6_address("fe80::2")));
|
||||
BOOST_TEST_NO_THROW(u3.set_encoded_zone_id("en%30"));
|
||||
BOOST_TEST_EQ(u3.zone_id(), "en0");
|
||||
BOOST_TEST_EQ(u3.encoded_zone_id(), "en%30");
|
||||
BOOST_TEST_EQ(u3.buffer(), "//[fe80::2%25en%30]");
|
||||
|
||||
// set_encoded_zone_id when no IPv6 host: should create default
|
||||
// constructed IPv6
|
||||
url u4;
|
||||
BOOST_TEST_NO_THROW(u4.set_encoded_zone_id("zone%34"));
|
||||
BOOST_TEST_EQ(u4.host_type(), host_type::ipv6);
|
||||
BOOST_TEST_EQ(u4.zone_id(), "zone4");
|
||||
BOOST_TEST_EQ(u4.buffer(), "//[::%25zone%34]");
|
||||
}
|
||||
|
||||
set_host_ipvfuture("v42.69", "//[v42.69]");
|
||||
BOOST_TEST_THROWS(url().set_host_ipvfuture("127.0.0.1"), system::system_error);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user