Commit ed6cc808 authored by Dominik Charousset's avatar Dominik Charousset

Add HTTP module test and fix SSL setup

parent 1f04207b
......@@ -26,6 +26,7 @@ option(CAF_ENABLE_CPACK "Enable packaging via CPack" OFF)
option(CAF_ENABLE_CURL_EXAMPLES "Build examples with libcurl" OFF)
option(CAF_ENABLE_PROTOBUF_EXAMPLES "Build examples with Google Protobuf" OFF)
option(CAF_ENABLE_QT6_EXAMPLES "Build examples with the Qt6 framework" OFF)
option(CAF_ENABLE_ROBOT_TESTS "Add the Robot tests to CTest " OFF)
option(CAF_ENABLE_RUNTIME_CHECKS "Build CAF with extra runtime assertions" OFF)
# -- CAF options that are on by default ----------------------------------------
......@@ -401,6 +402,12 @@ if(CAF_ENABLE_TOOLS)
add_subdirectory(tools)
endif()
# -- optionally add the Robot tests to CTest -----------------------------------
if(CAF_ENABLE_TESTING AND CAF_ENABLE_ROBOT_TESTS)
add_subdirectory(robot)
endif()
# -- add top-level compiler and linker flags that propagate to clients ---------
# Disable warnings regarding C++ classes at ABI boundaries on MSVC.
......
......@@ -48,11 +48,11 @@ struct kvs_actor_state {
caf::behavior make_behavior() {
return {
[this](caf::get_atom, const std::string& key) -> std::string {
[this](caf::get_atom, const std::string& key) -> caf::result<std::string> {
if (auto i = data.find(key); i != data.end())
return i->second;
else
return {};
return make_error(caf::sec::no_such_key, key + " not found");
},
[this](caf::put_atom, const std::string& key, std::string& value) {
data.insert_or_assign(key, std::move(value));
......@@ -122,7 +122,12 @@ int caf_main(caf::actor_system& sys, const config& cfg) {
prom.respond(http::status::ok, "text/plain", value);
},
[prom](const caf::error& what) mutable {
prom.respond(http::status::internal_server_error, what);
if (what == caf::sec::no_such_key)
prom.respond(http::status::not_found, "text/plain",
"Key not found.");
else
prom.respond(http::status::internal_server_error,
what);
});
})
.route("/api/<arg>", http::method::post,
......@@ -159,6 +164,10 @@ int caf_main(caf::actor_system& sys, const config& cfg) {
prom.respond(http::status::internal_server_error, what);
});
})
.route("/status", http::method::get,
[kvs](http::responder& res) {
res.respond(http::status::no_content);
})
// Launch the server.
.start();
// Report any error to the user.
......
......@@ -37,6 +37,7 @@ caf_add_component(
src/net/dsl/config_base.cpp
src/net/generic_lower_layer.cpp
src/net/generic_upper_layer.cpp
src/net/http/config.cpp
src/net/http/lower_layer.cpp
src/net/http/method.cpp
src/net/http/request.cpp
......
......@@ -47,11 +47,12 @@ public:
static constexpr std::string_view name = "lazy";
lazy(std::string host, uint16_t port)
: server(server_address{std::move(host), port}) {
lazy(std::shared_ptr<ssl::context> ctx, std::string host, uint16_t port)
: has_ctx(std::move(ctx)), server(server_address{std::move(host), port}) {
}
explicit lazy(const uri& addr) : server(addr) {
lazy(std::shared_ptr<ssl::context> ctx, const uri& addr)
: has_ctx(std::move(ctx)), server(addr) {
// nop
}
......@@ -68,14 +69,17 @@ public:
size_t max_retry_count = 0;
};
static constexpr auto lazy_v = client_config_tag<lazy>{};
using lazy_t = client_config_tag<lazy>;
static constexpr auto lazy_v = lazy_t{};
/// Configuration for a client that uses a user-provided socket.
class CAF_NET_EXPORT socket : public has_ctx {
public:
static constexpr std::string_view name = "socket";
explicit socket(stream_socket fd) : fd(fd) {
socket(std::shared_ptr<ssl::context> ctx, stream_socket fd)
: has_ctx(std::move(ctx)), fd(fd) {
// nop
}
......@@ -112,7 +116,9 @@ public:
}
};
static constexpr auto socket_v = client_config_tag<socket>{};
using socket_t = client_config_tag<socket>;
static constexpr auto socket_v = socket_t{};
/// Configuration for a client that uses an already established SSL
/// connection.
......@@ -145,31 +151,17 @@ public:
ssl::connection state;
};
static constexpr auto conn_v = client_config_tag<conn>{};
using conn_t = client_config_tag<conn>;
static constexpr auto fail_v = client_config_tag<error>{};
static constexpr auto conn_v = conn_t{};
template <class Base>
class value : public config_impl<Base, lazy, socket, conn> {
public:
using super = config_impl<Base, lazy, socket, conn>;
using fail_t = client_config_tag<error>;
using super::super;
static constexpr auto fail_v = fail_t{};
template <class T, class From, class... Args>
static auto make(client_config_tag<T>, From&& from, Args&&... args) {
static_assert(std::is_constructible_v<T, Args...>);
return make_counted<value>(std::forward<From>(from),
std::in_place_type<T>,
std::forward<Args>(args)...);
}
};
using value = config_impl<lazy, socket, conn>;
};
template <class Base>
using client_config_value = client_config::value<Base>;
template <class Base>
using client_config_ptr = intrusive_ptr<client_config_value<Base>>;
using client_config_value = client_config::value;
} // namespace caf::net::dsl
......@@ -17,10 +17,10 @@
namespace caf::net::dsl {
/// Base type for client factories for use with `can_connect`.
template <class ConfigBase, class Derived>
template <class Config, class Derived>
class client_factory_base {
public:
using config_type = client_config_value<ConfigBase>;
using config_type = Config;
using trait_type = typename config_type::trait_type;
......
......@@ -54,6 +54,8 @@ public:
+ std::string{name()});
}
/// Inspects the data of this configuration and returns a pointer to it as
/// `has_ctx` instance if possible, `nullptr` otherwise.
virtual has_ctx* as_has_ctx() noexcept = 0;
bool failed() const noexcept {
......@@ -81,31 +83,10 @@ public:
}
};
/// Simple base class for a configuration with a trait member.
template <class Trait>
class config_with_trait : public config_base {
template <class... Data>
class config_impl : public config_base {
public:
using trait_type = Trait;
explicit config_with_trait(multiplexer* mpx) : config_base(mpx) {
// nop
}
config_with_trait(const config_with_trait&) = default;
config_with_trait& operator=(const config_with_trait&) = default;
/// Configures various aspects of the protocol stack such as in- and output
/// types.
Trait trait;
};
template <class Base, class... Data>
class config_impl : public Base {
public:
using super = Base;
static_assert(std::is_base_of_v<config_base, super>);
using super = config_base;
template <class From, class... Args>
explicit config_impl(From&& from, Args&&... args)
......
......@@ -35,23 +35,16 @@ public:
static constexpr auto fail_v = generic_config_tag<error>{};
template <class Base>
class value : public config_impl<Base, lazy> {
class value : public config_impl<lazy> {
public:
using super = config_impl<Base, lazy>;
using super = config_impl<lazy>;
using super::super;
static auto make(multiplexer* mpx) {
return make_counted<value>(mpx, std::in_place_type<lazy>);
explicit value(multiplexer* mpx) : super(mpx, std::in_place_type<lazy>) {
// nop
}
};
};
template <class Base>
using generic_config_value = typename generic_config::value<Base>;
template <class Base>
using generic_config_ptr = intrusive_ptr<generic_config_value<Base>>;
using generic_config_value = typename generic_config::value;
} // namespace caf::net::dsl
......@@ -18,6 +18,22 @@ namespace caf::net::dsl {
/// Configuration for a client that uses a user-provided socket.
class has_ctx {
public:
using ctx_ptr = std::shared_ptr<ssl::context>;
has_ctx() = default;
has_ctx(ctx_ptr ptr) : ctx(std::move(ptr)) {
// nop
}
has_ctx(has_ctx&&) = default;
has_ctx(const has_ctx&) = default;
has_ctx& operator=(has_ctx&&) = default;
has_ctx& operator=(const has_ctx&) = default;
/// SSL context for secure servers.
std::shared_ptr<ssl::context> ctx;
......
......@@ -33,9 +33,11 @@ public:
public:
static constexpr std::string_view name = "lazy";
lazy(uint16_t port, std::string bind_address)
: port(port), bind_address(std::move(bind_address)) {
// nop
lazy(std::shared_ptr<ssl::context> ctx, uint16_t port,
std::string bind_address)
: has_ctx(std::move(ctx)),
port(port),
bind_address(std::move(bind_address)) {
}
/// The port number to bind to.
......@@ -48,14 +50,17 @@ public:
bool reuse_addr = true;
};
static constexpr auto lazy_v = server_config_tag<lazy>{};
using lazy_t = server_config_tag<lazy>;
static constexpr auto lazy_v = lazy_t{};
/// Configuration for a server that uses a user-provided socket.
class socket : public has_ctx {
public:
static constexpr std::string_view name = "socket";
explicit socket(tcp_accept_socket fd) : fd(fd) {
socket(std::shared_ptr<ssl::context> ctx, tcp_accept_socket fd)
: has_ctx(std::move(ctx)), fd(fd) {
// nop
}
......@@ -76,24 +81,20 @@ public:
}
};
static constexpr auto socket_v = server_config_tag<error>{};
using socket_t = server_config_tag<error>;
static constexpr auto socket_v = socket_t{};
using fail_t = server_config_tag<error>;
static constexpr auto fail_v = server_config_tag<error>{};
static constexpr auto fail_v = fail_t{};
template <class Base>
class value : public config_impl<Base, lazy, socket> {
class value : public config_impl<lazy, socket> {
public:
using super = config_impl<Base, lazy, socket>;
using super = config_impl<lazy, socket>;
using super::super;
template <class T, class From, class... Args>
static auto make(server_config_tag<T>, const From& from, Args&&... args) {
static_assert(std::is_constructible_v<T, Args...>);
return make_counted<value>(from, std::in_place_type<T>,
std::forward<Args>(args)...);
}
/// Configures how many reads we allow on a socket before returning to the
/// event loop.
size_t max_consecutive_reads
......@@ -104,10 +105,6 @@ public:
};
};
template <class Base>
using server_config_value = server_config::value<Base>;
template <class Base>
using server_config_ptr = intrusive_ptr<server_config_value<Base>>;
using server_config_value = server_config::value;
} // namespace caf::net::dsl
......@@ -16,10 +16,10 @@
namespace caf::net::dsl {
/// Base type for server factories for use with `can_accept`.
template <class ConfigBase, class Derived>
template <class Config, class Derived>
class server_factory_base {
public:
using config_type = server_config_value<ConfigBase>;
using config_type = Config;
using config_pointer = intrusive_ptr<config_type>;
......
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include "caf/actor_control_block.hpp"
#include "caf/detail/net_export.hpp"
#include "caf/net/dsl/generic_config.hpp"
#include "caf/net/dsl/server_config.hpp"
#include "caf/net/http/route.hpp"
#include "caf/net/tcp_accept_socket.hpp"
#include <string>
#include <vector>
namespace caf::net::http {
/// Configuration for the `with_t` DSL entry point. Refined into a server or
/// client configuration later on.
using base_config = dsl::generic_config_value;
/// Configuration for the server factory.
class CAF_NET_EXPORT server_config : public dsl::server_config_value {
public:
using super = dsl::server_config_value;
using super::super;
static intrusive_ptr<server_config>
make(dsl::server_config::lazy_t, const base_config& from, uint16_t port,
std::string bind_address);
static intrusive_ptr<server_config> make(dsl::server_config::socket_t,
const base_config& from,
tcp_accept_socket fd);
/// Stores the available routes on the HTTP server.
std::vector<route_ptr> routes;
/// Store actors that the server should monitor.
std::vector<strong_actor_ptr> monitored_actors;
};
} // namespace caf::net::http
......@@ -12,7 +12,9 @@
#include "caf/detail/net_export.hpp"
#include "caf/fwd.hpp"
#include "caf/net/checked_socket.hpp"
#include "caf/net/dsl/generic_config.hpp"
#include "caf/net/dsl/server_factory_base.hpp"
#include "caf/net/http/config.hpp"
#include "caf/net/http/request.hpp"
#include "caf/net/http/router.hpp"
#include "caf/net/http/server.hpp"
......@@ -99,31 +101,11 @@ private:
namespace caf::net::http {
/// Configuration type for WebSocket clients with a handshake object. The
/// handshake object sets the default endpoint to '/' for convenience.
class server_factory_config : public dsl::config_base {
public:
using super = dsl::config_base;
explicit server_factory_config(multiplexer* mpx) : super(mpx) {
// nop
}
explicit server_factory_config(const super& other) : super(other) {
// nop
}
server_factory_config(const server_factory_config&) = default;
std::vector<route_ptr> routes;
std::vector<strong_actor_ptr> monitored_actors;
};
/// Factory type for the `with(...).accept(...).start(...)` DSL.
class server_factory
: public dsl::server_factory_base<server_factory_config, server_factory> {
: public dsl::server_factory_base<server_config, server_factory> {
public:
using super = dsl::server_factory_base<server_factory_config, server_factory>;
using super = dsl::server_factory_base<server_config, server_factory>;
using config_type = typename super::config_type;
......
......@@ -10,6 +10,7 @@
#include "caf/net/dsl/has_accept.hpp"
#include "caf/net/dsl/has_connect.hpp"
#include "caf/net/dsl/has_context.hpp"
#include "caf/net/http/config.hpp"
#include "caf/net/http/request.hpp"
#include "caf/net/http/router.hpp"
#include "caf/net/http/server_factory.hpp"
......@@ -25,10 +26,8 @@ namespace caf::net::http {
class with_t : public extend<dsl::base, with_t>:: //
with<dsl::has_accept, dsl::has_context> {
public:
using config_type = dsl::generic_config_value<dsl::config_base>;
template <class... Ts>
explicit with_t(multiplexer* mpx) : config_(config_type::make(mpx)) {
explicit with_t(multiplexer* mpx) : config_(make_counted<base_config>(mpx)) {
// nop
}
......@@ -41,7 +40,7 @@ public:
with_t& operator=(const with_t&) noexcept = default;
/// @private
config_type& config() {
base_config& config() {
return *config_;
}
......@@ -52,7 +51,7 @@ public:
}
private:
intrusive_ptr<config_type> config_;
intrusive_ptr<base_config> config_;
};
inline with_t with(actor_system& sys) {
......
......@@ -9,6 +9,7 @@
#include "caf/disposable.hpp"
#include "caf/net/checked_socket.hpp"
#include "caf/net/dsl/client_factory_base.hpp"
#include "caf/net/lp/config.hpp"
#include "caf/net/lp/framing.hpp"
#include "caf/net/ssl/connection.hpp"
#include "caf/net/tcp_stream_socket.hpp"
......@@ -66,12 +67,11 @@ namespace caf::net::lp {
/// Factory for the `with(...).connect(...).start(...)` DSL.
template <class Trait>
class client_factory
: public dsl::client_factory_base<dsl::config_with_trait<Trait>,
client_factory<Trait>> {
class client_factory : public dsl::client_factory_base<client_config<Trait>,
client_factory<Trait>> {
public:
using super = dsl::client_factory_base<dsl::config_with_trait<Trait>,
client_factory<Trait>>;
using super
= dsl::client_factory_base<client_config<Trait>, client_factory<Trait>>;
using config_type = typename super::config_type;
......
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include "caf/actor_control_block.hpp"
#include "caf/detail/net_export.hpp"
#include "caf/net/dsl/generic_config.hpp"
#include "caf/net/dsl/server_config.hpp"
#include "caf/net/stream_socket.hpp"
#include <string>
#include <vector>
namespace caf::net::lp {
/// Configuration for the `with_t` DSL entry point. Refined into a server or
/// client configuration later on.
template <class Trait>
class base_config : public dsl::generic_config_value {
public:
using trait_type = Trait;
using super = dsl::generic_config_value;
using super::super;
/// Configures the protocol layer.
Trait trait;
};
/// The configuration for a length-prefix framing server.
template <class Trait>
class server_config : public dsl::server_config_value {
public:
using trait_type = Trait;
using super = dsl::server_config_value;
using super::super;
static auto make(dsl::server_config::lazy_t, const base_config<Trait>& from,
uint16_t port, std::string bind_address) {
auto res = make_counted<server_config>(from.mpx);
if (auto* err = std::get_if<error>(&from.data)) {
res->data = *err;
} else {
auto& src_data = std::get<dsl::generic_config::lazy>(from.data);
res->data = dsl::server_config::lazy{src_data.ctx, port,
std::move(bind_address)};
res->trait = from.trait;
}
return res;
}
static auto make(dsl::server_config::socket_t, const base_config<Trait>& from,
tcp_accept_socket fd) {
auto res = make_counted<server_config>(from.mpx);
if (auto* err = std::get_if<error>(&from.data)) {
res->data = *err;
close(fd);
} else {
auto& src_data = std::get<dsl::generic_config::lazy>(from.data);
res->data = dsl::server_config::socket{src_data.ctx, fd};
res->trait = from.trait;
}
return res;
}
Trait trait;
};
/// The configuration for a length-prefix framing client.
template <class Trait>
class client_config : public dsl::client_config_value {
public:
using trait_type = Trait;
using super = dsl::client_config_value;
using super::super;
template <class... Ts>
static auto
make(dsl::client_config::lazy_t, const base_config<Trait>& from, Ts&&... args) {
auto res = make_counted<client_config>(from.mpx);
if (auto* err = std::get_if<error>(&from.data)) {
res->data = *err;
} else {
auto& src_data = std::get<dsl::generic_config::lazy>(from.data);
res->data = dsl::client_config::lazy{src_data.ctx,
std::forward<Ts>(args)...};
res->trait = from.trait;
}
return res;
}
static auto make(dsl::client_config::socket_t, const base_config<Trait>& from,
stream_socket fd) {
auto res = make_counted<client_config>(from.mpx);
if (auto* err = std::get_if<error>(&from.data)) {
res->data = *err;
close(fd);
} else {
auto& src_data = std::get<dsl::generic_config::lazy>(from.data);
res->data = dsl::client_config::socket{src_data.ctx, fd};
res->trait = from.trait;
}
return res;
}
static auto make(dsl::client_config::socket_t, const base_config<Trait>& from,
ssl::connection conn) {
auto res = make_counted<client_config>(from.mpx);
if (auto* err = std::get_if<error>(&from.data)) {
res->data = *err;
} else {
auto& src_data = std::get<dsl::generic_config::lazy>(from.data);
res->data = dsl::client_config::socket{src_data.ctx, std::move(conn)};
res->trait = from.trait;
}
return res;
}
static auto make(dsl::client_config::fail_t, const base_config<Trait>& from,
error err) {
auto res = make_counted<client_config>(from.mpx);
res->data = std::move(err);
return res;
}
Trait trait;
};
} // namespace caf::net::lp
......@@ -13,6 +13,7 @@
#include "caf/net/checked_socket.hpp"
#include "caf/net/dsl/server_factory_base.hpp"
#include "caf/net/http/server.hpp"
#include "caf/net/lp/config.hpp"
#include "caf/net/lp/framing.hpp"
#include "caf/net/multiplexer.hpp"
#include "caf/net/octet_stream/transport.hpp"
......@@ -118,12 +119,11 @@ namespace caf::net::lp {
/// Factory type for the `with(...).accept(...).start(...)` DSL.
template <class Trait>
class server_factory
: public dsl::server_factory_base<dsl::config_with_trait<Trait>,
server_factory<Trait>> {
class server_factory : public dsl::server_factory_base<server_config<Trait>,
server_factory<Trait>> {
public:
using super = dsl::server_factory_base<dsl::config_with_trait<Trait>,
server_factory<Trait>>;
using super
= dsl::server_factory_base<server_config<Trait>, server_factory<Trait>>;
using config_type = typename super::config_type;
......
......@@ -11,6 +11,7 @@
#include "caf/net/dsl/has_connect.hpp"
#include "caf/net/dsl/has_context.hpp"
#include "caf/net/lp/client_factory.hpp"
#include "caf/net/lp/config.hpp"
#include "caf/net/lp/server_factory.hpp"
#include "caf/net/multiplexer.hpp"
#include "caf/net/ssl/context.hpp"
......@@ -25,10 +26,10 @@ template <class Trait>
class with_t : public extend<dsl::base, with_t<Trait>>::template //
with<dsl::has_accept, dsl::has_connect, dsl::has_context> {
public:
using config_type = dsl::generic_config_value<dsl::config_with_trait<Trait>>;
using config_type = base_config<Trait>;
template <class... Ts>
explicit with_t(multiplexer* mpx) : config_(config_type::make(mpx)) {
explicit with_t(multiplexer* mpx) : config_(make_counted<config_type>(mpx)) {
// nop
}
......
......@@ -12,6 +12,7 @@
#include "caf/net/ssl/connection.hpp"
#include "caf/net/tcp_stream_socket.hpp"
#include "caf/net/web_socket/client.hpp"
#include "caf/net/web_socket/config.hpp"
#include "caf/net/web_socket/framing.hpp"
#include "caf/timespan.hpp"
......@@ -60,34 +61,13 @@ private:
namespace caf::net::web_socket {
/// Configuration type for WebSocket clients with a handshake object. The
/// handshake object sets the default endpoint to '/' for convenience.
template <class Trait>
class client_factory_config : public dsl::config_with_trait<Trait> {
public:
using super = dsl::config_with_trait<Trait>;
explicit client_factory_config(multiplexer* mpx) : super(mpx) {
hs.endpoint("/");
}
explicit client_factory_config(const super& other) : super(other) {
hs.endpoint("/");
}
client_factory_config(const client_factory_config&) = default;
handshake hs;
};
/// Factory for the `with(...).connect(...).start(...)` DSL.
template <class Trait>
class client_factory
: public dsl::client_factory_base<client_factory_config<Trait>,
client_factory<Trait>> {
class client_factory : public dsl::client_factory_base<client_config<Trait>,
client_factory<Trait>> {
public:
using super = dsl::client_factory_base<client_factory_config<Trait>,
client_factory<Trait>>;
using super
= dsl::client_factory_base<client_config<Trait>, client_factory<Trait>>;
using super::super;
......
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#pragma once
#include "caf/actor_control_block.hpp"
#include "caf/detail/net_export.hpp"
#include "caf/net/dsl/generic_config.hpp"
#include "caf/net/dsl/server_config.hpp"
#include "caf/net/tcp_accept_socket.hpp"
#include "caf/net/web_socket/handshake.hpp"
#include <string>
#include <vector>
namespace caf::net::web_socket {
/// Configuration for the `with_t` DSL entry point. Refined into a server or
/// client configuration later on.
template <class Trait>
class base_config : public dsl::generic_config_value {
public:
using trait_type = Trait;
using super = dsl::generic_config_value;
using super::super;
/// Configures the protocol layer.
Trait trait;
};
/// The configuration for a length-prefix framing server.
template <class Trait>
class server_config : public dsl::server_config_value {
public:
using trait_type = Trait;
using super = dsl::server_config_value;
using super::super;
static auto make(dsl::server_config::lazy_t, const base_config<Trait>& from,
uint16_t port, std::string bind_address) {
auto res = make_counted<server_config>(from.mpx);
if (auto* err = std::get_if<error>(&from.data)) {
res->data = *err;
} else {
auto& src_data = std::get<dsl::generic_config::lazy>(from.data);
res->data = dsl::server_config::lazy{src_data.ctx, port,
std::move(bind_address)};
res->trait = from.trait;
}
return res;
}
static auto make(dsl::server_config::socket_t, const base_config<Trait>& from,
tcp_accept_socket fd) {
auto res = make_counted<server_config>(from.mpx);
if (auto* err = std::get_if<error>(&from.data)) {
res->data = *err;
close(fd);
} else {
auto& src_data = std::get<dsl::generic_config::lazy>(from.data);
res->data = dsl::server_config::socket{src_data.ctx, fd};
res->trait = from.trait;
}
return res;
}
Trait trait;
};
/// The configuration for a length-prefix framing client.
template <class Trait>
class client_config : public dsl::client_config_value {
public:
using trait_type = Trait;
using super = dsl::client_config_value;
explicit client_config(multiplexer* mpx) : super(mpx) {
hs.endpoint("/");
}
client_config(const client_config&) = default;
template <class... Ts>
static auto
make(dsl::client_config::lazy_t, const base_config<Trait>& from, Ts&&... args) {
auto res = make_counted<client_config>(from.mpx);
if (auto* err = std::get_if<error>(&from.data)) {
res->data = *err;
} else {
auto& src_data = std::get<dsl::generic_config::lazy>(from.data);
res->data = dsl::client_config::lazy{src_data.ctx,
std::forward<Ts>(args)...};
res->trait = from.trait;
}
return res;
}
static auto make(dsl::client_config::socket_t, const base_config<Trait>& from,
tcp_accept_socket fd) {
auto res = make_counted<client_config>(from.mpx);
if (auto* err = std::get_if<error>(&from.data)) {
res->data = *err;
close(fd);
} else {
auto& src_data = std::get<dsl::generic_config::lazy>(from.data);
res->data = dsl::client_config::socket{src_data.ctx, fd};
res->trait = from.trait;
}
return res;
}
static auto make(dsl::client_config::fail_t, const base_config<Trait>& from,
error err) {
auto res = make_counted<client_config>(from.mpx);
res->data = std::move(err);
return res;
}
Trait trait;
handshake hs;
};
} // namespace caf::net::web_socket
......@@ -17,12 +17,11 @@ namespace caf::net::web_socket {
/// DSL entry point for creating a server.
template <class Trait>
class has_on_request
: public dsl::server_factory_base<dsl::config_with_trait<Trait>,
has_on_request<Trait>> {
class has_on_request : public dsl::server_factory_base<server_config<Trait>,
has_on_request<Trait>> {
public:
using super = dsl::server_factory_base<dsl::config_with_trait<Trait>,
has_on_request<Trait>>;
using super
= dsl::server_factory_base<server_config<Trait>, has_on_request<Trait>>;
using super::super;
......
......@@ -17,6 +17,7 @@
#include "caf/net/octet_stream/transport.hpp"
#include "caf/net/ssl/transport.hpp"
#include "caf/net/tcp_accept_socket.hpp"
#include "caf/net/web_socket/config.hpp"
#include "caf/net/web_socket/server.hpp"
#include <cstdint>
......@@ -148,12 +149,11 @@ namespace caf::net::web_socket {
/// Factory type for the `with(...).accept(...).start(...)` DSL.
template <class Trait, class... Ts>
class server_factory
: public dsl::server_factory_base<dsl::config_with_trait<Trait>,
server_factory<Trait>> {
class server_factory : public dsl::server_factory_base<server_config<Trait>,
server_factory<Trait>> {
public:
using super = dsl::server_factory_base<dsl::config_with_trait<Trait>,
server_factory<Trait>>;
using super
= dsl::server_factory_base<server_config<Trait>, server_factory<Trait>>;
using config_type = typename super::config_type;
......
......@@ -13,6 +13,7 @@
#include "caf/net/ssl/context.hpp"
#include "caf/net/tcp_accept_socket.hpp"
#include "caf/net/web_socket/client_factory.hpp"
#include "caf/net/web_socket/config.hpp"
#include "caf/net/web_socket/default_trait.hpp"
#include "caf/net/web_socket/has_on_request.hpp"
......@@ -25,10 +26,10 @@ template <class Trait>
class with_t : public extend<dsl::base, with_t<Trait>>::template //
with<dsl::has_accept, dsl::has_uri_connect, dsl::has_context> {
public:
using config_type = dsl::generic_config_value<dsl::config_with_trait<Trait>>;
using config_type = base_config<Trait>;
template <class... Ts>
explicit with_t(multiplexer* mpx) : config_(config_type::make(mpx)) {
explicit with_t(multiplexer* mpx) : config_(make_counted<config_type>(mpx)) {
// nop
}
......
// This file is part of CAF, the C++ Actor Framework. See the file LICENSE in
// the main distribution directory for license terms and copyright or visit
// https://github.com/actor-framework/actor-framework/blob/master/LICENSE.
#include "caf/net/http/config.hpp"
namespace caf::net::http {
intrusive_ptr<server_config>
server_config::make(dsl::server_config::lazy_t, const base_config& from,
uint16_t port, std::string bind_address) {
auto res = make_counted<server_config>(from.mpx);
if (auto* err = std::get_if<error>(&from.data)) {
res->data = *err;
} else {
auto& src_data = std::get<dsl::generic_config::lazy>(from.data);
res->data = dsl::server_config::lazy{src_data.ctx, port,
std::move(bind_address)};
}
return res;
}
intrusive_ptr<server_config> server_config::make(dsl::server_config::socket_t,
const base_config& from,
tcp_accept_socket fd) {
auto res = make_counted<server_config>(from.mpx);
if (auto* err = std::get_if<error>(&from.data)) {
res->data = *err;
close(fd);
} else {
auto& src_data = std::get<dsl::generic_config::lazy>(from.data);
res->data = dsl::server_config::socket{src_data.ctx, fd};
}
return res;
}
} // namespace caf::net::http
......@@ -19,6 +19,7 @@ lower_layer::~lower_layer() {
bool lower_layer::send_response(status code) {
begin_header(code);
add_header_field("Content-Length"sv, "0"sv);
return end_header() && send_payload(const_byte_span{});
}
......
find_package(Python COMPONENTS Interpreter)
add_test(
NAME "robot-http-rest"
COMMAND
${Python_EXECUTABLE}
-m robot
--variable BINARY_PATH:$<TARGET_FILE:rest>
--variable SSL_PATH:${CMAKE_CURRENT_SOURCE_DIR}
"${CMAKE_CURRENT_SOURCE_DIR}/http/rest.robot")
This directory contains module and system tests that complement the C++ unit
tests.
-----BEGIN CERTIFICATE-----
MIIDmzCCAoOgAwIBAgIJAPLZ3e3WR0LLMA0GCSqGSIb3DQEBCwUAMGQxCzAJBgNV
BAYTAlVTMQswCQYDVQQIDAJDQTERMA8GA1UEBwwIQmVya2VsZXkxIzAhBgNVBAoM
GkFDTUUgU2lnbmluZyBBdXRob3JpdHkgSW5jMRAwDgYDVQQDDAdmb28uYmFyMB4X
DTE3MDQyMTIzMjM0OFoXDTQyMDQyMTIzMjM0OFowZDELMAkGA1UEBhMCVVMxCzAJ
BgNVBAgMAkNBMREwDwYDVQQHDAhCZXJrZWxleTEjMCEGA1UECgwaQUNNRSBTaWdu
aW5nIEF1dGhvcml0eSBJbmMxEDAOBgNVBAMMB2Zvby5iYXIwggEiMA0GCSqGSIb3
DQEBAQUAA4IBDwAwggEKAoIBAQC6ah79JvrN3LtcPzc9bX5THdzfidWncSmowotG
SZA3gcIhlsYD3P3RCaUR9g+f2Z/l0l7ciKgWetpNtN9hRBbg5/9tFzSpCb/Y0SSG
mwtHHovEqN2MWV+Od/MUcYSlL6MmPjSDc8Ls5NSniTr9OBE9J1jm72AsuzHasjPQ
D84TlWeTSs0HW3H5VxDb15xWYFnmgBo0JylDWj0+VWI+G41Xr7Ubu9699lWSFYF9
FCtdjzM5e1CGZOMvqUbUBus38BhUAdQ4fE7Dwnn8seKh+7HpJ70omIgqG87e4DBo
HbnMAkZaekk8+LBl0Hfu8c66Utw9mNoMIlFf/AMlJyLDIpNxAgMBAAGjUDBOMB0G
A1UdDgQWBBRc6Cbyshtny6jFWZtd/cEUUfMQ3DAfBgNVHSMEGDAWgBRc6Cbyshtn
y6jFWZtd/cEUUfMQ3DAMBgNVHRMEBTADAQH/MA0GCSqGSIb3DQEBCwUAA4IBAQCY
numHau9XYH5h4R2CoMdnKPMGk6V7UZZdbidLLcE4roQrYhnBdyhT69b/ySJK2Ee4
mt8T+E0wcg3k8Pr3aJEJA8eYYaJTqZvvv+TwuMBPjmE2rYSIpgMZv2tRD3XWMaQu
duLbwkclfejQHDD26xNXsxuU+WNB5kuvtNAg0oKFyFdNKElLQEcjyYzfxmCF4YX5
WmElijr1Tzuzd59rWPqC/tVIsh42vQ+P6g8Y1PDmo8eTUFveZ+wcr/eEPW6IOMrg
OW7tATcrgzNuXZ1umiuGgAPuIVqPfr9ssZHBqi9UOK9L/8MQrnOxecNUpPohcTFR
vq+Zqu15QV9T4BVWKHv0
-----END CERTIFICATE-----
-----BEGIN CERTIFICATE-----
MIIDOjCCAiICCQDz7oMOR7Wm7jANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQGEwJV
UzELMAkGA1UECAwCQ0ExETAPBgNVBAcMCEJlcmtlbGV5MSMwIQYDVQQKDBpBQ01F
IFNpZ25pbmcgQXV0aG9yaXR5IEluYzEQMA4GA1UEAwwHZm9vLmJhcjAgFw0xNzA0
MjEyMzI2MzhaGA80NzU1MDMxOTIzMjYzOFowWDELMAkGA1UEBhMCVVMxCzAJBgNV
BAgMAkNBMREwDwYDVQQHDAhCZXJrZWxleTEVMBMGA1UECgwMQUNNRSBTZXJ2aWNl
MRIwEAYDVQQDDAkxLmZvby5iYXIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
AoIBAQDHobccAQQqbZANdOdx852W/nUzGcwpurOi8zbh9yCxMwnFMogW9AsqKEnd
sypV6Ah/cIz45PAgCdEg+1pc2DG7+E0+QlV4ChNwCDuk+FSWB6pqMTCdZcLeIwlA
GPp6Ow9v40dW7IFpDetFKXEo6kqEzR5P58Q0a6KpCtpsSMqhk57Py83wB9gPA1vp
s77kN7D5CI3oay86TA5j5nfFMT1X/77Hs24csW6CLnW/OD4f1RK79UgPd/kpPKQ1
jNq+hsR7NZTcfrAF1hcfScxnKaznO7WopSt1k75NqLdnSN1GIci2GpiXYKtXZ9l5
TErv2Oucpw/u+a/wjKlXjrgLL9lfAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAKuW
yKA2uuiNc9MKU+yVbNaP8kPaMb/wMvVaFG8FFFpCTZ0MFMLsqRpeqtj7gMK/gaJC
CQm4EyadjzfWFYDLkHzm6b7gI8digvvhjr/C2RJ5Qxr2P0iFP1buGq0CqnF20XgQ
Q+ecS43CZ77CfKfS6ZLPmAZMAwgFLImVyo5mkaTECo3+9oCnjDYBapvXLJqCJRhk
NosoTmGCV0HecWN4l38ojnXd44aSktQIND9iCLus3S6++nFnX5DHGZiv6/SnSO/6
+Op7nV0A6zKVcMOYQ0SGZPD8UQs5wDJgrR9LY29Ox5QBwu/5NqyvNSrMQaTop5vb
wkMInaq5lLxEYQDSLBc=
-----END CERTIFICATE-----
robotframework
robotframework-requests
*** Settings ***
Documentation A test suite for examples/http/rest.hpp.
Library Process
Library RequestsLibrary
Suite Setup Start Server
Suite Teardown Stop Server
*** Variables ***
${HTTP_URL} http://localhost:55501
${HTTPS_URL} https://localhost:55502
${BINARY_PATH} /path/to/the/server
${SSL_PATH} /path/to/the/pem/files
*** Test Cases ***
HTTP Test Add Key Value Pair
[Tags] POST
Add Key Value Pair ${HTTP_URL} foo bar
Get Key Value Pair ${HTTP_URL} foo bar
HTTP Test Update Key Value Pair
[Tags] POST
Add Key Value Pair ${HTTP_URL} foo bar
Update Key Value Pair ${HTTP_URL} foo baz
Get Key Value Pair ${HTTP_URL} foo baz
HTTP Test Delete Key Value Pair
[Tags] DELETE
Add Key Value Pair ${HTTP_URL} foo bar
Delete Key Value Pair ${HTTP_URL} foo
Key Should Not Exist ${HTTP_URL} foo
HTTPS Test Add Key Value Pair
[Tags] POST
Add Key Value Pair ${HTTPS_URL} foo bar
Get Key Value Pair ${HTTPS_URL} foo bar
HTTPS Test Update Key Value Pair
[Tags] POST
Add Key Value Pair ${HTTPS_URL} foo bar
Update Key Value Pair ${HTTPS_URL} foo baz
Get Key Value Pair ${HTTPS_URL} foo baz
HTTPS Test Delete Key Value Pair
[Tags] DELETE
Add Key Value Pair ${HTTPS_URL} foo bar
Delete Key Value Pair ${HTTPS_URL} foo
Key Should Not Exist ${HTTPS_URL} foo
*** Keywords ***
Start Server
${res1}= Start Process ${BINARY_PATH} -p 55501
Set Suite Variable ${http_server_process} ${res1}
${res2}= Start Process ${BINARY_PATH} -p 55502 -k ${SSL_PATH}/key.pem -c ${SSL_PATH}/cert.pem
Set Suite Variable ${https_server_process} ${res2}
Wait Until Keyword Succeeds 5s 125ms Check If HTTP Server Is Reachable
Wait Until Keyword Succeeds 5s 125ms Check If HTTPS Server Is Reachable
Stop Server
Terminate Process ${http_server_process}
Terminate Process ${https_server_process}
Check If HTTP Server Is Reachable
Log Try reaching ${HTTP_URL}/status.
${resp}= GET ${HTTP_URL}/status expected_status=204
Check If HTTPS Server Is Reachable
Log Try reaching ${HTTPS_URL}/status.
${resp}= GET ${HTTPS_URL}/status expected_status=204 verify=${False}
Add Key Value Pair
[Arguments] ${base_url} ${key} ${value}
${resp}= POST ${base_url}/api/${key} data=${value} expected_status=204 verify=${False}
Get Key Value Pair
[Arguments] ${base_url} ${key} ${expected_value}
${resp}= GET ${base_url}/api/${key} expected_status=200 verify=${False}
Should Be Equal As Strings ${resp.content} ${expected_value}
Update Key Value Pair
[Arguments] ${base_url} ${key} ${new_value}
${resp}= POST ${base_url}/api/${key} data=${new_value} expected_status=204 verify=${False}
Delete Key Value Pair
[Arguments] ${base_url} ${key}
${resp}= DELETE ${base_url}/api/${key} expected_status=204 verify=${False}
Key Should Not Exist
[Arguments] ${base_url} ${key}
${resp}= GET ${base_url}/api/${key} expected_status=404 verify=${False}
-----BEGIN RSA PRIVATE KEY-----
MIIEogIBAAKCAQEAx6G3HAEEKm2QDXTncfOdlv51MxnMKbqzovM24fcgsTMJxTKI
FvQLKihJ3bMqVegIf3CM+OTwIAnRIPtaXNgxu/hNPkJVeAoTcAg7pPhUlgeqajEw
nWXC3iMJQBj6ejsPb+NHVuyBaQ3rRSlxKOpKhM0eT+fENGuiqQrabEjKoZOez8vN
8AfYDwNb6bO+5Dew+QiN6GsvOkwOY+Z3xTE9V/++x7NuHLFugi51vzg+H9USu/VI
D3f5KTykNYzavobEezWU3H6wBdYXH0nMZyms5zu1qKUrdZO+Tai3Z0jdRiHIthqY
l2CrV2fZeUxK79jrnKcP7vmv8IypV464Cy/ZXwIDAQABAoIBAC0Y7jmoTR2clJ9F
modWhnI215kMqd9/atdT5EEVx8/f/MQMj0vII8GJSm6H6/duLIVFksMjTM+gCBtQ
TPCOcmXJSQHYkGBGvm9fnMG+y7T81FWa+SWFeIkgFxXgzqzQLMOU72fGk9F8sHp2
Szb3/o+TmtZoQB2rdxqC9ibiJsxrG5IBVKkzlSPv3POkPXwSb1HcETqrTwefuioj
WMuMrqtm5Y3HddJ5l4JEF5VA3KrsfXWl3JLHH0UViemVahiNjXQAVTKAXIL1PHAV
J2MCEvlpA7sIgXREbmvPvZUTkt3pIqhVjZVJ7tHiSnSecqNTbuxcocnhKhZrHNtC
v2zYKHkCgYEA6cAIhz0qOGDycZ1lf9RSWw0RO1hO8frATMQNVoFVuJJCVL22u96u
0FvJ0JGyYbjthULnlOKyRe7DUL5HRLVS4D7vvKCrgwDmsJp1VFxMdASUdaBfq6aX
oKLUW4q7kC2lQcmK/PVRYwp2GQSx8bodWe+DtXUY/GcN03znY8mhSB0CgYEA2qJK
1GSZsm6kFbDek3BiMMHfO+X819owB2FmXiH+GQckyIZu9xA3HWrkOWTqwglEvzfO
qzFF96E9iEEtseAxhcM8gPvfFuXiUj9t2nH/7SzMnVGikhtYi0p6jrgHmscc4NBx
AOUA15kYEFOGqpZfl2uuKqgHidrHdGkJzzSUBqsCgYAVCjb6TVQejQNlnKBFOExN
a8iwScuZVlO21TLKJYwct/WGgSkQkgO0N37b6jFfQHEIvLPxn9IiH1KvUuFBWvzh
uGiF1wR5HzykitKizEgJbVwbllrmLXGagO2Sa9NkL+efG1AKYt53hrqIl/aYZoM7
1CZL0AV2uqPw9F4zijOdNQKBgH1WmvWGMsKjQTgaLI9z1ybCjjqlj70jHXOtt+Tx
Md2hRcobn5PN3PrlY68vlpHkhF/nG3jzB3x+GGt7ijm2IE3h7la3jl5vLb8fE9gu
kJykmSz7Nurx+GHqMbaN8/Ycfga4GIB9yGzRHIWHjOVQzb5eAfv8Vk4GeV/YM8Jx
Dwd/AoGAILn8pVC9dIFac2BDOFU5y9ZvMmZAvwRxh9vEWewNvkzg27vdYc+rCHNm
I7H0S/RqfqVeo0ApE5PQ8Sll6RvxN/mbSQo9YeCDGQ1r1rNe4Vs12GAYXAbE4ipf
BTdqMbieumB/zL97iK5baHUFEJ4VRtLQhh/SOXgew/BF8ccpilI=
-----END RSA PRIVATE KEY-----
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