Commit 66e71713 authored by Joseph Noir's avatar Joseph Noir

Add URI class

Still in progress, test fail to parse ipv6 addresses and invalid URIs
have to be tested and filtered.
parent 67bc5c0b
...@@ -22,6 +22,7 @@ set (LIBCAF_IO_SRCS ...@@ -22,6 +22,7 @@ set (LIBCAF_IO_SRCS
src/test_multiplexer.cpp src/test_multiplexer.cpp
src/acceptor_manager.cpp src/acceptor_manager.cpp
src/multiplexer.cpp src/multiplexer.cpp
src/uri.cpp
# BASP files # BASP files
src/header.cpp src/header.cpp
src/message_type.cpp src/message_type.cpp
......
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#ifndef CAF_IO_URI_HPP
#define CAF_IO_URI_HPP
#include <string>
#include <ostream>
#include <utility>
#include "caf/optional.hpp"
#include "caf/intrusive_ptr.hpp"
#include "caf/meta/type_name.hpp"
#include "caf/detail/comparable.hpp"
namespace caf {
namespace io {
namespace detail {
class uri_private;
void intrusive_ptr_add_ref(uri_private* p);
void intrusive_ptr_release(uri_private* p);
} // namespace detail
namespace {
using str_bounds = std::pair<std::string::iterator, std::string::iterator>;
} // namespace anonymous
///
/// @brief Uniform Resource Identifier (as defined in RFC 3986).
/// @include uri_documentation.txt
/// @note The documentation of the accessors are taken from RFC 3986.
///
class uri : caf::detail::comparable<uri, uri>,
caf::detail::comparable<uri, const char*>,
caf::detail::comparable<uri, std::string> {
public:
// required by util::comparable<uri, uri>
inline int compare(const uri& what) const {
return (this == &what) ? 0 : str().compare(what.str());
}
// required by util::comparable<uri, std::string>
inline int compare(const std::string& what) const {
return str().compare(what);
}
// required by util::comparable<uri, const char*>
inline int compare(const char* what) const {
// treat a NULL string like an empty string
return (what) ? str().compare(what) : str().compare("");
}
///
/// @brief Create an empty URI.
///
uri();
///
/// @brief Create this object as a copy of @p other.
/// @param other The original {@link caf::io::uri uri} object.
/// @note {@link caf::io::uri uri} is implicit shared, thus copy
/// operations are very fast and lightweight.
///
uri(const uri& other);
///
/// @brief Create an URI from @p uri_str.
///
/// If @p uri_str could not be parsed to a valid URI, then this URI
/// object will be empty.
///
/// @param uri_str An URI encoded as a string.
///
/// @warning Let <code>a</code> be a string then the assertion
/// <code>a.empty() == uri(a).empty()</code> fails, if
/// <code>a</code> is not empty, but does not describe a valid URI
/// (e.g. "Hello World" is a string, but is an invalid URI).
///
static optional<uri> make(const std::string& uri_str);
///
/// @brief Create an URI from @p uri_str_c_str.
/// @param uri_c_str An URI encoded as a C-string.
/// @see uri(const std::string&)
///
static optional<uri> make(const char* uri_c_str);
///
/// @brief Get the string describing this URI.
/// @returns The full string representation of this URI.
///
const std::string& str() const;
///
/// @brief Get the string describing this uri as a C-string.
/// @returns The full string representation of this URI as C-string.
/// @note Equal to <code>str().c_str()</code>.
///
inline const char* c_str() const { return str().c_str(); }
/**
* @brief Check if this URI is empty.
* @returns <code>true</code> if this URI is empty;
* otherwise <code>false</code>.
*/
bool empty() const { return str().empty(); }
///
/// @brief Get the host subcomponent of authority.
///
/// The host subcomponent of authority is identified by an IP literal
/// encapsulated within square brackets, an IPv4 address in dotted-
/// decimal form, or a registered name.
///
/// @returns The host subcomponent of {@link authority()}.
///
const str_bounds& host() const;
///
/// @brief Check if {@link host()} returns an IPv4 address.
/// @note The testing is done in the constructor, so this member
/// function only checks an internal flag (and has no
/// other overhead!).
/// @returns <code>true</code> if the host subcomponent of {@link authority()}
/// returns a string that describes a valid IPv4 address;
/// otherwise <code>false</code>.
///
bool host_is_ipv4addr() const;
///
/// @brief Check if {@link host()} returns an IPv6 address.
/// @note Returns true if host matches the regex
/// <code>[a-f0-9:\\.]</code> so {@link host()} might be an
/// invalid ipv6 address.
/// @note The testing is done in the constructor, so this member
/// function only checks an internal flag (and has no
/// other overhead!).
/// @returns <code>true</code> if the host subcomponent of {@link authority()}
/// returns a string that describes an IPv6 address;
/// otherwise <code>false</code>.
/// @warning This member function does not guarantee, that {@link host()}
/// returns a <b>valid</b> IPv6 address.
///
bool host_is_ipv6addr() const;
///
/// @brief Get the port subcomponent of authority.
///
/// Port is either empty or a decimal number (between 0 and 65536).
/// @returns A string representation of the port
/// subcomponent of {@link authority()}.
///
const str_bounds& port() const;
///
/// @brief Get the port subcomponent as integer value.
///
/// This value is always 0 if <code>port().empty() == true</code>.
/// @returns An integer (16-bit, unsigned) representation of the port
/// subcomponent of {@link authority()}.
///
uint16_t port_as_int() const;
///
/// @brief Get the path component of this URI object.
///
/// The path component contains data that serves to identifiy a resource
/// within the scope of the URI's scheme and naming authority (if any).
/// @returns The path component.
///
const str_bounds& path() const;
///
/// @brief Get the query component of this URI object.
///
/// The query component contains non-hierarchical data that, along with
/// data in the path component (Section 3.3), serves to identify a
/// resource within the scope of the URI's scheme and naming authority
/// (if any).
/// @returns The query component.
///
const str_bounds& query() const;
///
/// @brief Get the scheme component of this URI object.
///
/// Each URI begins with a scheme name that refers to a specification for
/// assigning identifiers within that scheme.
/// @returns The scheme component.
///
const str_bounds& scheme() const;
///
/// @brief Get the fragment component of this URI object.
///
/// The fragment identifier component of a URI allows indirect
/// identification of a secondary resource by reference to a primary
/// resource and additional identifying information.
/// @returns The fragment component.
///
const str_bounds& fragment() const;
///
/// @brief Get the authority component of this URI object.
///
/// The subcomponents of authority could be queried with
/// {@link user_information()}, {@link host()} and {@link port()}.
/// @returns The authority component.
///
const str_bounds& authority() const;
///
/// @brief Exchanges the contents of <code>this</code> and @p other.
/// @param other {@link caf::io::uri uri} object that should exchange its
/// content with the content of <code>this</code>.
///
void swap(uri& other);
///
/// @brief Equivalent to <code>uri(other).swap(*this)</code>.
/// @param other Original {@link caf::io::uri uri} object.
/// @returns <code>*this</code>.
///
uri& operator=(const uri& other);
/// @cond private
template <class Inspector>
friend typename Inspector::result_type inspect(Inspector& f, uri& u) {
return f(meta::type_name("uri"), u.c_str());
}
/// @endcond
private:
uri(detail::uri_private* d);
intrusive_ptr<detail::uri_private> d_;
};
} // namespace io
} // namespace caf
namespace std {
inline ostream& operator<<(ostream& ostr, const caf::io::uri& what) {
return (ostr << what.str());
}
} // namespace std
#endif // CAF_IO_URI_HPP
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include <string>
#include <utility>
#include <iostream>
#include "caf/ref_counted.hpp"
#include "caf/intrusive_ptr.hpp"
#include "caf/io/uri.hpp"
using namespace std;
namespace {
using str_bounds = std::pair<std::string::iterator, std::string::iterator>;
} // namespace <anonymous>
// foo://example.com:8042/over/there?name=ferret#nose
// \_/ \______________/\_________/ \_________/ \__/
// | | | | |
// scheme authority path query fragment
// | _____________________|__
// / \ / \.
// urn:example:animal:ferret:nose
namespace caf {
namespace io {
namespace detail {
class uri_private : public ref_counted {
friend optional<uri> uri::make(const string& uri_str);
enum {
default_flag,
ipv4_flag,
ipv6_flag
} m_flag_;
// complete uri
string m_uri_;
// uri components
str_bounds m_path_;
str_bounds m_query_;
str_bounds m_scheme_;
str_bounds m_fragment_;
str_bounds m_authority_;
// authority subcomponents
str_bounds m_host_;
str_bounds m_port_;
// convenience fields
uint16_t m_int_port_;
void clear() {
m_uri_.clear();
m_path_ = make_tuple(m_uri_.end(),m_uri_.end());
m_query_ = make_tuple(m_uri_.end(),m_uri_.end());
m_scheme_ = make_tuple(m_uri_.end(),m_uri_.end());
m_fragment_ = make_tuple(m_uri_.end(),m_uri_.end());
m_authority_ = make_tuple(m_uri_.end(),m_uri_.end());
}
// this parses the given uri to the form
// {scheme} {authority} {path} {query} {fragment}
bool parse_uri(const string& what) {
m_flag_ = default_flag;
auto empty = [](const str_bounds& bounds) {
return bounds.first >= bounds.second;
};
m_uri_.clear();
m_uri_ = what;
m_host_ = make_pair(begin(m_uri_), begin(m_uri_));
m_port_ = make_pair(begin(m_uri_), begin(m_uri_));
m_path_ = make_pair(begin(m_uri_), begin(m_uri_));
m_query_ = make_pair(begin(m_uri_), begin(m_uri_));
m_scheme_ = make_pair(begin(m_uri_), begin(m_uri_));
m_fragment_ = make_pair(begin(m_uri_), begin(m_uri_));
m_authority_ = make_pair(begin(m_uri_), begin(m_uri_));
// find ':' for scheme boundries
auto from_itr = begin(m_uri_);
auto to_itr = find(begin(m_uri_), end(m_uri_), ':');
if (to_itr == m_uri_.end()) {
return false;
}
m_scheme_ = make_pair(from_itr, to_itr);
from_itr = to_itr + 1;
// if the next two characters are '/', an authority follows the scheme
char seperator[] = { '/', '/' };
auto seperator_itr = search(from_itr, end(m_uri_),
begin(seperator), end(seperator));
if (seperator_itr != end(m_uri_)) {
from_itr += 2;
to_itr = find_if(from_itr, end(m_uri_), [](const char& c) {
return c == '/' || c == '#' || c == '?';
});
m_authority_ = make_pair(from_itr, to_itr);
if (empty(m_authority_)) {
return false;
}
auto at = find(m_authority_.first, m_authority_.second, '@');
if (at != m_authority_.second) {
}
// For our purpose we assume not to have a user info
auto col = find(m_authority_.first, m_authority_.second, ':');
if (col != m_authority_.second) {
m_host_ = make_pair(m_authority_.first, col);
m_port_ = make_pair(col + 1, m_authority_.second);
} else {
m_host_ = m_authority_;
m_port_ = make_pair(m_authority_.second, m_authority_.second);
}
if (!empty(m_host_) && *m_host_.first == '[') {
// ipv6 address
m_flag_ = ipv6_flag;
// erase leading "[" and trailing "]"
m_host_.first += 1;
m_host_.second -= 1;
} else if (!empty(m_host_)) {
m_flag_ = ipv4_flag;
}
if (empty(m_port_)) {
m_int_port_ = 0;
} else {
auto port_str = string(m_port_.first, m_port_.second);
m_int_port_ = static_cast<uint16_t>(atoi(port_str.c_str()));
}
from_itr = to_itr;
}
from_itr = find_if(from_itr, end(m_uri_), [](const char& c) {
return c != '/';
});
to_itr = find_if(from_itr, end(m_uri_), [](const char& c) {
return c == '#' || c == '?';
});
m_path_ = make_pair(from_itr, to_itr);
from_itr = to_itr;
if (from_itr != end(m_uri_) && *from_itr == '?') {
from_itr += 1;
to_itr = find(from_itr, end(m_uri_), '#');
m_query_ = make_pair(from_itr, to_itr);
from_itr = to_itr;
}
if (from_itr != end(m_uri_) && *from_itr == '#') {
from_itr += 1;
m_fragment_ = make_pair(from_itr, end(m_uri_));
}
return true;
}
public:
inline uri_private() { }
inline const str_bounds& path() const { return m_path_; }
inline const str_bounds& query() const { return m_query_; }
inline const str_bounds& scheme() const { return m_scheme_; }
inline const str_bounds& fragment() const { return m_fragment_; }
inline const str_bounds& authority() const { return m_authority_; }
inline const string& as_string() const { return m_uri_; }
inline const str_bounds& host() const { return m_host_; }
inline const str_bounds& port() const { return m_port_; }
inline uint16_t port_as_int() const { return m_int_port_; }
inline bool host_is_ipv4addr() const {
return m_flag_ == ipv4_flag;
}
inline bool host_is_ipv6addr() const {
return m_flag_ == ipv6_flag;
}
};
void intrusive_ptr_add_ref(uri_private* p) {
p->ref();
}
void intrusive_ptr_release(uri_private* p) {
p->deref();
}
namespace {
intrusive_ptr<uri_private> m_default_uri_private(new uri_private);
} // namespace <anonymous>
} // namespace detail
} // namespace io
} // namespace caf
namespace caf {
namespace io {
optional<uri> uri::make(const string& uri_str) {
detail::uri_private* result = new detail::uri_private;
if (result->parse_uri(uri_str))
return uri{result};
else {
delete result;
return {};
}
}
optional<uri> uri::make(const char* cstr) {
string tmp(cstr);
return make(tmp);
}
uri::uri() : d_(detail::m_default_uri_private) {
// nop
}
uri::uri(detail::uri_private* d) : d_(d) {
// nop
}
uri::uri(const uri& other) : d_(other.d_) {
// nop
}
uri& uri::operator=(const uri& other) {
d_ = other.d_;
return *this;
}
const string& uri::str() const {
return d_->as_string();
}
const str_bounds& uri::host() const {
return d_->host();
}
const str_bounds& uri::port() const {
return d_->port();
}
uint16_t uri::port_as_int() const {
return d_->port_as_int();
}
const str_bounds& uri::path() const {
return d_->path();
}
const str_bounds& uri::query() const {
return d_->query();
}
const str_bounds& uri::scheme() const {
return d_->scheme();
}
const str_bounds& uri::fragment() const {
return d_->fragment();
}
const str_bounds& uri::authority() const {
return d_->authority();
}
bool uri::host_is_ipv4addr() const {
return d_->host_is_ipv4addr();
}
bool uri::host_is_ipv6addr() const {
return d_->host_is_ipv6addr();
}
} // namespace io
} // namespace caf
/******************************************************************************
* ____ _ _____ *
* / ___| / \ | ___| C++ *
* | | / _ \ | |_ Actor *
* | |___ / ___ \| _| Framework *
* \____/_/ \_|_| *
* *
* Copyright (C) 2011 - 2016 *
* Dominik Charousset <dominik.charousset (at) haw-hamburg.de> *
* *
* Distributed under the terms and conditions of the BSD 3-Clause License or *
* (at your option) under the terms and conditions of the Boost Software *
* License 1.0. See accompanying files LICENSE and LICENSE_ALTERNATIVE. *
* *
* If you did not receive a copy of the license files, see *
* http://opensource.org/licenses/BSD-3-Clause and *
* http://www.boost.org/LICENSE_1_0.txt. *
******************************************************************************/
#include <utility>
#include "caf/config.hpp"
#define CAF_SUITE io_uri
#include "caf/test/unit_test.hpp"
#include "caf/all.hpp"
#include "caf/io/all.hpp"
#include "caf/io/uri.hpp"
using std::cout;
using std::cerr;
using std::endl;
using namespace caf;
using namespace caf::io;
namespace {
using str_bounds = std::pair<std::string::iterator, std::string::iterator>;
// building blocks
#define MY_SCHEME "my_scheme"
#define MY_HOST "my_host"
#define MY_V4_HOST "1.2.3.4"
#define MY_V6_HOST "2001:db8::ff00:42:8329"
#define MY_PORT "8080"
#define MY_PATH "my_path"
#define MY_QUERY "my_query"
#define MY_FRAGMENT "my_fragment"
// valid URIs
constexpr char uri_00[] = MY_SCHEME ":";
constexpr char uri_01[] = MY_SCHEME ":" MY_PATH;
constexpr char uri_02[] = MY_SCHEME ":/" MY_PATH;
constexpr char uri_03[] = MY_SCHEME "://" MY_HOST;
constexpr char uri_04[] = MY_SCHEME "://" MY_HOST ":" MY_PORT;
constexpr char uri_05[] = MY_SCHEME "://" MY_HOST ":" MY_PORT "/" MY_PATH;
constexpr char uri_06[] = MY_SCHEME "://" MY_HOST ":" MY_PORT "/" MY_PATH "?"
MY_QUERY;
constexpr char uri_07[] = MY_SCHEME "://" MY_HOST ":" MY_PORT "/" MY_PATH "?"
MY_QUERY "#" MY_FRAGMENT;
constexpr char uri_08[] = MY_SCHEME "://" MY_HOST ":" MY_PORT "?" MY_QUERY;
constexpr char uri_09[] = MY_SCHEME "://" MY_HOST ":" MY_PORT "#" MY_FRAGMENT;
constexpr char uri_10[] = MY_SCHEME "://" ":" MY_PORT;
// invalid URIs
class config : public actor_system_config {
public:
config() {
load<io::middleman>();
actor_system_config::parse(test::engine::argc(),
test::engine::argv());
}
};
bool empty(const str_bounds& bounds) {
return bounds.first >= bounds.second;
}
std::string string_of(const str_bounds& bounds) {
return std::string(bounds.first, bounds.second);
}
} // namespace <anonymous>
CAF_TEST(valid_uris) {
uri u;
CAF_CHECK(u.empty());
CAF_CHECK_EQUAL("", u.str());
CAF_CHECK(empty(u.scheme()));
CAF_CHECK(empty(u.host()));
CAF_CHECK(empty(u.port()));
CAF_CHECK(empty(u.path()));
CAF_CHECK(empty(u.query()));
CAF_CHECK(empty(u.fragment()));
auto u_00 = uri::make(uri_00).value();
CAF_CHECK_EQUAL(uri_00, u_00.str());
CAF_CHECK(!empty(u_00.scheme()));
CAF_CHECK(empty(u_00.host()));
CAF_CHECK(empty(u_00.port()));
CAF_CHECK(empty(u_00.path()));
CAF_CHECK(empty(u_00.query()));
CAF_CHECK(empty(u_00.fragment()));
CAF_CHECK_EQUAL(string_of(u_00.scheme()), MY_SCHEME);
auto u_01 = uri::make(uri_01).value();
CAF_CHECK_EQUAL(uri_01, u_01.str());
CAF_CHECK(!empty(u_01.scheme()));
CAF_CHECK(empty(u_01.host()));
CAF_CHECK(empty(u_01.port()));
CAF_CHECK(!empty(u_01.path()));
CAF_CHECK(empty(u_01.query()));
CAF_CHECK(empty(u_01.fragment()));
CAF_CHECK_EQUAL(string_of(u_01.scheme()), MY_SCHEME);
CAF_CHECK_EQUAL(string_of(u_01.path()), MY_PATH);
auto u_02 = uri::make(uri_02).value();
CAF_CHECK_EQUAL(uri_02, u_02.str());
CAF_CHECK(!empty(u_02.scheme()));
CAF_CHECK(empty(u_02.host()));
CAF_CHECK(empty(u_02.port()));
CAF_CHECK(!empty(u_02.path()));
CAF_CHECK(empty(u_02.query()));
CAF_CHECK(empty(u_02.fragment()));
CAF_CHECK_EQUAL(string_of(u_02.scheme()), MY_SCHEME);
CAF_CHECK_EQUAL(string_of(u_02.path()), MY_PATH);
auto u_03 = uri::make(uri_03).value();
CAF_CHECK_EQUAL(uri_03, u_03.str());
CAF_CHECK(!empty(u_03.scheme()));
CAF_CHECK(!empty(u_03.host()));
CAF_CHECK(empty(u_03.port()));
CAF_CHECK(empty(u_03.path()));
CAF_CHECK(empty(u_03.query()));
CAF_CHECK(empty(u_03.fragment()));
CAF_CHECK_EQUAL(string_of(u_03.scheme()), MY_SCHEME);
CAF_CHECK_EQUAL(string_of(u_03.host()), MY_HOST);
auto u_04 = uri::make(uri_04).value();
CAF_CHECK(!empty(u_04.scheme()));
CAF_CHECK(!empty(u_04.host()));
CAF_CHECK(!empty(u_04.port()));
CAF_CHECK(empty(u_04.path()));
CAF_CHECK(empty(u_04.query()));
CAF_CHECK(empty(u_04.fragment()));
CAF_CHECK_EQUAL(string_of(u_04.scheme()), MY_SCHEME);
CAF_CHECK_EQUAL(string_of(u_04.host()), MY_HOST);
CAF_CHECK_EQUAL(string_of(u_04.port()), MY_PORT);
auto u_05 = uri::make(uri_05).value();
CAF_CHECK_EQUAL(uri_05, u_05.str());
CAF_CHECK(!empty(u_05.scheme()));
CAF_CHECK(!empty(u_05.host()));
CAF_CHECK(!empty(u_05.port()));
CAF_CHECK(!empty(u_05.path()));
CAF_CHECK(empty(u_05.query()));
CAF_CHECK(empty(u_05.fragment()));
CAF_CHECK_EQUAL(string_of(u_05.scheme()), MY_SCHEME);
CAF_CHECK_EQUAL(string_of(u_05.host()), MY_HOST);
CAF_CHECK_EQUAL(string_of(u_05.port()), MY_PORT);
CAF_CHECK_EQUAL(string_of(u_05.path()), MY_PATH);
auto u_06 = uri::make(uri_06).value();
CAF_CHECK_EQUAL(uri_06, u_06.str());
CAF_CHECK(!empty(u_06.scheme()));
CAF_CHECK(!empty(u_06.host()));
CAF_CHECK(!empty(u_06.port()));
CAF_CHECK(!empty(u_06.path()));
CAF_CHECK(!empty(u_06.query()));
CAF_CHECK(empty(u_06.fragment()));
CAF_CHECK_EQUAL(string_of(u_06.scheme()), MY_SCHEME);
CAF_CHECK_EQUAL(string_of(u_06.host()), MY_HOST);
CAF_CHECK_EQUAL(string_of(u_06.port()), MY_PORT);
CAF_CHECK_EQUAL(string_of(u_06.path()), MY_PATH);
CAF_CHECK_EQUAL(string_of(u_06.query()), MY_QUERY);
auto u_07 = uri::make(uri_07).value();
CAF_CHECK_EQUAL(uri_07, u_07.str());
CAF_CHECK(!empty(u_07.scheme()));
CAF_CHECK(!empty(u_07.host()));
CAF_CHECK(!empty(u_07.port()));
CAF_CHECK(!empty(u_07.path()));
CAF_CHECK(!empty(u_07.query()));
CAF_CHECK(!empty(u_07.fragment()));
CAF_CHECK_EQUAL(string_of(u_07.scheme()), MY_SCHEME);
CAF_CHECK_EQUAL(string_of(u_07.host()), MY_HOST);
CAF_CHECK_EQUAL(string_of(u_07.port()), MY_PORT);
CAF_CHECK_EQUAL(string_of(u_07.path()), MY_PATH);
CAF_CHECK_EQUAL(string_of(u_07.query()), MY_QUERY);
CAF_CHECK_EQUAL(string_of(u_07.fragment()), MY_FRAGMENT);
auto u_08 = uri::make(uri_08).value();
CAF_CHECK_EQUAL(uri_08, u_08.str());
CAF_CHECK(!empty(u_08.scheme()));
CAF_CHECK(!empty(u_08.host()));
CAF_CHECK(!empty(u_08.port()));
CAF_CHECK(empty(u_08.path()));
CAF_CHECK(!empty(u_08.query()));
CAF_CHECK(empty(u_08.fragment()));
CAF_CHECK_EQUAL(string_of(u_08.scheme()), MY_SCHEME);
CAF_CHECK_EQUAL(string_of(u_08.host()), MY_HOST);
CAF_CHECK_EQUAL(string_of(u_08.port()), MY_PORT);
CAF_CHECK_EQUAL(string_of(u_08.query()), MY_QUERY);
auto u_09 = uri::make(uri_09).value();
CAF_CHECK_EQUAL(uri_09, u_09.str());
CAF_CHECK(!empty(u_09.scheme()));
CAF_CHECK(!empty(u_09.host()));
CAF_CHECK(!empty(u_09.port()));
CAF_CHECK(empty(u_09.path()));
CAF_CHECK(empty(u_09.query()));
CAF_CHECK(!empty(u_09.fragment()));
CAF_CHECK_EQUAL(string_of(u_09.scheme()), MY_SCHEME);
CAF_CHECK_EQUAL(string_of(u_09.host()), MY_HOST);
CAF_CHECK_EQUAL(string_of(u_09.port()), MY_PORT);
CAF_CHECK_EQUAL(string_of(u_09.fragment()), MY_FRAGMENT);
auto u_10 = uri::make(uri_10).value();
CAF_CHECK_EQUAL(uri_10, u_10.str());
CAF_CHECK(!empty(u_10.scheme()));
CAF_CHECK(empty(u_10.host()));
CAF_CHECK(!empty(u_10.port()));
CAF_CHECK(empty(u_10.path()));
CAF_CHECK(empty(u_10.query()));
CAF_CHECK(empty(u_10.fragment()));
CAF_CHECK_EQUAL(string_of(u_10.scheme()), MY_SCHEME);
CAF_CHECK_EQUAL(string_of(u_10.port()), MY_PORT);
}
CAF_TEST(ipv4_vs_ipv6) {
auto u_ipv4 = uri::make(MY_SCHEME "://" MY_V4_HOST ":" MY_PORT).value();
CAF_CHECK(u_ipv4.host_is_ipv4addr());
CAF_CHECK_EQUAL(string_of(u_ipv4.host()), MY_V4_HOST);
auto u_ipv6 = uri::make(MY_SCHEME "://[" MY_V6_HOST "]:" MY_PORT).value();
CAF_CHECK(u_ipv6.host_is_ipv6addr());
CAF_CHECK_EQUAL(string_of(u_ipv6.host()), MY_V6_HOST);
}
CAF_TEST(invalid_uri) {
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment