2 #include <boost/beast.hpp> 3 #include <rapidjson/document.h> 4 #include <rapidjson/stringbuffer.h> 5 #include <rapidjson/writer.h> 6 #include "../general_store.hpp" 7 #include "../handler.hpp" 8 #include "../handlers/async/async_handler.hpp" 16 template <
class Body,
class Allocator,
class Send>
17 void handle_request(
GeneralStore& gstore, boost::beast::http::request<Body, boost::beast::http::basic_fields<Allocator>>&& req, Send&& send) {
19 const auto bad_request = [&](boost::beast::string_view why) {
20 boost::beast::http::response<boost::beast::http::string_body> res{boost::beast::http::status::bad_request, req.version()};
21 res.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING);
22 res.set(boost::beast::http::field::content_type,
"text/html");
23 res.keep_alive(req.keep_alive());
25 res.prepare_payload();
30 const auto not_found = [&](boost::beast::string_view target) {
31 boost::beast::http::response<boost::beast::http::string_body> res{boost::beast::http::status::not_found, req.version()};
32 res.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING);
33 res.set(boost::beast::http::field::content_type,
"text/html");
34 res.keep_alive(req.keep_alive());
35 res.body() =
"The resource '" + std::string{target} +
"' was not found.";
36 res.prepare_payload();
41 auto const server_error = [&req](boost::beast::string_view what) {
42 boost::beast::http::response<boost::beast::http::string_body> res{boost::beast::http::status::internal_server_error, req.version()};
43 res.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING);
44 res.set(boost::beast::http::field::content_type,
"text/html");
45 res.keep_alive(req.keep_alive());
46 res.body() =
"An error occurred: '" + std::string{what} +
"'";
47 res.prepare_payload();
51 auto req_method = req.method();
52 logger.
info(
"Received from a Session: HTTP ", boost::beast::http::to_string(req.method()),
' ', req.target());
55 if (req_method == boost::beast::http::verb::head) {
56 http::response<http::empty_body> res{http::status::ok, req.version()};
57 res.set(http::field::server, BOOST_BEAST_VERSION_STRING);
58 res.set(http::field::content_type,
"application/json");
59 res.content_length(0);
60 res.keep_alive(req.keep_alive());
61 return send(std::move(res));
64 constexpr std::array supported_methods = {boost::beast::http::verb::get, boost::beast::http::verb::patch, boost::beast::http::verb::post,
65 boost::beast::http::verb::delete_};
67 if (
std::find(supported_methods.begin(), supported_methods.end(), req_method) == supported_methods.end())
68 return send(bad_request(
"Unknown/Unsupported HTTP-method"));
71 if (req.target().empty() || req.target()[0] !=
'/' || req.target().find(
"..") != boost::beast::string_view::npos)
72 return send(bad_request(
"Illegal request-target"));
74 const auto forward_packid = [&](
auto& res) noexcept {
75 if (
const auto pakid = req[
"X-Packet-ID"]; !pakid.empty())
76 res.set(
"X-Packet-ID", pakid);
82 if (path_parts.empty())
83 return send(bad_request(
"No module name specified"));
86 if (path_parts[0] ==
"async") {
87 if (path_parts.size() != 2)
88 return send(bad_request(
"Invalid request target"));
90 if (
auto opt = target.getBool(
"async"); opt && *opt)
91 return send(bad_request(
"Async retrieve cannot be async'ed"));
93 auto [code, body] = handle_async_retrieve<TransportProto::HTTP1>(gstore, path_parts[1]);
95 boost::beast::http::response<boost::beast::http::string_body> res{code, req.version()};
96 res.content_length(body.size());
97 res.body() = std::move(body);
98 res.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING);
99 res.set(boost::beast::http::field::content_type,
"application/json");
101 res.keep_alive(req.keep_alive());
102 return send(std::move(res));
105 if (
auto opt = target.getBool(
"async"); opt && *opt) {
106 auto launch_res = gstore.
async_store.
launch([&gstore, target = std::move(target), req = std::move(req)]() {
108 return std::string{buf.GetString(), buf.GetLength()};
112 return send(server_error(
"Unable to enqueue async request"));
116 boost::beast::http::response<boost::beast::http::string_body> res{boost::beast::http::status::ok, req.version()};
117 res.body() = std::string{
hex_encode_id(*launch_res).data(), n_bytes};
118 res.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING);
119 res.set(boost::beast::http::field::content_type,
"application/json");
121 res.content_length(n_bytes);
122 res.keep_alive(req.keep_alive());
123 return send(std::move(res));
126 auto buffer =
handle_json(gstore, req, std::move(target));
152 boost::beast::http::response<boost::beast::http::string_body> res{boost::beast::http::status::ok, req.version()};
153 res.body() = std::string{buffer.GetString()};
154 res.set(boost::beast::http::field::server, BOOST_BEAST_VERSION_STRING);
155 res.set(boost::beast::http::field::content_type,
"application/json");
157 handle_compression(
static_cast<const boost::beast::http::basic_fields<Allocator>&
>(req), static_cast<boost::beast::http::fields&>(res),
159 res.content_length(std::size_t{res.body().size()});
160 res.keep_alive(req.keep_alive());
161 return send(std::move(res));
Logger logger
Definition: logger.hpp:58
bool handle_compression(const boost::beast::http::basic_fields< Allocator > &in_head, boost::beast::http::basic_fields< Allocator > &out_head, std::string &body)
Definition: compression.hpp:39
AsyncStore async_store
Definition: general_store.hpp:10
void info(Ts...msg)
Definition: logger.hpp:34
void handle_request(GeneralStore &gstore, boost::beast::http::request< Body, boost::beast::http::basic_fields< Allocator >> &&req, Send &&send)
Definition: request_handler.hpp:17
rapidjson::StringBuffer handle_json(GeneralStore &gstore, const http::request< Body, http::basic_fields< Allocator >> &req, const TargetParser &target)
Definition: handler.hpp:25
std::uint32_t IndexType
Type used as the key to elems.
Definition: async_store.hpp:16
constexpr const std::vector< std::string_view > & getPathParts() const noexcept
Definition: urlparser.hpp:83
constexpr InputIt find(InputIt first, InputIt last, const T &value)
Definition: cexpr_algs.hpp:4
std::optional< IndexType > launch(Fcn &&fcn, std::optional< std::chrono::seconds > expire_opt=std::nullopt)
Definition: async_store.hpp:52
constexpr std::array< char, sizeof(std::uint32_t)*2 > hex_encode_id(std::uint32_t id) noexcept
Definition: async_handler.hpp:54
Definition: urlparser.hpp:36
Definition: general_store.hpp:5