Commit ef16fe0d authored by Dominik Charousset's avatar Dominik Charousset

Add serialization code for URIs

parent c03dd9b0
...@@ -23,10 +23,12 @@ ...@@ -23,10 +23,12 @@
#include <string> #include <string>
#include <utility> #include <utility>
#include "caf/error.hpp"
#include "caf/fwd.hpp" #include "caf/fwd.hpp"
#include "caf/uri.hpp" #include "caf/meta/load_callback.hpp"
#include "caf/ref_counted.hpp" #include "caf/ref_counted.hpp"
#include "caf/string_view.hpp" #include "caf/string_view.hpp"
#include "caf/uri.hpp"
namespace caf { namespace caf {
namespace detail { namespace detail {
...@@ -63,6 +65,12 @@ public: ...@@ -63,6 +65,12 @@ public:
/// The fragment component. /// The fragment component.
std::string fragment; std::string fragment;
// -- properties -------------------------------------------------------------
bool valid() const noexcept {
return !scheme.empty() && (!authority.empty() || !path.empty());
}
// -- modifiers -------------------------------------------------------------- // -- modifiers --------------------------------------------------------------
/// Assembles the human-readable string representation for this URI. /// Assembles the human-readable string representation for this URI.
...@@ -84,5 +92,20 @@ private: ...@@ -84,5 +92,20 @@ private:
mutable std::atomic<size_t> rc_; mutable std::atomic<size_t> rc_;
}; };
// -- related free functions -------------------------------------------------
/// @relates uri_impl
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, uri_impl& x) {
auto load = [&]() -> error {
x.str.clear();
if (x.valid())
x.assemble_str();
return none;
};
return f(x.scheme, x.authority, x.path, x.query, x.fragment,
meta::load_callback(load));
}
} // namespace detail } // namespace detail
} // namespace caf } // namespace caf
...@@ -111,12 +111,23 @@ public: ...@@ -111,12 +111,23 @@ public:
int compare(string_view x) const noexcept; int compare(string_view x) const noexcept;
// -- friend functions -------------------------------------------------------
friend error inspect(caf::serializer& dst, uri& x);
friend error inspect(caf::deserializer& src, uri& x);
private: private:
impl_ptr impl_; impl_ptr impl_;
}; };
// -- related free functions --------------------------------------------------- // -- related free functions ---------------------------------------------------
template <class Inspector>
typename Inspector::result_type inspect(Inspector& f, uri::authority_type& x) {
return f(x.userinfo, x.host, x.port);
}
/// @relates uri /// @relates uri
std::string to_string(const uri& x); std::string to_string(const uri& x);
......
...@@ -18,10 +18,12 @@ ...@@ -18,10 +18,12 @@
#include "caf/uri.hpp" #include "caf/uri.hpp"
#include "caf/deserializer.hpp"
#include "caf/detail/parser/read_uri.hpp" #include "caf/detail/parser/read_uri.hpp"
#include "caf/detail/uri_impl.hpp" #include "caf/detail/uri_impl.hpp"
#include "caf/error.hpp" #include "caf/error.hpp"
#include "caf/make_counted.hpp" #include "caf/make_counted.hpp"
#include "caf/serializer.hpp"
#include "caf/uri_builder.hpp" #include "caf/uri_builder.hpp"
namespace caf { namespace caf {
...@@ -72,6 +74,20 @@ int uri::compare(string_view x) const noexcept { ...@@ -72,6 +74,20 @@ int uri::compare(string_view x) const noexcept {
return string_view{str()}.compare(x); return string_view{str()}.compare(x);
} }
// -- friend functions ---------------------------------------------------------
error inspect(caf::serializer& dst, uri& x) {
return inspect(dst, const_cast<detail::uri_impl&>(*x.impl_));
}
error inspect(caf::deserializer& src, uri& x) {
auto impl = make_counted<detail::uri_impl>();
auto err = inspect(src, *impl);
if (err == none)
x = uri{std::move(impl)};
return err;
}
// -- related free functions --------------------------------------------------- // -- related free functions ---------------------------------------------------
std::string to_string(const uri& x) { std::string to_string(const uri& x) {
......
...@@ -114,12 +114,41 @@ struct uri_str_builder { ...@@ -114,12 +114,41 @@ struct uri_str_builder {
}; };
struct fixture { struct fixture {
uri_builder http; // -- member types -----------------------------------------------------------
uri_str_builder http_str;
using buffer = std::vector<char>;
// -- constructors, destructors, and assignment operators --------------------
fixture() { fixture() {
http.scheme("http"); http.scheme("http");
} }
// -- member variables -------------------------------------------------------
uri_builder http;
uri_str_builder http_str;
// -- utility functions ------------------------------------------------------
buffer serialize(uri x) {
buffer buf;
binary_serializer dst{nullptr, buf};
auto err = inspect(dst, x);
if (err)
CAF_FAIL("unable to serialize " << x << ": " << to_string(err));
return buf;
}
uri deserialize(buffer buf) {
uri result;
binary_deserializer src{nullptr, buf};
auto err = inspect(src, result);
if (err)
CAF_FAIL("unable to deserialize from buffer: " << to_string(err));
return result;
}
}; };
struct me_t {} me; struct me_t {} me;
...@@ -202,6 +231,9 @@ CAF_TEST(constructing) { ...@@ -202,6 +231,9 @@ CAF_TEST(constructing) {
CAF_CHECK_EQUAL(*(http << components), *(http_str << components)) CAF_CHECK_EQUAL(*(http << components), *(http_str << components))
CAF_TEST(builder construction) { CAF_TEST(builder construction) {
auto minimal = *(http << file);
CAF_CHECK_EQUAL(minimal.empty(), false);
CAF_CHECK_EQUAL(minimal, "http:file");
// all combinations of components // all combinations of components
BUILD(file); BUILD(file);
BUILD(file << kvp); BUILD(file << kvp);
...@@ -327,6 +359,8 @@ CAF_TEST(from string) { ...@@ -327,6 +359,8 @@ CAF_TEST(from string) {
ROUNDTRIP("hi%20there://it%27s@me%21/file%201#%5B42%5D"); ROUNDTRIP("hi%20there://it%27s@me%21/file%201#%5B42%5D");
} }
#undef ROUNDTRIP
CAF_TEST(empty components) { CAF_TEST(empty components) {
CAF_CHECK_EQUAL("foo:/"_u, "foo:/"); CAF_CHECK_EQUAL("foo:/"_u, "foo:/");
CAF_CHECK_EQUAL("foo:/#"_u, "foo:/"); CAF_CHECK_EQUAL("foo:/#"_u, "foo:/");
...@@ -346,4 +380,84 @@ CAF_TEST(invalid uris) { ...@@ -346,4 +380,84 @@ CAF_TEST(invalid uris) {
CAF_CHECK("http://foo:66000"_i); CAF_CHECK("http://foo:66000"_i);
} }
#define SERIALIZATION_ROUNDTRIP(str) \
CAF_CHECK_EQUAL(deserialize(serialize(str##_u)), str)
CAF_TEST(serialization) {
// all combinations of components
SERIALIZATION_ROUNDTRIP("http:file");
SERIALIZATION_ROUNDTRIP("http:file?a=1&b=2");
SERIALIZATION_ROUNDTRIP("http:file#42");
SERIALIZATION_ROUNDTRIP("http:file?a=1&b=2#42");
SERIALIZATION_ROUNDTRIP("http://node");
SERIALIZATION_ROUNDTRIP("http://node?a=1&b=2");
SERIALIZATION_ROUNDTRIP("http://node#42");
SERIALIZATION_ROUNDTRIP("http://node?a=1&b=2#42");
SERIALIZATION_ROUNDTRIP("http://node:80");
SERIALIZATION_ROUNDTRIP("http://node:80?a=1&b=2");
SERIALIZATION_ROUNDTRIP("http://node:80#42");
SERIALIZATION_ROUNDTRIP("http://node:80?a=1&b=2#42");
SERIALIZATION_ROUNDTRIP("http://me@node");
SERIALIZATION_ROUNDTRIP("http://me@node?a=1&b=2");
SERIALIZATION_ROUNDTRIP("http://me@node#42");
SERIALIZATION_ROUNDTRIP("http://me@node?a=1&b=2#42");
SERIALIZATION_ROUNDTRIP("http://me@node:80");
SERIALIZATION_ROUNDTRIP("http://me@node:80?a=1&b=2");
SERIALIZATION_ROUNDTRIP("http://me@node:80#42");
SERIALIZATION_ROUNDTRIP("http://me@node:80?a=1&b=2#42");
SERIALIZATION_ROUNDTRIP("http://node/file");
SERIALIZATION_ROUNDTRIP("http://node/file?a=1&b=2");
SERIALIZATION_ROUNDTRIP("http://node/file#42");
SERIALIZATION_ROUNDTRIP("http://node/file?a=1&b=2#42");
SERIALIZATION_ROUNDTRIP("http://node:80/file");
SERIALIZATION_ROUNDTRIP("http://node:80/file?a=1&b=2");
SERIALIZATION_ROUNDTRIP("http://node:80/file#42");
SERIALIZATION_ROUNDTRIP("http://node:80/file?a=1&b=2#42");
SERIALIZATION_ROUNDTRIP("http://me@node/file");
SERIALIZATION_ROUNDTRIP("http://me@node/file?a=1&b=2");
SERIALIZATION_ROUNDTRIP("http://me@node/file#42");
SERIALIZATION_ROUNDTRIP("http://me@node/file?a=1&b=2#42");
SERIALIZATION_ROUNDTRIP("http://me@node:80/file");
SERIALIZATION_ROUNDTRIP("http://me@node:80/file?a=1&b=2");
SERIALIZATION_ROUNDTRIP("http://me@node:80/file#42");
SERIALIZATION_ROUNDTRIP("http://me@node:80/file?a=1&b=2#42");
// all combinations of with IPv6 host
SERIALIZATION_ROUNDTRIP("http://[::1]");
SERIALIZATION_ROUNDTRIP("http://[::1]?a=1&b=2");
SERIALIZATION_ROUNDTRIP("http://[::1]#42");
SERIALIZATION_ROUNDTRIP("http://[::1]?a=1&b=2#42");
SERIALIZATION_ROUNDTRIP("http://[::1]:80");
SERIALIZATION_ROUNDTRIP("http://[::1]:80?a=1&b=2");
SERIALIZATION_ROUNDTRIP("http://[::1]:80#42");
SERIALIZATION_ROUNDTRIP("http://[::1]:80?a=1&b=2#42");
SERIALIZATION_ROUNDTRIP("http://me@[::1]");
SERIALIZATION_ROUNDTRIP("http://me@[::1]?a=1&b=2");
SERIALIZATION_ROUNDTRIP("http://me@[::1]#42");
SERIALIZATION_ROUNDTRIP("http://me@[::1]?a=1&b=2#42");
SERIALIZATION_ROUNDTRIP("http://me@[::1]:80");
SERIALIZATION_ROUNDTRIP("http://me@[::1]:80?a=1&b=2");
SERIALIZATION_ROUNDTRIP("http://me@[::1]:80#42");
SERIALIZATION_ROUNDTRIP("http://me@[::1]:80?a=1&b=2#42");
SERIALIZATION_ROUNDTRIP("http://[::1]/file");
SERIALIZATION_ROUNDTRIP("http://[::1]/file?a=1&b=2");
SERIALIZATION_ROUNDTRIP("http://[::1]/file#42");
SERIALIZATION_ROUNDTRIP("http://[::1]/file?a=1&b=2#42");
SERIALIZATION_ROUNDTRIP("http://[::1]:80/file");
SERIALIZATION_ROUNDTRIP("http://[::1]:80/file?a=1&b=2");
SERIALIZATION_ROUNDTRIP("http://[::1]:80/file#42");
SERIALIZATION_ROUNDTRIP("http://[::1]:80/file?a=1&b=2#42");
SERIALIZATION_ROUNDTRIP("http://me@[::1]/file");
SERIALIZATION_ROUNDTRIP("http://me@[::1]/file?a=1&b=2");
SERIALIZATION_ROUNDTRIP("http://me@[::1]/file#42");
SERIALIZATION_ROUNDTRIP("http://me@[::1]/file?a=1&b=2#42");
SERIALIZATION_ROUNDTRIP("http://me@[::1]:80/file");
SERIALIZATION_ROUNDTRIP("http://me@[::1]:80/file?a=1&b=2");
SERIALIZATION_ROUNDTRIP("http://me@[::1]:80/file#42");
SERIALIZATION_ROUNDTRIP("http://me@[::1]:80/file?a=1&b=2#42");
// percent encoding
SERIALIZATION_ROUNDTRIP("hi%20there://it%27s@me%21/file%201#%5B42%5D");
}
#undef SERIALIZATION_ROUNDTRIP
CAF_TEST_FIXTURE_SCOPE_END() CAF_TEST_FIXTURE_SCOPE_END()
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