From 5754fe486eece4cd36e06bbd9abf7d46147340ad Mon Sep 17 00:00:00 2001 From: Vinnie Falco Date: Mon, 6 Sep 2021 22:25:48 -0700 Subject: [PATCH] host work --- include/boost/url.hpp | 1 + include/boost/url/detail/config.hpp | 4 + include/boost/url/detail/network_order.hpp | 74 +++++ include/boost/url/detail/parse.hpp | 20 +- include/boost/url/detail/parts.hpp | 11 +- include/boost/url/host_type.hpp | 4 + include/boost/url/impl/ipv4_address.hpp | 33 ++ include/boost/url/impl/ipv4_address.ipp | 128 ++++++++ include/boost/url/impl/url.ipp | 10 +- include/boost/url/impl/url_view.ipp | 69 +++- include/boost/url/ipv4_address.hpp | 211 ++++++++++++ include/boost/url/optional.hpp | 11 + include/boost/url/rfc/host_bnf.hpp | 79 ++--- include/boost/url/rfc/impl/host_bnf.ipp | 56 +--- .../boost/url/rfc/impl/ipv4_address_bnf.ipp | 16 +- .../boost/url/rfc/impl/ipv6_address_bnf.ipp | 14 +- include/boost/url/rfc/ipv4_address_bnf.hpp | 3 +- include/boost/url/src.hpp | 1 + include/boost/url/url.hpp | 5 +- include/boost/url/url_view.hpp | 29 +- test/CMakeLists.txt | 1 + test/host_type.cpp | 21 ++ test/ipv4_address.cpp | 65 ++++ test/rfc/authority_bnf.cpp | 17 +- test/rfc/host_bnf.cpp | 37 ++- test/rfc/ipv4_address_bnf.cpp | 12 +- test/url_view.cpp | 304 ++++-------------- 27 files changed, 822 insertions(+), 414 deletions(-) create mode 100644 include/boost/url/detail/network_order.hpp create mode 100644 include/boost/url/impl/ipv4_address.hpp create mode 100644 include/boost/url/impl/ipv4_address.ipp create mode 100644 include/boost/url/ipv4_address.hpp create mode 100644 test/ipv4_address.cpp diff --git a/include/boost/url.hpp b/include/boost/url.hpp index 734d0ed4..71bf17ed 100644 --- a/include/boost/url.hpp +++ b/include/boost/url.hpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include diff --git a/include/boost/url/detail/config.hpp b/include/boost/url/detail/config.hpp index c8c56334..7664c01e 100644 --- a/include/boost/url/detail/config.hpp +++ b/include/boost/url/detail/config.hpp @@ -16,6 +16,10 @@ #include #include +#if CHAR_BIT != 8 +# error unsupported platform +#endif + // VFALCO Copied from // This is a derivative work. #ifdef __has_cpp_attribute diff --git a/include/boost/url/detail/network_order.hpp b/include/boost/url/detail/network_order.hpp new file mode 100644 index 00000000..40b3b1e2 --- /dev/null +++ b/include/boost/url/detail/network_order.hpp @@ -0,0 +1,74 @@ +// +// 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 +// + +#ifndef BOOST_URL_DETAIL_NETWORK_ORDER_HPP +#define BOOST_URL_DETAIL_NETWORK_ORDER_HPP + +#include +#include +#include + +namespace boost { +namespace urls { +namespace detail { + +inline +std::uint_least32_t +swap_endian( + std::uint_least32_t v0) noexcept +{ + return + ((v0 & 0xff000000) >> 24) | + ((v0 & 0x00ff0000) >> 8) | + ((v0 & 0x0000ff00) << 8) | + ((v0 & 0x000000ff) << 24); +} + +inline +bool +is_big_endian() noexcept +{ + unsigned char t0[4] = {}; + std::uint_least32_t t1 = 1; + std::memcpy(t0, &t1, 4); + if(t0[0] == 0) + { + // big endian + BOOST_ASSERT( + t0[3] == 1); + return true; + } + return false; +} + +inline +std::uint_least32_t +host_to_network( + std::uint_least32_t v) noexcept +{ + if(is_big_endian()) + return v; + return swap_endian(v); +} + +inline +std::uint_least32_t +network_to_host( + std::uint_least32_t v) noexcept +{ + if(is_big_endian()) + return v; + return swap_endian(v); +} + +} // detail +} // urls +} // boost + +#endif diff --git a/include/boost/url/detail/parse.hpp b/include/boost/url/detail/parse.hpp index f2ab937b..6fa96740 100644 --- a/include/boost/url/detail/parse.hpp +++ b/include/boost/url/detail/parse.hpp @@ -295,7 +295,8 @@ struct parser return; } ++p_; - pt.host = host_type::ipv6; + pt.host_type = + urls::host_type::ipv6; } void @@ -306,7 +307,8 @@ struct parser auto const p0 = p_; if(match_ip_v4()) { - pt.host = host_type::ipv4; + pt.host_type = + urls::host_type::ipv4; auto const p1 = p_; auto const e = reg_name_pct_set(); @@ -314,7 +316,8 @@ struct parser if(ec) return; if(p_ != p1) - pt.host = host_type::name; + pt.host_type = + urls::host_type::name; return; } auto const e = @@ -323,7 +326,8 @@ struct parser if(ec) return; if(p_ != p0) - pt.host = host_type::name; + pt.host_type = + urls::host_type::name; } short @@ -981,7 +985,7 @@ parse_plain_hostname( { if(ec != error::no_match) { - pt.host = host_type::name; + pt.host_type = host_type::name; return; } ec = {}; @@ -989,10 +993,10 @@ parse_plain_hostname( { if(pr.done()) { - pt.host = host_type::ipv4; + pt.host_type = host_type::ipv4; return; } - pt.host = host_type::name; + pt.host_type = host_type::name; return; } } @@ -1000,7 +1004,7 @@ parse_plain_hostname( { return; } - pt.host = host_type::name; + pt.host_type = host_type::name; } inline diff --git a/include/boost/url/detail/parts.hpp b/include/boost/url/detail/parts.hpp index 8df492c0..378dfd76 100644 --- a/include/boost/url/detail/parts.hpp +++ b/include/boost/url/detail/parts.hpp @@ -11,8 +11,10 @@ #define BOOST_URL_DETAIL_PARTS_HPP #include +#include #include #include +#include namespace boost { namespace urls { @@ -37,10 +39,12 @@ struct parts { std::size_t offset[id_end + 1]; std::size_t decoded[id_end]; + unsigned char ip_addr[16]; std::size_t nseg = 0; std::size_t nparam = 0; - host_type host = host_type::none; std::uint16_t port_number = 0; + urls::host_type host_type = + host_type::none; parts() noexcept { @@ -50,10 +54,15 @@ struct parts void clear() noexcept { + // VFALCO is this needed? + host_type = urls::host_type::none; for(int i = 0; i <= id_end; ++i) offset[i] = 0; + // VFALCO This isn't really needed + /* for(int i = 0; i < id_end; ++i) decoded[i] = 0; + */ } std::size_t diff --git a/include/boost/url/host_type.hpp b/include/boost/url/host_type.hpp index 9b9dcd77..1d19381f 100644 --- a/include/boost/url/host_type.hpp +++ b/include/boost/url/host_type.hpp @@ -34,10 +34,14 @@ enum class host_type name, /** A host is specified by IPv4address. + + @see ipv4_address */ ipv4, /** A host is specified by IPv6address. + + @see ipv6_address */ ipv6, diff --git a/include/boost/url/impl/ipv4_address.hpp b/include/boost/url/impl/ipv4_address.hpp new file mode 100644 index 00000000..31eaa2b4 --- /dev/null +++ b/include/boost/url/impl/ipv4_address.hpp @@ -0,0 +1,33 @@ +// +// 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/CPPAllinace/url +// + +#ifndef BOOST_URL_IMPL_IPV4_ADDRESS_HPP +#define BOOST_URL_IMPL_IPV4_ADDRESS_HPP + +#include + +namespace boost { +namespace urls { + +template +string_type +ipv4_address:: +to_string(Allocator const& a) const +{ + string_type s(a); + char buf[max_str_len]; + s.resize(print_impl(buf)); + std::memcpy(&s[0], buf, s.size()); + return s; +} + +} // urls +} // boost + +#endif diff --git a/include/boost/url/impl/ipv4_address.ipp b/include/boost/url/impl/ipv4_address.ipp new file mode 100644 index 00000000..83706691 --- /dev/null +++ b/include/boost/url/impl/ipv4_address.ipp @@ -0,0 +1,128 @@ +// +// 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/CPPAllinace/url +// + +#ifndef BOOST_URL_IMPL_IPV4_ADDRESS_IPP +#define BOOST_URL_IMPL_IPV4_ADDRESS_IPP + +#include +#include +#include + +namespace boost { +namespace urls { + +ipv4_address:: +ipv4_address( + bytes_type const& bytes) +{ + std::memcpy(&addr_, + bytes.data(), 4); +} + +ipv4_address:: +ipv4_address(uint_type addr) + : addr_(detail::host_to_network(addr)) +{ +} + +auto +ipv4_address:: +to_bytes() const noexcept -> + bytes_type +{ + bytes_type bytes; + std::memcpy( + bytes.data(), + &addr_, 4); + return bytes; +} + +auto +ipv4_address:: +to_uint() const noexcept -> + uint_type +{ + return detail::network_to_host( + addr_); +} + +bool +ipv4_address:: +is_loopback() const noexcept +{ + return (to_uint() & 0xFF000000) == + 0x7F000000; +} + +bool +ipv4_address:: +is_unspecified() const noexcept +{ + return to_uint() == 0; +} + +bool +ipv4_address:: +is_multicast() const noexcept +{ + return (to_uint() & 0xF0000000) == + 0xE0000000;; +} + +std::size_t +ipv4_address:: +print_impl( + char* dest) const noexcept +{ + auto const start = dest; + auto const write = + []( char*& dest, + unsigned char v) + { + if(v >= 100) + { + *dest++ = '0' + + v / 100; + v %= 100; + } + if(v >= 10) + { + *dest++ = '0' + + v / 10; + v %= 10; + } + *dest++ = '0' + v; + }; + auto const v = to_uint(); + write(dest, (v >> 24) & 0xff); + *dest++ = '.'; + write(dest, (v >> 16) & 0xff); + *dest++ = '.'; + write(dest, (v >> 8) & 0xff); + *dest++ = '.'; + write(dest, (v ) ); + return dest - start; +} + +std::ostream& +operator<<( + std::ostream& os, + ipv4_address const& a) +{ + char buf[ipv4_address::max_str_len + 1]; + auto n = a.print_impl(buf); + buf[n] = '\0'; + os << string_view(buf, n); + return os; +} + +} // urls +} // boost + +#endif diff --git a/include/boost/url/impl/url.ipp b/include/boost/url/impl/url.ipp index bd3dac04..75513e0d 100644 --- a/include/boost/url/impl/url.ipp +++ b/include/boost/url/impl/url.ipp @@ -740,9 +740,9 @@ set_host( } detail::parts pt; detail::parse_plain_hostname(pt, s); - BOOST_ASSERT( - pt.host != urls::host_type::none); - if(pt.host != urls::host_type::name) + BOOST_ASSERT(pt.host_type != + urls::host_type::none); + if(pt.host_type != urls::host_type::name) { if(! has_authority()) { @@ -792,7 +792,7 @@ set_host( e.encode(dest, s); } } - pt_.host = pt.host; + pt_.host_type = pt.host_type; return *this; } @@ -826,7 +826,7 @@ set_encoded_host( s.size()); s.copy(dest, s.size()); } - pt_.host = pt.host; + pt_.host_type = pt.host_type; return *this; } diff --git a/include/boost/url/impl/url_view.ipp b/include/boost/url/impl/url_view.ipp index 6a22d595..7ad1ac86 100644 --- a/include/boost/url/impl/url_view.ipp +++ b/include/boost/url/impl/url_view.ipp @@ -17,6 +17,7 @@ #include #include #include +#include namespace boost { namespace urls { @@ -302,6 +303,28 @@ encoded_password() const noexcept // host +string_view +url_view:: +encoded_hostname() const noexcept +{ + return get(detail::id_host); +} + +urls::ipv4_address +url_view:: +ipv4_address() const noexcept +{ + BOOST_ASSERT(pt_.host_type == + host_type::ipv4); + std::array< + unsigned char, 4> bytes; + std::memcpy( + &bytes[0], + &pt_.ip_addr[0], 4); + return urls::ipv4_address( + bytes); +} + string_view url_view:: encoded_host_and_port() const noexcept @@ -612,6 +635,44 @@ end() const noexcept -> namespace detail { +static +void +apply_host( + parts& p, + rfc::host_bnf const& h) +{ + p.host_type = h.host_type(); + switch(h.host_type()) + { + default: + case urls::host_type::none: + break; + case urls::host_type::name: + break; + case urls::host_type::ipv4: + { + auto const bytes = + h.get_ipv4().to_bytes(); + std::memcpy( + &p.ip_addr[0], + bytes.data(), 4); + break; + } + case urls::host_type::ipv6: + break; + case urls::host_type::ipvfuture: + break; + } + + if(h.host_type() != + host_type::none) + { + p.resize( + part::id_host, + h.str().size()); + } +} + static void apply_authority( @@ -651,13 +712,7 @@ apply_authority( p.resize(part::id_user, 2); } - auto const& h = t->host; - if(h.kind() != rfc::host_kind::none) - { - p.resize( - part::id_host, - h.str().size()); - } + apply_host(p, t->host); if(t->port.has_value()) { diff --git a/include/boost/url/ipv4_address.hpp b/include/boost/url/ipv4_address.hpp new file mode 100644 index 00000000..c6b31449 --- /dev/null +++ b/include/boost/url/ipv4_address.hpp @@ -0,0 +1,211 @@ +// +// 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/CPPAllinace/url +// + +#ifndef BOOST_URL_IPV4_ADDRESS_HPP +#define BOOST_URL_IPV4_ADDRESS_HPP + +#include +#include +#include +#include +#include +#include + +namespace boost { +namespace urls { + +class ipv4_address +{ +public: + /** The number of characters in the longest possible ipv4 string + */ + static + constexpr + std::size_t max_str_len = 15; + + /** The type used to represent an address as an unsigned integer + */ + using uint_type = + std::uint_least32_t; + + /** The type used to represent an address as an array of bytes + */ + using bytes_type = + std::array; + + /** Constructor + */ + ipv4_address() noexcept + : addr_(0) + { + } + + /** Construct from raw bytes + */ + BOOST_URL_DECL + explicit + ipv4_address( + bytes_type const & bytes); + + /** Construct from an unsigned integer in host byte order + */ + BOOST_URL_DECL + explicit + ipv4_address(uint_type addr); + + /** Constructor + */ + ipv4_address( + ipv4_address const& other) noexcept + : addr_(other.addr_) + { + } + + /** Assign from another address + */ + ipv4_address& + operator=( + ipv4_address const& other) noexcept + { + addr_ = other.addr_; + return *this; + } + + /** Return the address as bytes, in network byte order + */ + BOOST_URL_DECL + bytes_type + to_bytes() const noexcept; + + /** Return the address as an unsigned integer in host byte order + */ + BOOST_URL_DECL + uint_type + to_uint() const noexcept; + + /** Return the address as a string in dotted decimal format + + @par Exception Safety + + Strong guarantee. + Calls to allocate may throw. + + @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`. + + @return A `std::basic_string` using the + specified allocator. + */ + template> + string_type + to_string(Allocator const& a = {}) const; + + /** Return true if the address is a loopback address + */ + BOOST_URL_DECL + bool + is_loopback() const noexcept; + + /** Return true if the address is unspecified + */ + BOOST_URL_DECL + bool + is_unspecified() const noexcept; + + /** Return true if the address is a multicast address + */ + BOOST_URL_DECL + bool + is_multicast() const noexcept; + + /** Return true if two addresses are equal + */ + friend + bool + operator==( + ipv4_address const& a1, + ipv4_address const& a2) noexcept + { + return a1.addr_ == a2.addr_; + } + + /** Return true if two addresses are not equal + */ + friend + bool + operator!=( + ipv4_address const& a1, + ipv4_address const& a2) noexcept + { + return a1.addr_ != a2.addr_; + } + + /** Return an address object that represents any address + */ + static + ipv4_address + any() noexcept + { + return ipv4_address(); + } + + /** Return an address object that represents the loopback address + */ + static + ipv4_address + loopback() noexcept + { + return ipv4_address(0x7F000001); + } + + /** Return an address object that represents the broadcast address + */ + static + ipv4_address + broadcast() noexcept + { + return ipv4_address(0xFFFFFFFF); + } + + BOOST_URL_DECL + friend + std::ostream& + operator<<( + std::ostream&, + ipv4_address const&); + +private: + BOOST_URL_DECL + std::size_t + print_impl( + char* dest) const noexcept; + + // network order + uint_type addr_; +}; + +#if 0 +/** Format the ipv4_address to an output stream +*/ +BOOST_URL_DECL +std::ostream& +operator<<( + std::ostream&, + ipv4_address const&); +#endif + +} // urls +} // boost + +#include + +#endif diff --git a/include/boost/url/optional.hpp b/include/boost/url/optional.hpp index 7fe52366..c23beed1 100644 --- a/include/boost/url/optional.hpp +++ b/include/boost/url/optional.hpp @@ -14,11 +14,20 @@ #include #include #include +#include + #include namespace boost { namespace urls { +#if 1 + +template +using optional = boost::optional; + +#else + /** A simplified C++11 optional */ template @@ -260,6 +269,8 @@ operator!=( return t != *u; } +#endif + } // urls } // boost diff --git a/include/boost/url/rfc/host_bnf.hpp b/include/boost/url/rfc/host_bnf.hpp index 1dd852a0..f8dd0fe1 100644 --- a/include/boost/url/rfc/host_bnf.hpp +++ b/include/boost/url/rfc/host_bnf.hpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -21,17 +22,6 @@ namespace boost { namespace urls { namespace rfc { -/** The kind of host -*/ -enum class host_kind -{ - none, - ipv4, - ipv6, - ipv_future, - domain -}; - /** BNF for host @par BNF @@ -44,70 +34,63 @@ enum class host_kind */ class host_bnf { - host_kind kind_ = - host_kind::none; - string_view s_; - - union - { - ipv4_address_bnf ipv4_; - ipv6_address_bnf ipv6_; - pct_encoded_str domain_{}; - string_view fut_; - }; - - void destroy(); + string_view str_; + pct_encoded_str name_; + ipv4_address ipv4_; + ipv6_address_bnf ipv6_; + string_view ipvfuture_; + host_type host_type_ = + host_type::none; public: - host_bnf() - { - } + BOOST_URL_DECL + ~host_bnf() noexcept; BOOST_URL_DECL - ~host_bnf(); + host_bnf() noexcept; string_view str() const noexcept { - return s_; + return str_; } - host_kind - kind() const noexcept + urls::host_type + host_type() const noexcept { - return kind_; + return host_type_; } - ipv4_address_bnf const& + pct_encoded_str + get_name() const noexcept + { + BOOST_ASSERT(host_type_ == + urls::host_type::name); + return name_; + } + + ipv4_address const& get_ipv4() const noexcept { - BOOST_ASSERT(kind_ == - host_kind::ipv4); + BOOST_ASSERT(host_type_ == + urls::host_type::ipv4); return ipv4_; } ipv6_address_bnf const& get_ipv6() const noexcept { - BOOST_ASSERT(kind_ == - host_kind::ipv6); + BOOST_ASSERT(host_type_ == + urls::host_type::ipv6); return ipv6_; } string_view get_ipv_future() const noexcept { - BOOST_ASSERT(kind_ == - host_kind::ipv_future); - return fut_; - } - - pct_encoded_str - get_domain() const noexcept - { - BOOST_ASSERT(kind_ == - host_kind::domain); - return domain_; + BOOST_ASSERT(host_type_ == + urls::host_type::ipvfuture); + return ipvfuture_; } BOOST_URL_DECL diff --git a/include/boost/url/rfc/impl/host_bnf.ipp b/include/boost/url/rfc/impl/host_bnf.ipp index f8e2265c..bda35a64 100644 --- a/include/boost/url/rfc/impl/host_bnf.ipp +++ b/include/boost/url/rfc/impl/host_bnf.ipp @@ -18,35 +18,11 @@ namespace boost { namespace urls { namespace rfc { -void host_bnf:: -destroy() -{ - switch(kind_) - { - default: - case host_kind::none: - break; - case host_kind::ipv4: - ipv4_.~ipv4_address_bnf(); - break; - case host_kind::ipv6: - ipv6_.~ipv6_address_bnf(); - break; - case host_kind::ipv_future: - fut_.~string_view(); - break; - case host_kind::domain: - domain_.~pct_encoded_str(); - break; - } -} +~host_bnf() noexcept = default; host_bnf:: -~host_bnf() -{ - destroy(); -} +host_bnf() noexcept = default; bool parse( @@ -56,8 +32,6 @@ parse( host_bnf& t) { auto const start = it; - t.destroy(); - t.kind_ = host_kind::none; if(*it == '[') { // IP-literal @@ -71,16 +45,15 @@ parse( if(v.is_ipv6) { // IPv6address - ::new(&t.ipv6_) - ipv6_address_bnf(v.ipv6); - t.kind_ = host_kind::ipv6; + t.ipv6_ = v.ipv6; + t.host_type_ = host_type::ipv6; goto finish; } // VFALCO TODO // IPvFuture - ::new(&t.fut_) string_view( - v.fut_str); - t.kind_ = host_kind::ipv_future; + t.ipvfuture_ = v.fut_str; + t.host_type_ = + host_type::ipvfuture; goto finish; } // IPv4address @@ -89,9 +62,8 @@ parse( auto it0 = it; if(parse(it, end, ec, v)) { - ::new(&t.ipv4_) - ipv4_address_bnf(v); - t.kind_ = host_kind::ipv4; + t.ipv4_ = v.addr; + t.host_type_ = host_type::ipv4; goto finish; } it = it0; @@ -102,17 +74,17 @@ parse( pct_encoded_str ns; if(! parse(it, end, ec, pct_encoded_bnf< - unsub_char_mask>{ns})) + unsub_char_mask>{ + t.name_})) { // bad reg-name return false; } - ::new(&t.domain_) - pct_encoded_str(ns); - t.kind_ = host_kind::domain; + t.host_type_ = + host_type::name; } finish: - t.s_ = string_view( + t.str_ = string_view( start, it - start); return true; } diff --git a/include/boost/url/rfc/impl/ipv4_address_bnf.ipp b/include/boost/url/rfc/impl/ipv4_address_bnf.ipp index a0689c4c..90e7a29a 100644 --- a/include/boost/url/rfc/impl/ipv4_address_bnf.ipp +++ b/include/boost/url/rfc/impl/ipv4_address_bnf.ipp @@ -23,7 +23,7 @@ namespace detail { struct dec_octet { - std::uint8_t& v; + unsigned char& v; friend bool @@ -115,18 +115,16 @@ parse( { using bnf::parse; auto const start = it; + std::array v; if(! parse(it, end, ec, - detail::dec_octet{ - t.octets[0]}, '.', - detail::dec_octet{ - t.octets[1]}, '.', - detail::dec_octet{ - t.octets[2]}, '.', - detail::dec_octet{ - t.octets[3]})) + detail::dec_octet{v[0]}, '.', + detail::dec_octet{v[1]}, '.', + detail::dec_octet{v[2]}, '.', + detail::dec_octet{v[3]})) return false; t.str = string_view( start, it - start); + t.addr = ipv4_address(v); return true; } diff --git a/include/boost/url/rfc/impl/ipv6_address_bnf.ipp b/include/boost/url/rfc/impl/ipv6_address_bnf.ipp index cfe686ec..d17bf4f5 100644 --- a/include/boost/url/rfc/impl/ipv6_address_bnf.ipp +++ b/include/boost/url/rfc/impl/ipv6_address_bnf.ipp @@ -206,14 +206,12 @@ parse( if(! parse( it, end, ec, v4)) return false; - t.octets[2*(7-n)+0] = - v4.octets[0]; - t.octets[2*(7-n)+1] = - v4.octets[1]; - t.octets[2*(7-n)+2] = - v4.octets[2]; - t.octets[2*(7-n)+3] = - v4.octets[3]; + auto const b = + v4.addr.to_bytes(); + t.octets[2*(7-n)+0] = b[0]; + t.octets[2*(7-n)+1] = b[1]; + t.octets[2*(7-n)+2] = b[2]; + t.octets[2*(7-n)+3] = b[3]; t.trailing_ipv4 = true; --n; break; diff --git a/include/boost/url/rfc/ipv4_address_bnf.hpp b/include/boost/url/rfc/ipv4_address_bnf.hpp index 3d61df88..1a16998a 100644 --- a/include/boost/url/rfc/ipv4_address_bnf.hpp +++ b/include/boost/url/rfc/ipv4_address_bnf.hpp @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -42,7 +43,7 @@ struct ipv4_address_bnf std::array; string_view str; - value_type octets; + ipv4_address addr; BOOST_URL_DECL friend diff --git a/include/boost/url/src.hpp b/include/boost/url/src.hpp index 9415d52f..08555932 100644 --- a/include/boost/url/src.hpp +++ b/include/boost/url/src.hpp @@ -28,6 +28,7 @@ in a translation unit of the program. #include #include +#include #include #include #include diff --git a/include/boost/url/url.hpp b/include/boost/url/url.hpp index 48dcc088..ab4b7c77 100644 --- a/include/boost/url/url.hpp +++ b/include/boost/url/url.hpp @@ -737,7 +737,7 @@ public: urls::host_type host_type() const noexcept { - return pt_.host; + return pt_.host_type; } /** Return the host and port. @@ -782,7 +782,8 @@ public: host( Allocator const& a = {}) const { - if(pt_.host != urls::host_type::name) + if(pt_.host_type != + urls::host_type::name) { auto const s = pt_.get( detail::id_host, s_); diff --git a/include/boost/url/url_view.hpp b/include/boost/url/url_view.hpp index e6c6c889..4306d8bb 100644 --- a/include/boost/url/url_view.hpp +++ b/include/boost/url/url_view.hpp @@ -11,6 +11,7 @@ #define BOOST_URL_URL_VIEW_HPP #include +#include #include #include #include @@ -269,7 +270,7 @@ public: //-------------------------------------------- - /** Return the type of host present, if any. + /** Return the type of host present, if any @par Exception Safety @@ -278,9 +279,21 @@ public: urls::host_type host_type() const noexcept { - return pt_.host; + return pt_.host_type; } + /** Return the host name string if it exists, or an empty string + */ + BOOST_URL_DECL + string_view + encoded_hostname() const noexcept; + + /** Return the ipv4 address if it exists + */ + BOOST_URL_DECL + urls::ipv4_address + ipv4_address() const noexcept; + /** Return the host and port. This function returns the encoded host and port, @@ -323,15 +336,15 @@ public: host( Allocator const& a = {}) const { - if(pt_.host != urls::host_type::name) + auto const s0 = encoded_host(); + if(pt_.host_type != + urls::host_type::name) { - auto const s = pt_.get( - detail::id_host, s_); + // no decoding return string_type( - s.data(), s.size(), a); + s0.data(), s0.size(), a); } - return detail::decode( - encoded_host(), a); + return detail::decode(s0, a); } /** Return the host. diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index ab69539c..04c48e56 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -24,6 +24,7 @@ set(BOOST_URL_TESTS_FILES _detail_parse.cpp error.cpp host_type.cpp + ipv4_address.cpp optional.cpp query_params_view.cpp sandbox.cpp diff --git a/test/host_type.cpp b/test/host_type.cpp index 0bc4d0d8..de9bc558 100644 --- a/test/host_type.cpp +++ b/test/host_type.cpp @@ -9,3 +9,24 @@ // Test that header file is self-contained. #include + +#include "test_suite.hpp" + +namespace boost { +namespace urls { + +class host_type_test +{ +public: + void + run() + { + } +}; + +TEST_SUITE( + host_type_test, + "boost.url.host_type"); + +} // urls +} // boost diff --git a/test/ipv4_address.cpp b/test/ipv4_address.cpp new file mode 100644 index 00000000..b40636e7 --- /dev/null +++ b/test/ipv4_address.cpp @@ -0,0 +1,65 @@ +// +// 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 +// + +// Test that header file is self-contained. +#include + +#include +#include "test_suite.hpp" + +namespace boost { +namespace urls { + +class ipv4_address_test +{ +public: + void + run() + { + { + ipv4_address a; + BOOST_TEST(a.is_unspecified()); + BOOST_TEST(a == + ipv4_address::any()); + } + { + ipv4_address a(0xc0a80001); + BOOST_TEST(! a.is_loopback()); + BOOST_TEST(! a.is_unspecified()); + BOOST_TEST(! a.is_multicast()); + auto v = a.to_bytes(); + BOOST_TEST(v[0] == 0xc0); + BOOST_TEST(v[1] == 0xa8); + BOOST_TEST(v[2] == 0x00); + BOOST_TEST(v[3] == 0x01); + BOOST_TEST(a.to_uint() == + 0xc0a80001); + BOOST_TEST(a.to_string() == + "192.168.0.1"); + } + { + ipv4_address a1 = + ipv4_address::loopback(); + BOOST_TEST(a1.is_loopback()); + ipv4_address a2; + BOOST_TEST(a1 != a2); + BOOST_TEST(a2.is_unspecified()); + a2 = a1; + BOOST_TEST(a2.is_loopback()); + BOOST_TEST(a1 == a2); + } + } +}; + +TEST_SUITE( + ipv4_address_test, + "boost.url.ipv4_address"); + +} // urls +} // boost diff --git a/test/rfc/authority_bnf.cpp b/test/rfc/authority_bnf.cpp index 89f221f7..e8383102 100644 --- a/test/rfc/authority_bnf.cpp +++ b/test/rfc/authority_bnf.cpp @@ -11,13 +11,24 @@ #include #include + #include "test_suite.hpp" #include "test_bnf.hpp" +#include + namespace boost { namespace urls { namespace rfc { +BOOST_STATIC_ASSERT( + std::is_copy_constructible< + authority_bnf>::value); + +BOOST_STATIC_ASSERT( + std::is_copy_assignable< + authority_bnf>::value); + class authority_bnf_test { public: @@ -42,9 +53,9 @@ public: "x:y@e.com:8080", ec, p)); BOOST_TEST(p.str == "x:y@e.com:8080"); - BOOST_TEST(p.host.kind() == - host_kind::domain); - BOOST_TEST(p.host.get_domain().str + BOOST_TEST(p.host.host_type() == + host_type::name); + BOOST_TEST(p.host.get_name().str == "e.com"); if(BOOST_TEST(p.port.has_value())) { diff --git a/test/rfc/host_bnf.cpp b/test/rfc/host_bnf.cpp index c7f87245..64d6111b 100644 --- a/test/rfc/host_bnf.cpp +++ b/test/rfc/host_bnf.cpp @@ -11,13 +11,25 @@ #include #include +#include + #include "test_suite.hpp" #include "test_bnf.hpp" +#include + namespace boost { namespace urls { namespace rfc { +BOOST_STATIC_ASSERT( + std::is_copy_constructible< + host_bnf>::value); + +BOOST_STATIC_ASSERT( + std::is_copy_assignable< + host_bnf>::value); + class host_bnf_test { public: @@ -25,7 +37,7 @@ public: host_bnf check( string_view s, - rfc::host_kind k) + host_type ht) { host_bnf h; error_code ec; @@ -34,7 +46,7 @@ public: parse(s, ec, h))) return {}; BOOST_TEST( - h.kind() == k); + h.host_type() == ht); return h; } @@ -53,26 +65,27 @@ public: good("boost.org"); good("999.0.0.1"); - BOOST_TEST(check("", host_kind::domain) + BOOST_TEST(check("", host_type::name) .str() == ""); - BOOST_TEST(check("1.2.3.999", host_kind::domain) - .get_domain().str == "1.2.3.999"); + BOOST_TEST(check("1.2.3.999", host_type::name) + .get_name().str == "1.2.3.999"); - BOOST_TEST(check("1.2.3.4", host_kind::ipv4) - .get_ipv4().octets == ( + BOOST_TEST(check("1.2.3.4", host_type::ipv4) + .get_ipv4().to_bytes() == ( std::array({1,2,3,4}))); - BOOST_TEST(check("[1:2:3:4:5:6:7:8]", host_kind::ipv6) - .get_ipv6().octets == ( + BOOST_TEST((check( + "[1:2:3:4:5:6:7:8]", host_type::ipv6) + .get_ipv6().octets == std::array( {0,1,0,2,0,3,0,4,0,5,0,6,0,7,0,8}))); - BOOST_TEST(check("[v1.2]", host_kind::ipv_future) + BOOST_TEST(check("[v1.2]", host_type::ipvfuture) .get_ipv_future() == "v1.2"); - BOOST_TEST(check("www.example.com", host_kind::domain) - .get_domain().str == "www.example.com"); + BOOST_TEST(check("www.example.com", host_type::name) + .get_name().str == "www.example.com"); } }; diff --git a/test/rfc/ipv4_address_bnf.cpp b/test/rfc/ipv4_address_bnf.cpp index 90bdba57..5f466066 100644 --- a/test/rfc/ipv4_address_bnf.cpp +++ b/test/rfc/ipv4_address_bnf.cpp @@ -29,16 +29,8 @@ public: BOOST_TEST(parse(s, ec, t)); if(! BOOST_TEST(! ec)) return; - std::uint32_t v1 = - (static_cast( - t.octets[0]) << 24) | - (static_cast( - t.octets[1]) << 16) | - (static_cast( - t.octets[2]) << 8) | - (static_cast( - t.octets[3]) ); - BOOST_TEST(v1 == v); + BOOST_TEST( + t.addr.to_uint() == v); } void diff --git a/test/url_view.cpp b/test/url_view.cpp index 75710ca9..304a9d77 100644 --- a/test/url_view.cpp +++ b/test/url_view.cpp @@ -20,230 +20,7 @@ namespace urls { class url_view_test { public: - test_suite::log_type log; - - void - testView() - { - BOOST_TEST(url_view().host_type() == host_type::none); - BOOST_TEST(url_view("//").host_type() == host_type::none); - BOOST_TEST(url_view("//127.0.0.1").host_type() == host_type::ipv4); - BOOST_TEST(url_view("//0.0.0.0").host_type() == host_type::ipv4); - BOOST_TEST(url_view("//255.255.255.255").host_type() == host_type::ipv4); - BOOST_TEST(url_view("//0.0.0.").host_type() == host_type::name); - BOOST_TEST(url_view("//127.00.0.1").host_type() == host_type::name); - BOOST_TEST(url_view("//999.0.0.0").host_type() == host_type::name); - BOOST_TEST(url_view("//example.com").host_type() == host_type::name); - BOOST_TEST(url_view("//127.0.0.1.9").host_type() == host_type::name); - - url_view const v("http://username:pass@example.com:80/path/to/file.txt?k1=v1&k2=v2"); - BOOST_TEST(v.encoded_url() == "http://username:pass@example.com:80/path/to/file.txt?k1=v1&k2=v2"); - BOOST_TEST(v.encoded_origin() == "http://username:pass@example.com:80"); - BOOST_TEST(v.encoded_authority() == "username:pass@example.com:80"); - BOOST_TEST(v.scheme() == "http"); - BOOST_TEST(v.encoded_username() == "username"); - BOOST_TEST(v.encoded_password() == "pass"); - BOOST_TEST(v.encoded_userinfo() == "username:pass"); - BOOST_TEST(v.encoded_host() == "example.com"); - BOOST_TEST(v.has_port()); - BOOST_TEST(v.port() == "80"); - BOOST_TEST(v.encoded_host_and_port() == "example.com:80"); - BOOST_TEST(v.encoded_path() == "/path/to/file.txt"); - BOOST_TEST(v.encoded_query() == "k1=v1&k2=v2"); - BOOST_TEST(v.encoded_fragment() == ""); - - BOOST_TEST(v.username() == "username"); - BOOST_TEST(v.password() == "pass"); - BOOST_TEST(v.host() == "example.com"); - BOOST_TEST(v.query() == "k1=v1&k2=v2"); - BOOST_TEST(v.fragment() == ""); - } - - //------------------------------------------------------ - - void - testUser() - { - BOOST_TEST(url_view().username() == ""); - BOOST_TEST(url_view("//x/").username() == ""); - BOOST_TEST(url_view("//x@/").username() == "x"); - BOOST_TEST(url_view("//x:@/").username() == "x"); - BOOST_TEST(url_view("//x:y@/").username() == "x"); - BOOST_TEST(url_view("//:y@/").username() == ""); - BOOST_TEST(url_view("//:@/").username() == ""); - BOOST_TEST(url_view("//@/").username() == ""); - BOOST_TEST(url_view("//%3A@/").username() == ":"); - - BOOST_TEST(url_view().encoded_username() == ""); - BOOST_TEST(url_view("//x/").encoded_username() == ""); - BOOST_TEST(url_view("//x@/").encoded_username() == "x"); - BOOST_TEST(url_view("//x:@/").encoded_username() == "x"); - BOOST_TEST(url_view("//x:y@/").encoded_username() == "x"); - BOOST_TEST(url_view("//:y@/").encoded_username() == ""); - BOOST_TEST(url_view("//:@/").encoded_username() == ""); - BOOST_TEST(url_view("//@/").encoded_username() == ""); - BOOST_TEST(url_view("//%3A@/").encoded_username() == "%3A"); - } - - //------------------------------------------------------ - - void - testHostAndPort() - { - BOOST_TEST(url_view().encoded_host_and_port() == ""); - BOOST_TEST(url_view("//").encoded_host_and_port() == ""); - BOOST_TEST(url_view("//x").encoded_host_and_port() == "x"); - BOOST_TEST(url_view("//x:").encoded_host_and_port() == "x:"); - BOOST_TEST(url_view("//x:0").encoded_host_and_port() == "x:0"); - BOOST_TEST(url_view("//x:0/").encoded_host_and_port() == "x:0"); - } - - void - testIPv4() - { - BOOST_TEST(url_view().host_type() == host_type::none); - BOOST_TEST(url_view("//0.0.0.0").host_type() == host_type::ipv4); - BOOST_TEST(url_view("//255.255.255.255").host_type() == host_type::ipv4); - BOOST_TEST(url_view("//255.255.255.255").host_type() == host_type::ipv4); - BOOST_TEST(url_view("//256.255.255.255").host_type() == host_type::name); - BOOST_TEST(url_view("//256.255.255.").host_type() == host_type::name); - BOOST_TEST(url_view("//00.0.0.0").host_type() == host_type::name); - } - - void - testIPv6() - { - BOOST_TEST(url_view("//[::]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[0000:0000:0000:0000:0000:0000:0000:0000]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[1234:5678:9ABC:DEF0:0000:0000:0000:0000]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[3FFE:1900:4545:3:200:F8FF:FE21:67CF]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[FE80:0:0:0:200:F8FF:FE21:67CF]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[2001:0DB8:0A0B:12F0:0000:0000:0000:0001]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[2001:DB8:3333:4444:5555:6666:7777:8888]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[2001:DB8:3333:4444:CCCC:DDDD:EEEE:FFFF]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[::]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[2001:DB8::]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[::1234:5678]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[2001:DB8::1234:5678]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[2001:0DB8:0001:0000:0000:0AB9:C0A8:0102]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[2001:DB8:1::AB9:C0A8:102]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[684D:1111:222:3333:4444:5555:6:77]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[0:0:0:0:0:0:0:0]").host_type() == host_type::ipv6); - - BOOST_TEST(url_view("//[::1:2:3:4:5]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[0:0:0:1:2:3:4:5]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[1:2::3:4:5]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[1:2:0:0:0:3:4:5]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[1:2:3:4:5::]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[1:2:3:4:5:0:0:0]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[0:0:0:0:0:FFFF:102:405]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[::]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[::0]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[::1]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[0:0:0::1]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[FFFF::1]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[FFFF:0:0:0:0:0:0:1]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[2001:0DB8:0A0B:12F0:0:0:0:1]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[2001:DB8:A0B:12F0::1]").host_type() == host_type::ipv6); - - BOOST_TEST(url_view("//[::FFFF:1.2.3.4]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[0:0:0:0:0:0:1.2.3.4]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[::1.2.3.4]").host_type() == host_type::ipv6); - - BOOST_TEST_NO_THROW(url_view("//[fe80:0:0:0:200:f8ff:fe21:67cf]")); - BOOST_TEST_NO_THROW(url_view("//[2001:0db8:0a0b:12f0:0000:0000:0000:0001]")); - BOOST_TEST_NO_THROW(url_view("//[2001:db8:3333:4444:5555:6666:7777:8888]")); - BOOST_TEST_NO_THROW(url_view("//[2001:db8:3333:4444:CCCC:DDDD:EEEE:FFFF]")); - BOOST_TEST_NO_THROW(url_view("//[::]")); - BOOST_TEST_NO_THROW(url_view("//[2001:db8::]")); - BOOST_TEST_NO_THROW(url_view("//[::1234:5678]")); - BOOST_TEST_NO_THROW(url_view("//[2001:db8::1234:5678]")); - BOOST_TEST_NO_THROW(url_view("//[2001:0db8:0001:0000:0000:0ab9:C0A8:0102]")); - BOOST_TEST_NO_THROW(url_view("//[2001:db8:1::ab9:C0A8:102]")); - BOOST_TEST_NO_THROW(url_view("//[684D:1111:222:3333:4444:5555:6:77]")); - BOOST_TEST_NO_THROW(url_view("//[0:0:0:0:0:0:0:0]")); - - BOOST_TEST_THROWS(url_view("http://[0]"), invalid_part); - BOOST_TEST_THROWS(url_view("//[0:1.2.3.4]"), invalid_part); - BOOST_TEST_THROWS(url_view("//[0:0:0:0:0:0:0::1.2.3.4]"), invalid_part); - BOOST_TEST_THROWS(url_view("http://[0:0:0:0:0:0:0:1.2.3.4]"), invalid_part); - BOOST_TEST_THROWS(url_view("http://[::FFFF:999.2.3.4]"), invalid_part); - - // coverage - BOOST_TEST_THROWS(url_view("//["), invalid_part); - BOOST_TEST_THROWS(url_view("//[::"), invalid_part); - BOOST_TEST_THROWS(url_view("//[0"), invalid_part); - BOOST_TEST_THROWS(url_view("//[:"), invalid_part); - BOOST_TEST_THROWS(url_view("//[::0::]"), invalid_part); - BOOST_TEST_THROWS(url_view("//[:0::]"), invalid_part); - BOOST_TEST_THROWS(url_view("//[0::0:x]"), invalid_part); - BOOST_TEST_THROWS(url_view("//[x::]"), invalid_part); - BOOST_TEST_THROWS(url_view("//[0:12"), invalid_part); - BOOST_TEST_THROWS(url_view("//[0:123"), invalid_part); - BOOST_TEST_THROWS(url_view("//[::1.]"), invalid_part); - BOOST_TEST_THROWS(url_view("//[::1.2]"), invalid_part); - BOOST_TEST_THROWS(url_view("//[::1.2"), invalid_part); - BOOST_TEST_THROWS(url_view("//[::1.2x]"), invalid_part); - BOOST_TEST_THROWS(url_view("//[::1.2.]"), invalid_part); - BOOST_TEST_THROWS(url_view("//[::1.2.3"), invalid_part); - BOOST_TEST_THROWS(url_view("//[::1.2.3]"), invalid_part); - BOOST_TEST_THROWS(url_view("//[::1.2.3x]"), invalid_part); - BOOST_TEST_THROWS(url_view("//[::1.2.3.]"), invalid_part); - BOOST_TEST_THROWS(url_view("//[::1.2.3.4x]"), invalid_part); - - BOOST_TEST(url_view("//[1:2:3:4:5:6::7]").host_type() == host_type::ipv6); - BOOST_TEST(url_view("//[1:2:3:4:5:6:7::]").host_type() == host_type::ipv6); - } - - void - testHost() - { - BOOST_TEST(url_view().host() == ""); - BOOST_TEST(url_view("//?#").host() == ""); - BOOST_TEST(url_view("//x?#").host() == "x"); - BOOST_TEST(url_view("//%2F").host() == "/"); - BOOST_TEST(url_view("//%2F?#").host() == "/"); - - BOOST_TEST(url_view().encoded_host() == ""); - BOOST_TEST(url_view("//?#").encoded_host() == ""); - BOOST_TEST(url_view("//x?#").encoded_host() == "x"); - BOOST_TEST(url_view("//%2F").encoded_host() == "%2F"); - BOOST_TEST(url_view("//%2F?#").encoded_host() == "%2F"); - - testIPv4(); - testIPv6(); - } - - void - testPort() - { - BOOST_TEST(! url_view().has_port()); - BOOST_TEST(url_view().port() == ""); - BOOST_TEST(url_view("//x:/").port() == ""); - BOOST_TEST(url_view("//x:/").has_port()); - BOOST_TEST(url_view("//x:80/").port() == "80"); - BOOST_TEST(url_view("//x:80/").has_port()); - } - - //------------------------------------------------------ - - void - testPath() - { - BOOST_TEST(url_view().encoded_path() == ""); - BOOST_TEST(url_view("x:a").encoded_path() == "a"); - BOOST_TEST(url_view("x:/a").encoded_path() == "/a"); - BOOST_TEST(url_view("x://y/a").encoded_path() == "/a"); - - BOOST_TEST(url_view("x").encoded_path() == "x"); - BOOST_TEST(url_view("x/").encoded_path() == "x/"); - BOOST_TEST(url_view("x//").encoded_path() == "x//"); - - BOOST_TEST(url_view("/").encoded_path() == "/"); - - testSegments(); - } - +#if 0 void testSegments() { @@ -295,11 +72,12 @@ public: BOOST_TEST(it->encoded_string() == "path"); } } +#endif //-------------------------------------------- void - testParseUri() + testParse() { error_code ec; auto const u = urls::parse_uri( @@ -318,22 +96,6 @@ public: BOOST_TEST(u->encoded_fragment() == "frag"); } - void - testShared() - { - string_view s = - "http://username:pass@www.boost.org:8080/x/y/z?a=b&c=3#frag"; - std::shared_ptr sp; - { - auto const u = urls::parse_uri(s); - sp = u.make_shared(); - BOOST_TEST( - u.encoded_url().data() != - sp->encoded_url().data()); - } - BOOST_TEST(sp->encoded_url() == s); - } - void testScheme() { @@ -435,6 +197,38 @@ public: } } + void + testHost() + { + { + auto u = parse_uri( + "http://www.example.com/"); + BOOST_TEST(u.encoded_hostname() == + "www.example.com"); + BOOST_TEST(u.host_type() == + host_type::name); + } + { + auto u = parse_uri( + "http://192.168.0.1/"); + BOOST_TEST(u.host_type() == + host_type::ipv4); + BOOST_TEST(u.encoded_hostname() == + "192.168.0.1"); + BOOST_TEST( + u.ipv4_address().to_uint() == + 0xc0a80001); + } + { + auto u = parse_uri( + "http://[1::6:192.168.0.1]:8080/"); + BOOST_TEST(u.encoded_hostname() == + "[1::6:192.168.0.1]"); + BOOST_TEST(u.host_type() == + host_type::ipv6); + } + } + void testQuery() { @@ -613,24 +407,34 @@ public: } } + void + testShared() + { + string_view s = + "http://username:pass@www.boost.org:8080/x/y/z?a=b&c=3#frag"; + std::shared_ptr sp; + { + auto const u = urls::parse_uri(s); + sp = u.make_shared(); + BOOST_TEST( + u.encoded_url().data() != + sp->encoded_url().data()); + } + BOOST_TEST(sp->encoded_url() == s); + } + //-------------------------------------------- void run() { - testView(); - - testHostAndPort(); - testHost(); - testPort(); - testPath(); - - testParseUri(); - testShared(); + testParse(); testScheme(); testUserinfo(); + testHost(); testQuery(); testFragment(); + testShared(); } };