summaryrefslogtreecommitdiff
path: root/crow/include
diff options
context:
space:
mode:
Diffstat (limited to 'crow/include')
-rw-r--r--crow/include/crow.h3
-rw-r--r--crow/include/crow/app.h389
-rw-r--r--crow/include/crow/common.h195
-rw-r--r--crow/include/crow/http_connection.h1019
-rw-r--r--crow/include/crow/http_request.h98
-rw-r--r--crow/include/crow/http_response.h218
-rw-r--r--crow/include/crow/http_server.h294
-rw-r--r--crow/include/crow/logging.h202
-rw-r--r--crow/include/crow/middleware_context.h83
-rw-r--r--crow/include/crow/query_string.h563
-rw-r--r--crow/include/crow/routing.h1977
-rw-r--r--crow/include/crow/socket_adaptors.h276
-rw-r--r--crow/include/crow/timer_queue.h115
-rw-r--r--crow/include/crow/utility.h919
-rw-r--r--crow/include/crow/websocket.h398
15 files changed, 3728 insertions, 3021 deletions
diff --git a/crow/include/crow.h b/crow/include/crow.h
index edc0d7f924..7e31cf335c 100644
--- a/crow/include/crow.h
+++ b/crow/include/crow.h
@@ -1,4 +1,6 @@
#pragma once
+#include "boost/beast/core.hpp"
+
#include "crow/app.h"
#include "crow/common.h"
#include "crow/http_connection.h"
@@ -13,4 +15,3 @@
#include "crow/timer_queue.h"
#include "crow/utility.h"
#include "crow/websocket.h"
-#include "boost/beast/core.hpp"
diff --git a/crow/include/crow/app.h b/crow/include/crow/app.h
index 78d99df0e1..7051ec869f 100644
--- a/crow/include/crow/app.h
+++ b/crow/include/crow/app.h
@@ -7,6 +7,7 @@
#include <memory>
#include <string>
#include <utility>
+
#include "crow/http_request.h"
#include "crow/http_server.h"
#include "crow/logging.h"
@@ -14,198 +15,236 @@
#include "crow/routing.h"
#include "crow/utility.h"
-#define BMCWEB_ROUTE(app, url) \
- app.template route<crow::black_magic::get_parameter_tag(url)>(url)
+#define BMCWEB_ROUTE(app, url) \
+ app.template route<crow::black_magic::get_parameter_tag(url)>(url)
-namespace crow {
+namespace crow
+{
#ifdef BMCWEB_ENABLE_SSL
using ssl_context_t = boost::asio::ssl::context;
#endif
-template <typename... Middlewares>
-class Crow {
- public:
- using self_t = Crow;
- using server_t = Server<Crow, SocketAdaptor, Middlewares...>;
+template <typename... Middlewares> class Crow
+{
+ public:
+ using self_t = Crow;
+ using server_t = Server<Crow, SocketAdaptor, Middlewares...>;
#ifdef BMCWEB_ENABLE_SSL
- using ssl_server_t = Server<Crow, SSLAdaptor, Middlewares...>;
+ using ssl_server_t = Server<Crow, SSLAdaptor, Middlewares...>;
#endif
- explicit Crow(std::shared_ptr<boost::asio::io_service> io =
- std::make_shared<boost::asio::io_service>())
- : io(std::move(io)) {}
- ~Crow() { this->stop(); }
-
- template <typename Adaptor>
- void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor) {
- router.handleUpgrade(req, res, adaptor);
- }
-
- void handle(const Request& req, Response& res) { router.handle(req, res); }
-
- DynamicRule& routeDynamic(std::string&& rule) {
- return router.newRuleDynamic(rule);
- }
-
- template <uint64_t Tag>
- auto route(std::string&& rule) -> typename std::result_of<
- decltype (&Router::newRuleTagged<Tag>)(Router, std::string&&)>::type {
- return router.newRuleTagged<Tag>(std::move(rule));
- }
-
- self_t& socket(int existing_socket) {
- socketFd = existing_socket;
- return *this;
- }
-
- self_t& port(std::uint16_t port) {
- portUint = port;
- return *this;
- }
-
- self_t& bindaddr(std::string bindaddr) {
- bindaddrStr = bindaddr;
- return *this;
- }
-
- void validate() { router.validate(); }
-
- void run() {
- validate();
+ explicit Crow(std::shared_ptr<boost::asio::io_service> io =
+ std::make_shared<boost::asio::io_service>()) :
+ io(std::move(io))
+ {
+ }
+ ~Crow()
+ {
+ this->stop();
+ }
+
+ template <typename Adaptor>
+ void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor)
+ {
+ router.handleUpgrade(req, res, adaptor);
+ }
+
+ void handle(const Request& req, Response& res)
+ {
+ router.handle(req, res);
+ }
+
+ DynamicRule& routeDynamic(std::string&& rule)
+ {
+ return router.newRuleDynamic(rule);
+ }
+
+ template <uint64_t Tag>
+ auto route(std::string&& rule) -> typename std::result_of<
+ decltype (&Router::newRuleTagged<Tag>)(Router, std::string&&)>::type
+ {
+ return router.newRuleTagged<Tag>(std::move(rule));
+ }
+
+ self_t& socket(int existing_socket)
+ {
+ socketFd = existing_socket;
+ return *this;
+ }
+
+ self_t& port(std::uint16_t port)
+ {
+ portUint = port;
+ return *this;
+ }
+
+ self_t& bindaddr(std::string bindaddr)
+ {
+ bindaddrStr = bindaddr;
+ return *this;
+ }
+
+ void validate()
+ {
+ router.validate();
+ }
+
+ void run()
+ {
+ validate();
#ifdef BMCWEB_ENABLE_SSL
- if (useSsl) {
- if (-1 == socketFd) {
- sslServer = std::move(std::make_unique<ssl_server_t>(
- this, bindaddrStr, portUint, &middlewares, &sslContext, io));
- } else {
- sslServer = std::move(std::make_unique<ssl_server_t>(
- this, socketFd, &middlewares, &sslContext, io));
- }
- sslServer->setTickFunction(tickInterval, tickFunction);
- sslServer->run();
- } else
+ if (useSsl)
+ {
+ if (-1 == socketFd)
+ {
+ sslServer = std::move(std::make_unique<ssl_server_t>(
+ this, bindaddrStr, portUint, &middlewares, &sslContext,
+ io));
+ }
+ else
+ {
+ sslServer = std::move(std::make_unique<ssl_server_t>(
+ this, socketFd, &middlewares, &sslContext, io));
+ }
+ sslServer->setTickFunction(tickInterval, tickFunction);
+ sslServer->run();
+ }
+ else
#endif
+ {
+ if (-1 == socketFd)
+ {
+ server = std::move(std::make_unique<server_t>(
+ this, bindaddrStr, portUint, &middlewares, nullptr, io));
+ }
+ else
+ {
+ server = std::move(std::make_unique<server_t>(
+ this, socketFd, &middlewares, nullptr, io));
+ }
+ server->setTickFunction(tickInterval, tickFunction);
+ server->run();
+ }
+ }
+
+ void stop()
{
- if (-1 == socketFd) {
- server = std::move(std::make_unique<server_t>(
- this, bindaddrStr, portUint, &middlewares, nullptr, io));
- } else {
- server = std::move(std::make_unique<server_t>(
- this, socketFd, &middlewares, nullptr, io));
- }
- server->setTickFunction(tickInterval, tickFunction);
- server->run();
- }
- }
-
- void stop() { io->stop(); }
-
- void debugPrint() {
- BMCWEB_LOG_DEBUG << "Routing:";
- router.debugPrint();
- }
-
- std::vector<const std::string*> getRoutes() {
- // TODO(ed) Should this be /?
- const std::string root("");
- return router.getRoutes(root);
- }
- std::vector<const std::string*> getRoutes(const std::string& parent) {
- return router.getRoutes(parent);
- }
+ io->stop();
+ }
+
+ void debugPrint()
+ {
+ BMCWEB_LOG_DEBUG << "Routing:";
+ router.debugPrint();
+ }
+
+ std::vector<const std::string*> getRoutes()
+ {
+ // TODO(ed) Should this be /?
+ const std::string root("");
+ return router.getRoutes(root);
+ }
+ std::vector<const std::string*> getRoutes(const std::string& parent)
+ {
+ return router.getRoutes(parent);
+ }
#ifdef BMCWEB_ENABLE_SSL
- self_t& sslFile(const std::string& crt_filename,
- const std::string& key_filename) {
- useSsl = true;
- sslContext.set_verify_mode(boost::asio::ssl::verify_peer);
- sslContext.use_certificate_file(crt_filename, ssl_context_t::pem);
- sslContext.use_private_key_file(key_filename, ssl_context_t::pem);
- sslContext.set_options(boost::asio::ssl::context::default_workarounds |
- boost::asio::ssl::context::no_sslv2 |
- boost::asio::ssl::context::no_sslv3);
- return *this;
- }
-
- self_t& sslFile(const std::string& pem_filename) {
- useSsl = true;
- sslContext.set_verify_mode(boost::asio::ssl::verify_peer);
- sslContext.load_verify_file(pem_filename);
- sslContext.set_options(boost::asio::ssl::context::default_workarounds |
- boost::asio::ssl::context::no_sslv2 |
- boost::asio::ssl::context::no_sslv3);
- return *this;
- }
-
- self_t& ssl(boost::asio::ssl::context&& ctx) {
- useSsl = true;
- sslContext = std::move(ctx);
- return *this;
- }
-
- bool useSsl{false};
- ssl_context_t sslContext{boost::asio::ssl::context::sslv23};
+ self_t& sslFile(const std::string& crt_filename,
+ const std::string& key_filename)
+ {
+ useSsl = true;
+ sslContext.set_verify_mode(boost::asio::ssl::verify_peer);
+ sslContext.use_certificate_file(crt_filename, ssl_context_t::pem);
+ sslContext.use_private_key_file(key_filename, ssl_context_t::pem);
+ sslContext.set_options(boost::asio::ssl::context::default_workarounds |
+ boost::asio::ssl::context::no_sslv2 |
+ boost::asio::ssl::context::no_sslv3);
+ return *this;
+ }
+
+ self_t& sslFile(const std::string& pem_filename)
+ {
+ useSsl = true;
+ sslContext.set_verify_mode(boost::asio::ssl::verify_peer);
+ sslContext.load_verify_file(pem_filename);
+ sslContext.set_options(boost::asio::ssl::context::default_workarounds |
+ boost::asio::ssl::context::no_sslv2 |
+ boost::asio::ssl::context::no_sslv3);
+ return *this;
+ }
+
+ self_t& ssl(boost::asio::ssl::context&& ctx)
+ {
+ useSsl = true;
+ sslContext = std::move(ctx);
+ return *this;
+ }
+
+ bool useSsl{false};
+ ssl_context_t sslContext{boost::asio::ssl::context::sslv23};
#else
- template <typename T, typename... Remain>
- self_t& ssl_file(T&&, Remain&&...) {
- // We can't call .ssl() member function unless BMCWEB_ENABLE_SSL is defined.
- static_assert(
- // make static_assert dependent to T; always false
- std::is_base_of<T, void>::value,
- "Define BMCWEB_ENABLE_SSL to enable ssl support.");
- return *this;
- }
-
- template <typename T>
- self_t& ssl(T&&) {
- // We can't call .ssl() member function unless BMCWEB_ENABLE_SSL is defined.
- static_assert(
- // make static_assert dependent to T; always false
- std::is_base_of<T, void>::value,
- "Define BMCWEB_ENABLE_SSL to enable ssl support.");
- return *this;
- }
+ template <typename T, typename... Remain> self_t& ssl_file(T&&, Remain&&...)
+ {
+ // We can't call .ssl() member function unless BMCWEB_ENABLE_SSL is
+ // defined.
+ static_assert(
+ // make static_assert dependent to T; always false
+ std::is_base_of<T, void>::value,
+ "Define BMCWEB_ENABLE_SSL to enable ssl support.");
+ return *this;
+ }
+
+ template <typename T> self_t& ssl(T&&)
+ {
+ // We can't call .ssl() member function unless BMCWEB_ENABLE_SSL is
+ // defined.
+ static_assert(
+ // make static_assert dependent to T; always false
+ std::is_base_of<T, void>::value,
+ "Define BMCWEB_ENABLE_SSL to enable ssl support.");
+ return *this;
+ }
#endif
- // middleware
- using context_t = detail::Context<Middlewares...>;
- template <typename T>
- typename T::Context& getContext(const Request& req) {
- static_assert(black_magic::Contains<T, Middlewares...>::value,
- "App doesn't have the specified middleware type.");
- auto& ctx = *reinterpret_cast<context_t*>(req.middlewareContext);
- return ctx.template get<T>();
- }
-
- template <typename T>
- T& getMiddleware() {
- return utility::getElementByType<T, Middlewares...>(middlewares);
- }
-
- template <typename Duration, typename Func>
- self_t& tick(Duration d, Func f) {
- tickInterval = std::chrono::duration_cast<std::chrono::milliseconds>(d);
- tickFunction = f;
- return *this;
- }
-
- private:
- std::shared_ptr<asio::io_service> io;
- uint16_t portUint = 80;
- std::string bindaddrStr = "::";
- int socketFd = -1;
- Router router;
-
- std::chrono::milliseconds tickInterval{};
- std::function<void()> tickFunction;
-
- std::tuple<Middlewares...> middlewares;
+ // middleware
+ using context_t = detail::Context<Middlewares...>;
+ template <typename T> typename T::Context& getContext(const Request& req)
+ {
+ static_assert(black_magic::Contains<T, Middlewares...>::value,
+ "App doesn't have the specified middleware type.");
+ auto& ctx = *reinterpret_cast<context_t*>(req.middlewareContext);
+ return ctx.template get<T>();
+ }
+
+ template <typename T> T& getMiddleware()
+ {
+ return utility::getElementByType<T, Middlewares...>(middlewares);
+ }
+
+ template <typename Duration, typename Func> self_t& tick(Duration d, Func f)
+ {
+ tickInterval = std::chrono::duration_cast<std::chrono::milliseconds>(d);
+ tickFunction = f;
+ return *this;
+ }
+
+ private:
+ std::shared_ptr<asio::io_service> io;
+ uint16_t portUint = 80;
+ std::string bindaddrStr = "::";
+ int socketFd = -1;
+ Router router;
+
+ std::chrono::milliseconds tickInterval{};
+ std::function<void()> tickFunction;
+
+ std::tuple<Middlewares...> middlewares;
#ifdef BMCWEB_ENABLE_SSL
- std::unique_ptr<ssl_server_t> sslServer;
+ std::unique_ptr<ssl_server_t> sslServer;
#endif
- std::unique_ptr<server_t> server;
+ std::unique_ptr<server_t> server;
};
-template <typename... Middlewares>
-using App = Crow<Middlewares...>;
+template <typename... Middlewares> using App = Crow<Middlewares...>;
using SimpleApp = Crow<>;
-} // namespace crow
+} // namespace crow
diff --git a/crow/include/crow/common.h b/crow/include/crow/common.h
index e155da6da9..b3e424f994 100644
--- a/crow/include/crow/common.h
+++ b/crow/include/crow/common.h
@@ -1,127 +1,140 @@
#pragma once
+#include <boost/beast/http/verb.hpp>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
+
#include "crow/utility.h"
-#include <boost/beast/http/verb.hpp>
-namespace crow {
-enum class HTTPMethod {
+namespace crow
+{
+enum class HTTPMethod
+{
#ifndef DELETE
- DELETE = 0,
- GET,
- HEAD,
- POST,
- PUT,
- CONNECT,
- OPTIONS,
- TRACE,
- PATCH = 24, // see http_parser_merged.h line 118 for why it is 24
+ DELETE = 0,
+ GET,
+ HEAD,
+ POST,
+ PUT,
+ CONNECT,
+ OPTIONS,
+ TRACE,
+ PATCH = 24, // see http_parser_merged.h line 118 for why it is 24
#endif
- Delete = 0,
- Get,
- Head,
- Post,
- Put,
- Connect,
- Options,
- Trace,
- Patch = 24,
+ Delete = 0,
+ Get,
+ Head,
+ Post,
+ Put,
+ Connect,
+ Options,
+ Trace,
+ Patch = 24,
};
-inline std::string methodName(boost::beast::http::verb method) {
- switch (method) {
- case boost::beast::http::verb::delete_:
- return "DELETE";
- case boost::beast::http::verb::get:
- return "GET";
- case boost::beast::http::verb::head:
- return "HEAD";
- case boost::beast::http::verb::post:
- return "POST";
- case boost::beast::http::verb::put:
- return "PUT";
- case boost::beast::http::verb::connect:
- return "CONNECT";
- case boost::beast::http::verb::options:
- return "OPTIONS";
- case boost::beast::http::verb::trace:
- return "TRACE";
- case boost::beast::http::verb::patch:
- return "PATCH";
- }
- return "invalid";
+inline std::string methodName(boost::beast::http::verb method)
+{
+ switch (method)
+ {
+ case boost::beast::http::verb::delete_:
+ return "DELETE";
+ case boost::beast::http::verb::get:
+ return "GET";
+ case boost::beast::http::verb::head:
+ return "HEAD";
+ case boost::beast::http::verb::post:
+ return "POST";
+ case boost::beast::http::verb::put:
+ return "PUT";
+ case boost::beast::http::verb::connect:
+ return "CONNECT";
+ case boost::beast::http::verb::options:
+ return "OPTIONS";
+ case boost::beast::http::verb::trace:
+ return "TRACE";
+ case boost::beast::http::verb::patch:
+ return "PATCH";
+ }
+ return "invalid";
}
-enum class ParamType {
- INT,
- UINT,
- DOUBLE,
- STRING,
- PATH,
+enum class ParamType
+{
+ INT,
+ UINT,
+ DOUBLE,
+ STRING,
+ PATH,
- MAX
+ MAX
};
-struct RoutingParams {
- std::vector<int64_t> intParams;
- std::vector<uint64_t> uintParams;
- std::vector<double> doubleParams;
- std::vector<std::string> stringParams;
+struct RoutingParams
+{
+ std::vector<int64_t> intParams;
+ std::vector<uint64_t> uintParams;
+ std::vector<double> doubleParams;
+ std::vector<std::string> stringParams;
- void debugPrint() const {
- std::cerr << "RoutingParams" << std::endl;
- for (auto i : intParams) {
- std::cerr << i << ", ";
- }
- std::cerr << std::endl;
- for (auto i : uintParams) {
- std::cerr << i << ", ";
+ void debugPrint() const
+ {
+ std::cerr << "RoutingParams" << std::endl;
+ for (auto i : intParams)
+ {
+ std::cerr << i << ", ";
+ }
+ std::cerr << std::endl;
+ for (auto i : uintParams)
+ {
+ std::cerr << i << ", ";
+ }
+ std::cerr << std::endl;
+ for (auto i : doubleParams)
+ {
+ std::cerr << i << ", ";
+ }
+ std::cerr << std::endl;
+ for (auto& i : stringParams)
+ {
+ std::cerr << i << ", ";
+ }
+ std::cerr << std::endl;
}
- std::cerr << std::endl;
- for (auto i : doubleParams) {
- std::cerr << i << ", ";
- }
- std::cerr << std::endl;
- for (auto& i : stringParams) {
- std::cerr << i << ", ";
- }
- std::cerr << std::endl;
- }
- template <typename T>
- T get(unsigned) const;
+ template <typename T> T get(unsigned) const;
};
-template <>
-inline int64_t RoutingParams::get<int64_t>(unsigned index) const {
- return intParams[index];
+template <> inline int64_t RoutingParams::get<int64_t>(unsigned index) const
+{
+ return intParams[index];
}
-template <>
-inline uint64_t RoutingParams::get<uint64_t>(unsigned index) const {
- return uintParams[index];
+template <> inline uint64_t RoutingParams::get<uint64_t>(unsigned index) const
+{
+ return uintParams[index];
}
-template <>
-inline double RoutingParams::get<double>(unsigned index) const {
- return doubleParams[index];
+template <> inline double RoutingParams::get<double>(unsigned index) const
+{
+ return doubleParams[index];
}
template <>
-inline std::string RoutingParams::get<std::string>(unsigned index) const {
- return stringParams[index];
+inline std::string RoutingParams::get<std::string>(unsigned index) const
+{
+ return stringParams[index];
}
-} // namespace crow
+} // namespace crow
constexpr boost::beast::http::verb operator"" _method(const char* str,
- size_t /*len*/) {
- using verb = boost::beast::http::verb;
- // clang-format off
+ size_t /*len*/)
+{
+ using verb = boost::beast::http::verb;
+ // clang-format off
return
crow::black_magic::isEquP(str, "GET", 3) ? verb::get :
crow::black_magic::isEquP(str, "DELETE", 6) ? verb::delete_ :
@@ -134,5 +147,5 @@ constexpr boost::beast::http::verb operator"" _method(const char* str,
crow::black_magic::isEquP(str, "PATCH", 5) ? verb::patch :
crow::black_magic::isEquP(str, "PURGE", 5) ? verb::purge :
throw std::runtime_error("invalid http method");
- // clang-format on
+ // clang-format on
} \ No newline at end of file
diff --git a/crow/include/crow/http_connection.h b/crow/include/crow/http_connection.h
index 5f2f719a9b..6d62c85bc4 100644
--- a/crow/include/crow/http_connection.h
+++ b/crow/include/crow/http_connection.h
@@ -1,249 +1,279 @@
#pragma once
+#include "http_utility.hpp"
+
#include <array>
#include <atomic>
+#include <boost/algorithm/string.hpp>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/asio.hpp>
+#include <boost/beast/core.hpp>
+#include <boost/beast/http.hpp>
+#include <boost/beast/websocket.hpp>
#include <chrono>
#include <regex>
#include <vector>
-#include "http_utility.hpp"
+
#include "crow/http_response.h"
#include "crow/logging.h"
#include "crow/middleware_context.h"
#include "crow/socket_adaptors.h"
#include "crow/timer_queue.h"
-#include <boost/algorithm/string.hpp>
-#include <boost/algorithm/string/predicate.hpp>
-#include <boost/asio.hpp>
-#include <boost/beast/core.hpp>
-#include <boost/beast/http.hpp>
-#include <boost/beast/websocket.hpp>
#ifdef BMCWEB_ENABLE_SSL
#include <boost/asio/ssl.hpp>
#endif
-namespace crow {
-
-inline void escapeHtml(std::string& data) {
- std::string buffer;
- // less than 5% of characters should be larger, so reserve a buffer of the
- // right size
- buffer.reserve(data.size() * 1.05);
- for (size_t pos = 0; pos != data.size(); ++pos) {
- switch (data[pos]) {
- case '&':
- buffer.append("&amp;");
- break;
- case '\"':
- buffer.append("&quot;");
- break;
- case '\'':
- buffer.append("&apos;");
- break;
- case '<':
- buffer.append("&lt;");
- break;
- case '>':
- buffer.append("&gt;");
- break;
- default:
- buffer.append(&data[pos], 1);
- break;
+namespace crow
+{
+
+inline void escapeHtml(std::string& data)
+{
+ std::string buffer;
+ // less than 5% of characters should be larger, so reserve a buffer of the
+ // right size
+ buffer.reserve(data.size() * 1.05);
+ for (size_t pos = 0; pos != data.size(); ++pos)
+ {
+ switch (data[pos])
+ {
+ case '&':
+ buffer.append("&amp;");
+ break;
+ case '\"':
+ buffer.append("&quot;");
+ break;
+ case '\'':
+ buffer.append("&apos;");
+ break;
+ case '<':
+ buffer.append("&lt;");
+ break;
+ case '>':
+ buffer.append("&gt;");
+ break;
+ default:
+ buffer.append(&data[pos], 1);
+ break;
+ }
}
- }
- data.swap(buffer);
+ data.swap(buffer);
}
-inline void convertToLinks(std::string& s) {
- const static std::regex r{
- "(&quot;@odata\\.((id)|(Context))&quot;[ \\n]*:[ "
- "\\n]*)(&quot;((?!&quot;).*)&quot;)"};
- s = std::regex_replace(s, r, "$1<a href=\"$6\">$5</a>");
+inline void convertToLinks(std::string& s)
+{
+ const static std::regex r{"(&quot;@odata\\.((id)|(Context))&quot;[ \\n]*:[ "
+ "\\n]*)(&quot;((?!&quot;).*)&quot;)"};
+ s = std::regex_replace(s, r, "$1<a href=\"$6\">$5</a>");
}
-inline void prettyPrintJson(crow::Response& res) {
- std::string value = res.jsonValue.dump(4);
- escapeHtml(value);
- convertToLinks(value);
- res.body() =
- "<html>\n"
- "<head>\n"
- "<title>Redfish API</title>\n"
- "<link rel=\"stylesheet\" type=\"text/css\" "
- "href=\"/styles/default.css\">\n"
- "<script src=\"/highlight.pack.js\"></script>"
- "<script>hljs.initHighlightingOnLoad();</script>"
- "</head>\n"
- "<body>\n"
- "<div style=\"max-width: 576px;margin:0 auto;\">\n"
- "<img src=\"/DMTF_Redfish_logo_2017.svg\" alt=\"redfish\" "
- "height=\"406px\" "
- "width=\"576px\">\n"
- "<br>\n"
- "<pre>\n"
- "<code class=\"json\">" +
- value +
- "</code>\n"
- "</pre>\n"
- "</div>\n"
- "</body>\n"
- "</html>\n";
+inline void prettyPrintJson(crow::Response& res)
+{
+ std::string value = res.jsonValue.dump(4);
+ escapeHtml(value);
+ convertToLinks(value);
+ res.body() = "<html>\n"
+ "<head>\n"
+ "<title>Redfish API</title>\n"
+ "<link rel=\"stylesheet\" type=\"text/css\" "
+ "href=\"/styles/default.css\">\n"
+ "<script src=\"/highlight.pack.js\"></script>"
+ "<script>hljs.initHighlightingOnLoad();</script>"
+ "</head>\n"
+ "<body>\n"
+ "<div style=\"max-width: 576px;margin:0 auto;\">\n"
+ "<img src=\"/DMTF_Redfish_logo_2017.svg\" alt=\"redfish\" "
+ "height=\"406px\" "
+ "width=\"576px\">\n"
+ "<br>\n"
+ "<pre>\n"
+ "<code class=\"json\">" +
+ value +
+ "</code>\n"
+ "</pre>\n"
+ "</div>\n"
+ "</body>\n"
+ "</html>\n";
}
using namespace boost;
using tcp = asio::ip::tcp;
-namespace detail {
-template <typename MW>
-struct CheckBeforeHandleArity3Const {
- template <typename T, void (T::*)(Request&, Response&, typename MW::Context&)
- const = &T::beforeHandle>
- struct Get {};
+namespace detail
+{
+template <typename MW> struct CheckBeforeHandleArity3Const
+{
+ template <typename T,
+ void (T::*)(Request&, Response&, typename MW::Context&) const =
+ &T::beforeHandle>
+ struct Get
+ {
+ };
};
-template <typename MW>
-struct CheckBeforeHandleArity3 {
- template <typename T, void (T::*)(Request&, Response&,
- typename MW::Context&) = &T::beforeHandle>
- struct Get {};
+template <typename MW> struct CheckBeforeHandleArity3
+{
+ template <typename T, void (T::*)(Request&, Response&,
+ typename MW::Context&) = &T::beforeHandle>
+ struct Get
+ {
+ };
};
-template <typename MW>
-struct CheckAfterHandleArity3Const {
- template <typename T, void (T::*)(Request&, Response&, typename MW::Context&)
- const = &T::afterHandle>
- struct Get {};
+template <typename MW> struct CheckAfterHandleArity3Const
+{
+ template <typename T,
+ void (T::*)(Request&, Response&, typename MW::Context&) const =
+ &T::afterHandle>
+ struct Get
+ {
+ };
};
-template <typename MW>
-struct CheckAfterHandleArity3 {
- template <typename T, void (T::*)(Request&, Response&,
- typename MW::Context&) = &T::afterHandle>
- struct Get {};
+template <typename MW> struct CheckAfterHandleArity3
+{
+ template <typename T, void (T::*)(Request&, Response&,
+ typename MW::Context&) = &T::afterHandle>
+ struct Get
+ {
+ };
};
-template <typename T>
-struct IsBeforeHandleArity3Impl {
- template <typename C>
- static std::true_type f(
- typename CheckBeforeHandleArity3Const<T>::template Get<C>*);
+template <typename T> struct IsBeforeHandleArity3Impl
+{
+ template <typename C>
+ static std::true_type
+ f(typename CheckBeforeHandleArity3Const<T>::template Get<C>*);
- template <typename C>
- static std::true_type f(
- typename CheckBeforeHandleArity3<T>::template Get<C>*);
+ template <typename C>
+ static std::true_type
+ f(typename CheckBeforeHandleArity3<T>::template Get<C>*);
- template <typename C>
- static std::false_type f(...);
+ template <typename C> static std::false_type f(...);
- public:
- static const bool value = decltype(f<T>(nullptr))::value;
+ public:
+ static const bool value = decltype(f<T>(nullptr))::value;
};
-template <typename T>
-struct IsAfterHandleArity3Impl {
- template <typename C>
- static std::true_type f(
- typename CheckAfterHandleArity3Const<T>::template Get<C>*);
+template <typename T> struct IsAfterHandleArity3Impl
+{
+ template <typename C>
+ static std::true_type
+ f(typename CheckAfterHandleArity3Const<T>::template Get<C>*);
- template <typename C>
- static std::true_type f(typename CheckAfterHandleArity3<T>::template Get<C>*);
+ template <typename C>
+ static std::true_type
+ f(typename CheckAfterHandleArity3<T>::template Get<C>*);
- template <typename C>
- static std::false_type f(...);
+ template <typename C> static std::false_type f(...);
- public:
- static const bool value = decltype(f<T>(nullptr))::value;
+ public:
+ static const bool value = decltype(f<T>(nullptr))::value;
};
template <typename MW, typename Context, typename ParentContext>
typename std::enable_if<!IsBeforeHandleArity3Impl<MW>::value>::type
-beforeHandlerCall(MW& mw, Request& req, Response& res, Context& ctx,
- ParentContext& /*parent_ctx*/) {
- mw.beforeHandle(req, res, ctx.template get<MW>(), ctx);
+ beforeHandlerCall(MW& mw, Request& req, Response& res, Context& ctx,
+ ParentContext& /*parent_ctx*/)
+{
+ mw.beforeHandle(req, res, ctx.template get<MW>(), ctx);
}
template <typename MW, typename Context, typename ParentContext>
typename std::enable_if<IsBeforeHandleArity3Impl<MW>::value>::type
-beforeHandlerCall(MW& mw, Request& req, Response& res, Context& ctx,
- ParentContext& /*parent_ctx*/) {
- mw.beforeHandle(req, res, ctx.template get<MW>());
+ beforeHandlerCall(MW& mw, Request& req, Response& res, Context& ctx,
+ ParentContext& /*parent_ctx*/)
+{
+ mw.beforeHandle(req, res, ctx.template get<MW>());
}
template <typename MW, typename Context, typename ParentContext>
typename std::enable_if<!IsAfterHandleArity3Impl<MW>::value>::type
-afterHandlerCall(MW& mw, Request& req, Response& res, Context& ctx,
- ParentContext& /*parent_ctx*/) {
- mw.afterHandle(req, res, ctx.template get<MW>(), ctx);
+ afterHandlerCall(MW& mw, Request& req, Response& res, Context& ctx,
+ ParentContext& /*parent_ctx*/)
+{
+ mw.afterHandle(req, res, ctx.template get<MW>(), ctx);
}
template <typename MW, typename Context, typename ParentContext>
typename std::enable_if<IsAfterHandleArity3Impl<MW>::value>::type
-afterHandlerCall(MW& mw, Request& req, Response& res, Context& ctx,
- ParentContext& /*parent_ctx*/) {
- mw.afterHandle(req, res, ctx.template get<MW>());
+ afterHandlerCall(MW& mw, Request& req, Response& res, Context& ctx,
+ ParentContext& /*parent_ctx*/)
+{
+ mw.afterHandle(req, res, ctx.template get<MW>());
}
template <int N, typename Context, typename Container, typename CurrentMW,
typename... Middlewares>
bool middlewareCallHelper(Container& middlewares, Request& req, Response& res,
- Context& ctx) {
- using parent_context_t = typename Context::template partial<N - 1>;
- beforeHandlerCall<CurrentMW, Context, parent_context_t>(
- std::get<N>(middlewares), req, res, ctx,
- static_cast<parent_context_t&>(ctx));
-
- if (res.isCompleted()) {
- afterHandlerCall<CurrentMW, Context, parent_context_t>(
+ Context& ctx)
+{
+ using parent_context_t = typename Context::template partial<N - 1>;
+ beforeHandlerCall<CurrentMW, Context, parent_context_t>(
std::get<N>(middlewares), req, res, ctx,
static_cast<parent_context_t&>(ctx));
- return true;
- }
- if (middlewareCallHelper<N + 1, Context, Container, Middlewares...>(
- middlewares, req, res, ctx)) {
- afterHandlerCall<CurrentMW, Context, parent_context_t>(
- std::get<N>(middlewares), req, res, ctx,
- static_cast<parent_context_t&>(ctx));
- return true;
- }
+ if (res.isCompleted())
+ {
+ afterHandlerCall<CurrentMW, Context, parent_context_t>(
+ std::get<N>(middlewares), req, res, ctx,
+ static_cast<parent_context_t&>(ctx));
+ return true;
+ }
+
+ if (middlewareCallHelper<N + 1, Context, Container, Middlewares...>(
+ middlewares, req, res, ctx))
+ {
+ afterHandlerCall<CurrentMW, Context, parent_context_t>(
+ std::get<N>(middlewares), req, res, ctx,
+ static_cast<parent_context_t&>(ctx));
+ return true;
+ }
- return false;
+ return false;
}
template <int N, typename Context, typename Container>
bool middlewareCallHelper(Container& /*middlewares*/, Request& /*req*/,
- Response& /*res*/, Context& /*ctx*/) {
- return false;
+ Response& /*res*/, Context& /*ctx*/)
+{
+ return false;
}
template <int N, typename Context, typename Container>
-typename std::enable_if<(N < 0)>::type afterHandlersCallHelper(
- Container& /*middlewares*/, Context& /*Context*/, Request& /*req*/,
- Response& /*res*/) {}
+typename std::enable_if<(N < 0)>::type
+ afterHandlersCallHelper(Container& /*middlewares*/, Context& /*Context*/,
+ Request& /*req*/, Response& /*res*/)
+{
+}
template <int N, typename Context, typename Container>
-typename std::enable_if<(N == 0)>::type afterHandlersCallHelper(
- Container& middlewares, Context& ctx, Request& req, Response& res) {
- using parent_context_t = typename Context::template partial<N - 1>;
- using CurrentMW = typename std::tuple_element<
- N, typename std::remove_reference<Container>::type>::type;
- afterHandlerCall<CurrentMW, Context, parent_context_t>(
- std::get<N>(middlewares), req, res, ctx,
- static_cast<parent_context_t&>(ctx));
+typename std::enable_if<(N == 0)>::type
+ afterHandlersCallHelper(Container& middlewares, Context& ctx, Request& req,
+ Response& res)
+{
+ using parent_context_t = typename Context::template partial<N - 1>;
+ using CurrentMW = typename std::tuple_element<
+ N, typename std::remove_reference<Container>::type>::type;
+ afterHandlerCall<CurrentMW, Context, parent_context_t>(
+ std::get<N>(middlewares), req, res, ctx,
+ static_cast<parent_context_t&>(ctx));
}
template <int N, typename Context, typename Container>
-typename std::enable_if<(N > 0)>::type afterHandlersCallHelper(
- Container& middlewares, Context& ctx, Request& req, Response& res) {
- using parent_context_t = typename Context::template partial<N - 1>;
- using CurrentMW = typename std::tuple_element<
- N, typename std::remove_reference<Container>::type>::type;
- afterHandlerCall<CurrentMW, Context, parent_context_t>(
- std::get<N>(middlewares), req, res, ctx,
- static_cast<parent_context_t&>(ctx));
- afterHandlersCallHelper<N - 1, Context, Container>(middlewares, ctx, req,
- res);
+typename std::enable_if<(N > 0)>::type
+ afterHandlersCallHelper(Container& middlewares, Context& ctx, Request& req,
+ Response& res)
+{
+ using parent_context_t = typename Context::template partial<N - 1>;
+ using CurrentMW = typename std::tuple_element<
+ N, typename std::remove_reference<Container>::type>::type;
+ afterHandlerCall<CurrentMW, Context, parent_context_t>(
+ std::get<N>(middlewares), req, res, ctx,
+ static_cast<parent_context_t&>(ctx));
+ afterHandlersCallHelper<N - 1, Context, Container>(middlewares, ctx, req,
+ res);
}
-} // namespace detail
+} // namespace detail
#ifdef BMCWEB_ENABLE_DEBUG
static std::atomic<int> connectionCount;
@@ -253,331 +283,382 @@ static std::atomic<int> connectionCount;
constexpr unsigned int httpReqBodyLimit = 1024 * 1024 * 30;
template <typename Adaptor, typename Handler, typename... Middlewares>
-class Connection {
- public:
- Connection(boost::asio::io_service& ioService, Handler* handler,
- const std::string& server_name,
- std::tuple<Middlewares...>* middlewares,
- std::function<std::string()>& get_cached_date_str_f,
- detail::TimerQueue& timerQueue,
- typename Adaptor::context* adaptorCtx)
- : adaptor(ioService, adaptorCtx),
- handler(handler),
- serverName(server_name),
- middlewares(middlewares),
- getCachedDateStr(get_cached_date_str_f),
- timerQueue(timerQueue) {
- parser.emplace(std::piecewise_construct, std::make_tuple());
- // Temporarily changed to 30MB; Need to modify uploading/authentication
- // mechanism
- parser->body_limit(httpReqBodyLimit);
- req.emplace(parser->get());
+class Connection
+{
+ public:
+ Connection(boost::asio::io_service& ioService, Handler* handler,
+ const std::string& server_name,
+ std::tuple<Middlewares...>* middlewares,
+ std::function<std::string()>& get_cached_date_str_f,
+ detail::TimerQueue& timerQueue,
+ typename Adaptor::context* adaptorCtx) :
+ adaptor(ioService, adaptorCtx),
+ handler(handler), serverName(server_name), middlewares(middlewares),
+ getCachedDateStr(get_cached_date_str_f), timerQueue(timerQueue)
+ {
+ parser.emplace(std::piecewise_construct, std::make_tuple());
+ // Temporarily changed to 30MB; Need to modify uploading/authentication
+ // mechanism
+ parser->body_limit(httpReqBodyLimit);
+ req.emplace(parser->get());
#ifdef BMCWEB_ENABLE_DEBUG
- connectionCount++;
- BMCWEB_LOG_DEBUG << this << " Connection open, total " << connectionCount;
+ connectionCount++;
+ BMCWEB_LOG_DEBUG << this << " Connection open, total "
+ << connectionCount;
#endif
- }
+ }
- ~Connection() {
- res.completeRequestHandler = nullptr;
- cancelDeadlineTimer();
+ ~Connection()
+ {
+ res.completeRequestHandler = nullptr;
+ cancelDeadlineTimer();
#ifdef BMCWEB_ENABLE_DEBUG
- connectionCount--;
- BMCWEB_LOG_DEBUG << this << " Connection closed, total " << connectionCount;
+ connectionCount--;
+ BMCWEB_LOG_DEBUG << this << " Connection closed, total "
+ << connectionCount;
#endif
- }
-
- decltype(std::declval<Adaptor>().rawSocket()) & socket() {
- return adaptor.rawSocket();
- }
-
- void start() {
- adaptor.start([this](const boost::system::error_code& ec) {
- if (!ec) {
- startDeadline();
-
- doReadHeaders();
- } else {
- checkDestroy();
- }
- });
- }
-
- void handle() {
- cancelDeadlineTimer();
- bool isInvalidRequest = false;
- const boost::string_view connection =
- req->getHeaderValue(boost::beast::http::field::connection);
-
- // Check for HTTP version 1.1.
- if (req->version() == 11) {
- if (req->getHeaderValue(boost::beast::http::field::host).empty()) {
- isInvalidRequest = true;
- res = Response(boost::beast::http::status::bad_request);
- }
}
- BMCWEB_LOG_INFO << "Request: " << adaptor.remoteEndpoint() << " " << this
- << " HTTP/" << req->version() / 10 << "."
- << req->version() % 10 << ' ' << req->methodString() << " "
- << req->target();
-
- needToCallAfterHandlers = false;
-
- if (!isInvalidRequest) {
- res.completeRequestHandler = [] {};
- res.isAliveHelper = [this]() -> bool { return adaptor.isOpen(); };
-
- ctx = detail::Context<Middlewares...>();
- req->middlewareContext = (void*)&ctx;
- req->ioService = &adaptor.getIoService();
- detail::middlewareCallHelper<0, decltype(ctx), decltype(*middlewares),
- Middlewares...>(*middlewares, *req, res,
- ctx);
-
- if (!res.completed) {
- if (req->isUpgrade() &&
- boost::iequals(
- req->getHeaderValue(boost::beast::http::field::upgrade),
- "websocket")) {
- handler->handleUpgrade(*req, res, std::move(adaptor));
- return;
+ decltype(std::declval<Adaptor>().rawSocket())& socket()
+ {
+ return adaptor.rawSocket();
+ }
+
+ void start()
+ {
+ adaptor.start([this](const boost::system::error_code& ec) {
+ if (!ec)
+ {
+ startDeadline();
+
+ doReadHeaders();
+ }
+ else
+ {
+ checkDestroy();
+ }
+ });
+ }
+
+ void handle()
+ {
+ cancelDeadlineTimer();
+ bool isInvalidRequest = false;
+ const boost::string_view connection =
+ req->getHeaderValue(boost::beast::http::field::connection);
+
+ // Check for HTTP version 1.1.
+ if (req->version() == 11)
+ {
+ if (req->getHeaderValue(boost::beast::http::field::host).empty())
+ {
+ isInvalidRequest = true;
+ res = Response(boost::beast::http::status::bad_request);
+ }
}
- res.completeRequestHandler = [this] { this->completeRequest(); };
- needToCallAfterHandlers = true;
- handler->handle(*req, res);
- if (req->keepAlive()) {
- res.addHeader("connection", "Keep-Alive");
+
+ BMCWEB_LOG_INFO << "Request: " << adaptor.remoteEndpoint() << " "
+ << this << " HTTP/" << req->version() / 10 << "."
+ << req->version() % 10 << ' ' << req->methodString()
+ << " " << req->target();
+
+ needToCallAfterHandlers = false;
+
+ if (!isInvalidRequest)
+ {
+ res.completeRequestHandler = [] {};
+ res.isAliveHelper = [this]() -> bool { return adaptor.isOpen(); };
+
+ ctx = detail::Context<Middlewares...>();
+ req->middlewareContext = (void*)&ctx;
+ req->ioService = &adaptor.getIoService();
+ detail::middlewareCallHelper<
+ 0, decltype(ctx), decltype(*middlewares), Middlewares...>(
+ *middlewares, *req, res, ctx);
+
+ if (!res.completed)
+ {
+ if (req->isUpgrade() &&
+ boost::iequals(
+ req->getHeaderValue(boost::beast::http::field::upgrade),
+ "websocket"))
+ {
+ handler->handleUpgrade(*req, res, std::move(adaptor));
+ return;
+ }
+ res.completeRequestHandler = [this] {
+ this->completeRequest();
+ };
+ needToCallAfterHandlers = true;
+ handler->handle(*req, res);
+ if (req->keepAlive())
+ {
+ res.addHeader("connection", "Keep-Alive");
+ }
+ }
+ else
+ {
+ completeRequest();
+ }
+ }
+ else
+ {
+ completeRequest();
}
- } else {
- completeRequest();
- }
- } else {
- completeRequest();
}
- }
- void completeRequest() {
- BMCWEB_LOG_INFO << "Response: " << this << ' ' << req->url << ' '
- << res.resultInt() << " keepalive=" << req->keepAlive();
+ void completeRequest()
+ {
+ BMCWEB_LOG_INFO << "Response: " << this << ' ' << req->url << ' '
+ << res.resultInt() << " keepalive=" << req->keepAlive();
+
+ if (needToCallAfterHandlers)
+ {
+ needToCallAfterHandlers = false;
- if (needToCallAfterHandlers) {
- needToCallAfterHandlers = false;
+ // call all afterHandler of middlewares
+ detail::afterHandlersCallHelper<((int)sizeof...(Middlewares) - 1),
+ decltype(ctx),
+ decltype(*middlewares)>(
+ *middlewares, ctx, *req, res);
+ }
- // call all afterHandler of middlewares
- detail::afterHandlersCallHelper<((int)sizeof...(Middlewares) - 1),
- decltype(ctx), decltype(*middlewares)>(
- *middlewares, ctx, *req, res);
+ // auto self = this->shared_from_this();
+ res.completeRequestHandler = nullptr;
+
+ if (!adaptor.isOpen())
+ {
+ // BMCWEB_LOG_DEBUG << this << " delete (socket is closed) " <<
+ // isReading
+ // << ' ' << isWriting;
+ // delete this;
+ return;
+ }
+ if (res.body().empty() && !res.jsonValue.empty())
+ {
+ if (http_helpers::requestPrefersHtml(*req))
+ {
+ prettyPrintJson(res);
+ }
+ else
+ {
+ res.jsonMode();
+ res.body() = res.jsonValue.dump(2);
+ }
+ }
+
+ if (res.resultInt() >= 400 && res.body().empty())
+ {
+ res.body() = std::string(res.reason());
+ }
+ res.addHeader(boost::beast::http::field::server, serverName);
+ res.addHeader(boost::beast::http::field::date, getCachedDateStr());
+
+ res.keepAlive(req->keepAlive());
+
+ doWrite();
}
- // auto self = this->shared_from_this();
- res.completeRequestHandler = nullptr;
+ private:
+ void doReadHeaders()
+ {
+ // auto self = this->shared_from_this();
+ isReading = true;
+ BMCWEB_LOG_DEBUG << this << " doReadHeaders";
+
+ // Clean up any previous Connection.
+ boost::beast::http::async_read_header(
+ adaptor.socket(), buffer, *parser,
+ [this](const boost::system::error_code& ec,
+ std::size_t bytes_transferred) {
+ isReading = false;
+ BMCWEB_LOG_ERROR << this << " async_read_header "
+ << bytes_transferred << " Bytes";
+ bool errorWhileReading = false;
+ if (ec)
+ {
+ errorWhileReading = true;
+ BMCWEB_LOG_ERROR
+ << this << " Error while reading: " << ec.message();
+ }
+ else
+ {
+ // if the adaptor isn't open anymore, and wasn't handed to a
+ // websocket, treat as an error
+ if (!adaptor.isOpen() && !req->isUpgrade())
+ {
+ errorWhileReading = true;
+ }
+ }
+
+ if (errorWhileReading)
+ {
+ cancelDeadlineTimer();
+ adaptor.close();
+ BMCWEB_LOG_DEBUG << this << " from read(1)";
+ checkDestroy();
+ return;
+ }
+
+ // Compute the url parameters for the request
+ req->url = req->target();
+ std::size_t index = req->url.find("?");
+ if (index != boost::string_view::npos)
+ {
+ req->url = req->url.substr(0, index - 1);
+ }
+ req->urlParams = QueryString(std::string(req->target()));
+ doRead();
+ });
+ }
- if (!adaptor.isOpen()) {
- // BMCWEB_LOG_DEBUG << this << " delete (socket is closed) " << isReading
- // << ' ' << isWriting;
- // delete this;
- return;
+ void doRead()
+ {
+ // auto self = this->shared_from_this();
+ isReading = true;
+ BMCWEB_LOG_DEBUG << this << " doRead";
+
+ boost::beast::http::async_read(
+ adaptor.socket(), buffer, *parser,
+ [this](const boost::system::error_code& ec,
+ std::size_t bytes_transferred) {
+ BMCWEB_LOG_ERROR << this << " async_read " << bytes_transferred
+ << " Bytes";
+ isReading = false;
+
+ bool errorWhileReading = false;
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "Error while reading: " << ec.message();
+ errorWhileReading = true;
+ }
+ else
+ {
+ if (!adaptor.isOpen())
+ {
+ errorWhileReading = true;
+ }
+ }
+ if (errorWhileReading)
+ {
+ cancelDeadlineTimer();
+ adaptor.close();
+ BMCWEB_LOG_DEBUG << this << " from read(1)";
+ checkDestroy();
+ return;
+ }
+ handle();
+ });
}
- if (res.body().empty() && !res.jsonValue.empty()) {
- if (http_helpers::requestPrefersHtml(*req)) {
- prettyPrintJson(res);
- } else {
- res.jsonMode();
- res.body() = res.jsonValue.dump(2);
- }
+
+ void doWrite()
+ {
+ // auto self = this->shared_from_this();
+ isWriting = true;
+ BMCWEB_LOG_DEBUG << "Doing Write";
+ res.preparePayload();
+ serializer.emplace(*res.stringResponse);
+ boost::beast::http::async_write(
+ adaptor.socket(), *serializer,
+ [&](const boost::system::error_code& ec,
+ std::size_t bytes_transferred) {
+ isWriting = false;
+ BMCWEB_LOG_DEBUG << this << " Wrote " << bytes_transferred
+ << " bytes";
+
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG << this << " from write(2)";
+ checkDestroy();
+ return;
+ }
+ if (!req->keepAlive())
+ {
+ adaptor.close();
+ BMCWEB_LOG_DEBUG << this << " from write(1)";
+ checkDestroy();
+ return;
+ }
+
+ serializer.reset();
+ BMCWEB_LOG_DEBUG << this << " Clearing response";
+ res.clear();
+ parser.emplace(std::piecewise_construct, std::make_tuple());
+ parser->body_limit(httpReqBodyLimit); // reset body limit for
+ // newly created parser
+ buffer.consume(buffer.size());
+
+ req.emplace(parser->get());
+ doReadHeaders();
+ });
}
- if (res.resultInt() >= 400 && res.body().empty()) {
- res.body() = std::string(res.reason());
+ void checkDestroy()
+ {
+ BMCWEB_LOG_DEBUG << this << " isReading " << isReading << " isWriting "
+ << isWriting;
+ if (!isReading && !isWriting)
+ {
+ BMCWEB_LOG_DEBUG << this << " delete (idle) ";
+ delete this;
+ }
}
- res.addHeader(boost::beast::http::field::server, serverName);
- res.addHeader(boost::beast::http::field::date, getCachedDateStr());
-
- res.keepAlive(req->keepAlive());
-
- doWrite();
- }
-
- private:
- void doReadHeaders() {
- // auto self = this->shared_from_this();
- isReading = true;
- BMCWEB_LOG_DEBUG << this << " doReadHeaders";
-
- // Clean up any previous Connection.
- boost::beast::http::async_read_header(
- adaptor.socket(), buffer, *parser,
- [this](const boost::system::error_code& ec,
- std::size_t bytes_transferred) {
- isReading = false;
- BMCWEB_LOG_ERROR << this << " async_read_header " << bytes_transferred
- << " Bytes";
- bool errorWhileReading = false;
- if (ec) {
- errorWhileReading = true;
- BMCWEB_LOG_ERROR << this
- << " Error while reading: " << ec.message();
- } else {
- // if the adaptor isn't open anymore, and wasn't handed to a
- // websocket, treat as an error
- if (!adaptor.isOpen() && !req->isUpgrade()) {
- errorWhileReading = true;
- }
- }
- if (errorWhileReading) {
- cancelDeadlineTimer();
- adaptor.close();
- BMCWEB_LOG_DEBUG << this << " from read(1)";
- checkDestroy();
- return;
- }
-
- // Compute the url parameters for the request
- req->url = req->target();
- std::size_t index = req->url.find("?");
- if (index != boost::string_view::npos) {
- req->url = req->url.substr(0, index - 1);
- }
- req->urlParams = QueryString(std::string(req->target()));
- doRead();
- });
- }
-
- void doRead() {
- // auto self = this->shared_from_this();
- isReading = true;
- BMCWEB_LOG_DEBUG << this << " doRead";
-
- boost::beast::http::async_read(
- adaptor.socket(), buffer, *parser,
- [this](const boost::system::error_code& ec,
- std::size_t bytes_transferred) {
- BMCWEB_LOG_ERROR << this << " async_read " << bytes_transferred
- << " Bytes";
- isReading = false;
-
- bool errorWhileReading = false;
- if (ec) {
- BMCWEB_LOG_ERROR << "Error while reading: " << ec.message();
- errorWhileReading = true;
- } else {
- if (!adaptor.isOpen()) {
- errorWhileReading = true;
+ void cancelDeadlineTimer()
+ {
+ BMCWEB_LOG_DEBUG << this << " timer cancelled: " << &timerQueue << ' '
+ << timerCancelKey;
+ timerQueue.cancel(timerCancelKey);
+ }
+
+ void startDeadline()
+ {
+ cancelDeadlineTimer();
+
+ timerCancelKey = timerQueue.add([this] {
+ if (!adaptor.isOpen())
+ {
+ return;
}
- }
- if (errorWhileReading) {
- cancelDeadlineTimer();
adaptor.close();
- BMCWEB_LOG_DEBUG << this << " from read(1)";
- checkDestroy();
- return;
- }
- handle();
- });
- }
-
- void doWrite() {
- // auto self = this->shared_from_this();
- isWriting = true;
- BMCWEB_LOG_DEBUG << "Doing Write";
- res.preparePayload();
- serializer.emplace(*res.stringResponse);
- boost::beast::http::async_write(
- adaptor.socket(), *serializer,
- [&](const boost::system::error_code& ec,
- std::size_t bytes_transferred) {
- isWriting = false;
- BMCWEB_LOG_DEBUG << this << " Wrote " << bytes_transferred
- << " bytes";
-
- if (ec) {
- BMCWEB_LOG_DEBUG << this << " from write(2)";
- checkDestroy();
- return;
- }
- if (!req->keepAlive()) {
- adaptor.close();
- BMCWEB_LOG_DEBUG << this << " from write(1)";
- checkDestroy();
- return;
- }
-
- serializer.reset();
- BMCWEB_LOG_DEBUG << this << " Clearing response";
- res.clear();
- parser.emplace(std::piecewise_construct, std::make_tuple());
- parser->body_limit(httpReqBodyLimit); // reset body limit for
- // newly created parser
- buffer.consume(buffer.size());
-
- req.emplace(parser->get());
- doReadHeaders();
});
- }
-
- void checkDestroy() {
- BMCWEB_LOG_DEBUG << this << " isReading " << isReading << " isWriting "
- << isWriting;
- if (!isReading && !isWriting) {
- BMCWEB_LOG_DEBUG << this << " delete (idle) ";
- delete this;
+ BMCWEB_LOG_DEBUG << this << " timer added: " << &timerQueue << ' '
+ << timerCancelKey;
}
- }
-
- void cancelDeadlineTimer() {
- BMCWEB_LOG_DEBUG << this << " timer cancelled: " << &timerQueue << ' '
- << timerCancelKey;
- timerQueue.cancel(timerCancelKey);
- }
-
- void startDeadline() {
- cancelDeadlineTimer();
-
- timerCancelKey = timerQueue.add([this] {
- if (!adaptor.isOpen()) {
- return;
- }
- adaptor.close();
- });
- BMCWEB_LOG_DEBUG << this << " timer added: " << &timerQueue << ' '
- << timerCancelKey;
- }
-
- private:
- Adaptor adaptor;
- Handler* handler;
-
- // Making this a boost::optional allows it to be efficiently destroyed and
- // re-created on Connection reset
- boost::optional<
- boost::beast::http::request_parser<boost::beast::http::string_body>>
- parser;
-
- boost::beast::flat_buffer buffer{8192};
-
- boost::optional<
- boost::beast::http::response_serializer<boost::beast::http::string_body>>
- serializer;
-
- boost::optional<crow::Request> req;
- crow::Response res;
-
- const std::string& serverName;
-
- int timerCancelKey{-1};
-
- bool isReading{};
- bool isWriting{};
- bool needToCallAfterHandlers{};
- bool needToStartReadAfterComplete{};
- bool addKeepAlive{};
-
- std::tuple<Middlewares...>* middlewares;
- detail::Context<Middlewares...> ctx;
-
- std::function<std::string()>& getCachedDateStr;
- detail::TimerQueue& timerQueue;
-}; // namespace crow
-} // namespace crow
+
+ private:
+ Adaptor adaptor;
+ Handler* handler;
+
+ // Making this a boost::optional allows it to be efficiently destroyed and
+ // re-created on Connection reset
+ boost::optional<
+ boost::beast::http::request_parser<boost::beast::http::string_body>>
+ parser;
+
+ boost::beast::flat_buffer buffer{8192};
+
+ boost::optional<boost::beast::http::response_serializer<
+ boost::beast::http::string_body>>
+ serializer;
+
+ boost::optional<crow::Request> req;
+ crow::Response res;
+
+ const std::string& serverName;
+
+ int timerCancelKey{-1};
+
+ bool isReading{};
+ bool isWriting{};
+ bool needToCallAfterHandlers{};
+ bool needToStartReadAfterComplete{};
+ bool addKeepAlive{};
+
+ std::tuple<Middlewares...>* middlewares;
+ detail::Context<Middlewares...> ctx;
+
+ std::function<std::string()>& getCachedDateStr;
+ detail::TimerQueue& timerQueue;
+}; // namespace crow
+} // namespace crow
diff --git a/crow/include/crow/http_request.h b/crow/include/crow/http_request.h
index 7e95bc6669..0e6dd12932 100644
--- a/crow/include/crow/http_request.h
+++ b/crow/include/crow/http_request.h
@@ -7,42 +7,66 @@
#include "crow/common.h"
#include "crow/query_string.h"
-namespace crow {
-
-struct Request {
- boost::string_view url{};
- QueryString urlParams{};
- bool isSecure{false};
-
- const std::string& body;
-
- void* middlewareContext{};
- boost::asio::io_service* ioService{};
-
- Request(boost::beast::http::request<boost::beast::http::string_body>& req)
- : req(req), body(req.body()) {}
-
- const boost::beast::http::verb method() const { return req.method(); }
-
- const boost::string_view getHeaderValue(boost::string_view key) const {
- return req[key];
- }
-
- const boost::string_view getHeaderValue(boost::beast::http::field key) const {
- return req[key];
- }
-
- const boost::string_view methodString() const { return req.method_string(); }
-
- const boost::string_view target() const { return req.target(); }
-
- unsigned version() { return req.version(); }
-
- bool isUpgrade() { return boost::beast::websocket::is_upgrade(req); }
-
- bool keepAlive() { return req.keep_alive(); }
-
- boost::beast::http::request<boost::beast::http::string_body>& req;
+namespace crow
+{
+
+struct Request
+{
+ boost::string_view url{};
+ QueryString urlParams{};
+ bool isSecure{false};
+
+ const std::string& body;
+
+ void* middlewareContext{};
+ boost::asio::io_service* ioService{};
+
+ Request(boost::beast::http::request<boost::beast::http::string_body>& req) :
+ req(req), body(req.body())
+ {
+ }
+
+ const boost::beast::http::verb method() const
+ {
+ return req.method();
+ }
+
+ const boost::string_view getHeaderValue(boost::string_view key) const
+ {
+ return req[key];
+ }
+
+ const boost::string_view getHeaderValue(boost::beast::http::field key) const
+ {
+ return req[key];
+ }
+
+ const boost::string_view methodString() const
+ {
+ return req.method_string();
+ }
+
+ const boost::string_view target() const
+ {
+ return req.target();
+ }
+
+ unsigned version()
+ {
+ return req.version();
+ }
+
+ bool isUpgrade()
+ {
+ return boost::beast::websocket::is_upgrade(req);
+ }
+
+ bool keepAlive()
+ {
+ return req.keep_alive();
+ }
+
+ boost::beast::http::request<boost::beast::http::string_body>& req;
};
-} // namespace crow
+} // namespace crow
diff --git a/crow/include/crow/http_response.h b/crow/include/crow/http_response.h
index 560eef46e8..d66bf47046 100644
--- a/crow/include/crow/http_response.h
+++ b/crow/include/crow/http_response.h
@@ -1,121 +1,173 @@
#pragma once
+#include "nlohmann/json.hpp"
+
+#include <boost/beast/http.hpp>
#include <string>
-#include "nlohmann/json.hpp"
#include "crow/http_request.h"
#include "crow/logging.h"
-#include <boost/beast/http.hpp>
-namespace crow {
+namespace crow
+{
template <typename Adaptor, typename Handler, typename... Middlewares>
class Connection;
-struct Response {
- template <typename Adaptor, typename Handler, typename... Middlewares>
- friend class crow::Connection;
- using response_type =
- boost::beast::http::response<boost::beast::http::string_body>;
-
- boost::optional<response_type> stringResponse;
-
- nlohmann::json jsonValue;
+struct Response
+{
+ template <typename Adaptor, typename Handler, typename... Middlewares>
+ friend class crow::Connection;
+ using response_type =
+ boost::beast::http::response<boost::beast::http::string_body>;
- void addHeader(const boost::string_view key, const boost::string_view value) {
- stringResponse->set(key, value);
- }
+ boost::optional<response_type> stringResponse;
- void addHeader(boost::beast::http::field key, boost::string_view value) {
- stringResponse->set(key, value);
- }
+ nlohmann::json jsonValue;
- Response() : stringResponse(response_type{}) {}
+ void addHeader(const boost::string_view key, const boost::string_view value)
+ {
+ stringResponse->set(key, value);
+ }
- explicit Response(boost::beast::http::status code)
- : stringResponse(response_type{}) {}
+ void addHeader(boost::beast::http::field key, boost::string_view value)
+ {
+ stringResponse->set(key, value);
+ }
- explicit Response(boost::string_view body_)
- : stringResponse(response_type{}) {
- stringResponse->body() = std::string(body_);
- }
+ Response() : stringResponse(response_type{})
+ {
+ }
- Response(boost::beast::http::status code, boost::string_view s)
- : stringResponse(response_type{}) {
- stringResponse->result(code);
- stringResponse->body() = std::string(s);
- }
+ explicit Response(boost::beast::http::status code) :
+ stringResponse(response_type{})
+ {
+ }
- Response(Response&& r) {
- BMCWEB_LOG_DEBUG << "Moving response containers";
- *this = std::move(r);
- }
+ explicit Response(boost::string_view body_) :
+ stringResponse(response_type{})
+ {
+ stringResponse->body() = std::string(body_);
+ }
- ~Response() { BMCWEB_LOG_DEBUG << this << " Destroying response"; }
+ Response(boost::beast::http::status code, boost::string_view s) :
+ stringResponse(response_type{})
+ {
+ stringResponse->result(code);
+ stringResponse->body() = std::string(s);
+ }
- Response& operator=(const Response& r) = delete;
+ Response(Response&& r)
+ {
+ BMCWEB_LOG_DEBUG << "Moving response containers";
+ *this = std::move(r);
+ }
- Response& operator=(Response&& r) noexcept {
- BMCWEB_LOG_DEBUG << "Moving response containers";
- stringResponse = std::move(r.stringResponse);
- r.stringResponse.emplace(response_type{});
- jsonValue = std::move(r.jsonValue);
- completed = r.completed;
- return *this;
- }
+ ~Response()
+ {
+ BMCWEB_LOG_DEBUG << this << " Destroying response";
+ }
- void result(boost::beast::http::status v) { stringResponse->result(v); }
+ Response& operator=(const Response& r) = delete;
- boost::beast::http::status result() { return stringResponse->result(); }
+ Response& operator=(Response&& r) noexcept
+ {
+ BMCWEB_LOG_DEBUG << "Moving response containers";
+ stringResponse = std::move(r.stringResponse);
+ r.stringResponse.emplace(response_type{});
+ jsonValue = std::move(r.jsonValue);
+ completed = r.completed;
+ return *this;
+ }
- unsigned resultInt() { return stringResponse->result_int(); }
+ void result(boost::beast::http::status v)
+ {
+ stringResponse->result(v);
+ }
- boost::string_view reason() { return stringResponse->reason(); }
+ boost::beast::http::status result()
+ {
+ return stringResponse->result();
+ }
- bool isCompleted() const noexcept { return completed; }
+ unsigned resultInt()
+ {
+ return stringResponse->result_int();
+ }
- std::string& body() { return stringResponse->body(); }
+ boost::string_view reason()
+ {
+ return stringResponse->reason();
+ }
- void keepAlive(bool k) { stringResponse->keep_alive(k); }
+ bool isCompleted() const noexcept
+ {
+ return completed;
+ }
- void preparePayload() { stringResponse->prepare_payload(); };
+ std::string& body()
+ {
+ return stringResponse->body();
+ }
- void clear() {
- BMCWEB_LOG_DEBUG << this << " Clearing response containers";
- stringResponse.emplace(response_type{});
- jsonValue.clear();
- completed = false;
- }
+ void keepAlive(bool k)
+ {
+ stringResponse->keep_alive(k);
+ }
- void write(boost::string_view body_part) {
- stringResponse->body() += std::string(body_part);
- }
+ void preparePayload()
+ {
+ stringResponse->prepare_payload();
+ };
+
+ void clear()
+ {
+ BMCWEB_LOG_DEBUG << this << " Clearing response containers";
+ stringResponse.emplace(response_type{});
+ jsonValue.clear();
+ completed = false;
+ }
- void end() {
- if (completed) {
- BMCWEB_LOG_ERROR << "Response was ended twice";
- return;
+ void write(boost::string_view body_part)
+ {
+ stringResponse->body() += std::string(body_part);
}
- completed = true;
- BMCWEB_LOG_DEBUG << "calling completion handler";
- if (completeRequestHandler) {
- BMCWEB_LOG_DEBUG << "completion handler was valid";
- completeRequestHandler();
+
+ void end()
+ {
+ if (completed)
+ {
+ BMCWEB_LOG_ERROR << "Response was ended twice";
+ return;
+ }
+ completed = true;
+ BMCWEB_LOG_DEBUG << "calling completion handler";
+ if (completeRequestHandler)
+ {
+ BMCWEB_LOG_DEBUG << "completion handler was valid";
+ completeRequestHandler();
+ }
}
- }
- void end(boost::string_view body_part) {
- write(body_part);
- end();
- }
+ void end(boost::string_view body_part)
+ {
+ write(body_part);
+ end();
+ }
- bool isAlive() { return isAliveHelper && isAliveHelper(); }
+ bool isAlive()
+ {
+ return isAliveHelper && isAliveHelper();
+ }
- private:
- bool completed{};
- std::function<void()> completeRequestHandler;
- std::function<bool()> isAliveHelper;
+ private:
+ bool completed{};
+ std::function<void()> completeRequestHandler;
+ std::function<bool()> isAliveHelper;
- // In case of a JSON object, set the Content-Type header
- void jsonMode() { addHeader("Content-Type", "application/json"); }
+ // In case of a JSON object, set the Content-Type header
+ void jsonMode()
+ {
+ addHeader("Content-Type", "application/json");
+ }
};
-} // namespace crow
+} // namespace crow
diff --git a/crow/include/crow/http_server.h b/crow/include/crow/http_server.h
index 96b85dc264..173d0d1ffb 100644
--- a/crow/include/crow/http_server.h
+++ b/crow/include/crow/http_server.h
@@ -1,183 +1,205 @@
#pragma once
#include <atomic>
+#include <boost/asio.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
#include <chrono>
#include <cstdint>
#include <future>
#include <memory>
#include <utility>
#include <vector>
+
#include "crow/http_connection.h"
#include "crow/logging.h"
#include "crow/timer_queue.h"
-#include <boost/asio.hpp>
-#include <boost/date_time/posix_time/posix_time.hpp>
#ifdef BMCWEB_ENABLE_SSL
#include <boost/asio/ssl.hpp>
#endif
-namespace crow {
+namespace crow
+{
using namespace boost;
using tcp = asio::ip::tcp;
template <typename Handler, typename Adaptor = SocketAdaptor,
typename... Middlewares>
-class Server {
- public:
- Server(Handler* handler, std::unique_ptr<tcp::acceptor>&& acceptor,
- std::tuple<Middlewares...>* middlewares = nullptr,
- typename Adaptor::context* adaptor_ctx = nullptr,
- std::shared_ptr<boost::asio::io_service> io =
- std::make_shared<boost::asio::io_service>())
- : ioService(std::move(io)),
- acceptor(std::move(acceptor)),
- signals(*ioService, SIGINT, SIGTERM),
- tickTimer(*ioService),
- handler(handler),
- middlewares(middlewares),
- adaptorCtx(adaptor_ctx) {}
-
- Server(Handler* handler, const std::string& bindaddr, uint16_t port,
- std::tuple<Middlewares...>* middlewares = nullptr,
- typename Adaptor::context* adaptor_ctx = nullptr,
- std::shared_ptr<boost::asio::io_service> io =
- std::make_shared<boost::asio::io_service>())
- : Server(handler,
+class Server
+{
+ public:
+ Server(Handler* handler, std::unique_ptr<tcp::acceptor>&& acceptor,
+ std::tuple<Middlewares...>* middlewares = nullptr,
+ typename Adaptor::context* adaptor_ctx = nullptr,
+ std::shared_ptr<boost::asio::io_service> io =
+ std::make_shared<boost::asio::io_service>()) :
+ ioService(std::move(io)),
+ acceptor(std::move(acceptor)), signals(*ioService, SIGINT, SIGTERM),
+ tickTimer(*ioService), handler(handler), middlewares(middlewares),
+ adaptorCtx(adaptor_ctx)
+ {
+ }
+
+ Server(Handler* handler, const std::string& bindaddr, uint16_t port,
+ std::tuple<Middlewares...>* middlewares = nullptr,
+ typename Adaptor::context* adaptor_ctx = nullptr,
+ std::shared_ptr<boost::asio::io_service> io =
+ std::make_shared<boost::asio::io_service>()) :
+ Server(handler,
std::make_unique<tcp::acceptor>(
*io,
tcp::endpoint(
boost::asio::ip::address::from_string(bindaddr), port)),
- middlewares, adaptor_ctx, io) {}
-
- Server(Handler* handler, int existing_socket,
- std::tuple<Middlewares...>* middlewares = nullptr,
- typename Adaptor::context* adaptor_ctx = nullptr,
- std::shared_ptr<boost::asio::io_service> io =
- std::make_shared<boost::asio::io_service>())
- : Server(handler,
+ middlewares, adaptor_ctx, io)
+ {
+ }
+
+ Server(Handler* handler, int existing_socket,
+ std::tuple<Middlewares...>* middlewares = nullptr,
+ typename Adaptor::context* adaptor_ctx = nullptr,
+ std::shared_ptr<boost::asio::io_service> io =
+ std::make_shared<boost::asio::io_service>()) :
+ Server(handler,
std::make_unique<tcp::acceptor>(*io, boost::asio::ip::tcp::v6(),
existing_socket),
- middlewares, adaptor_ctx, io) {}
-
- void setTickFunction(std::chrono::milliseconds d, std::function<void()> f) {
- tickInterval = d;
- tickFunction = f;
- }
-
- void onTick() {
- tickFunction();
- tickTimer.expires_from_now(
- boost::posix_time::milliseconds(tickInterval.count()));
- tickTimer.async_wait([this](const boost::system::error_code& ec) {
- if (ec) {
- return;
- }
- onTick();
- });
- }
-
- void updateDateStr() {
- auto lastTimeT = time(0);
- tm myTm{};
+ middlewares, adaptor_ctx, io)
+ {
+ }
+
+ void setTickFunction(std::chrono::milliseconds d, std::function<void()> f)
+ {
+ tickInterval = d;
+ tickFunction = f;
+ }
+
+ void onTick()
+ {
+ tickFunction();
+ tickTimer.expires_from_now(
+ boost::posix_time::milliseconds(tickInterval.count()));
+ tickTimer.async_wait([this](const boost::system::error_code& ec) {
+ if (ec)
+ {
+ return;
+ }
+ onTick();
+ });
+ }
+
+ void updateDateStr()
+ {
+ auto lastTimeT = time(0);
+ tm myTm{};
#ifdef _MSC_VER
- gmtime_s(&my_tm, &last_time_t);
+ gmtime_s(&my_tm, &last_time_t);
#else
- gmtime_r(&lastTimeT, &myTm);
+ gmtime_r(&lastTimeT, &myTm);
#endif
- dateStr.resize(100);
- size_t dateStrSz =
- strftime(&dateStr[0], 99, "%a, %d %b %Y %H:%M:%S GMT", &myTm);
- dateStr.resize(dateStrSz);
- };
-
- void run() {
- updateDateStr();
-
- getCachedDateStr = [this]() -> std::string {
- static std::chrono::time_point<std::chrono::steady_clock> lastDateUpdate =
- std::chrono::steady_clock::now();
- if (std::chrono::steady_clock::now() - lastDateUpdate >=
- std::chrono::seconds(10)) {
- lastDateUpdate = std::chrono::steady_clock::now();
- updateDateStr();
- }
- return this->dateStr;
+ dateStr.resize(100);
+ size_t dateStrSz =
+ strftime(&dateStr[0], 99, "%a, %d %b %Y %H:%M:%S GMT", &myTm);
+ dateStr.resize(dateStrSz);
};
- boost::asio::deadline_timer timer(*ioService);
- timer.expires_from_now(boost::posix_time::seconds(1));
-
- std::function<void(const boost::system::error_code& ec)> handler;
- handler = [&](const boost::system::error_code& ec) {
- if (ec) {
- return;
- }
- timerQueue.process();
- timer.expires_from_now(boost::posix_time::seconds(1));
- timer.async_wait(handler);
- };
- timer.async_wait(handler);
-
- if (tickFunction && tickInterval.count() > 0) {
- tickTimer.expires_from_now(
- boost::posix_time::milliseconds(tickInterval.count()));
- tickTimer.async_wait([this](const boost::system::error_code& ec) {
- if (ec) {
- return;
+ void run()
+ {
+ updateDateStr();
+
+ getCachedDateStr = [this]() -> std::string {
+ static std::chrono::time_point<std::chrono::steady_clock>
+ lastDateUpdate = std::chrono::steady_clock::now();
+ if (std::chrono::steady_clock::now() - lastDateUpdate >=
+ std::chrono::seconds(10))
+ {
+ lastDateUpdate = std::chrono::steady_clock::now();
+ updateDateStr();
+ }
+ return this->dateStr;
+ };
+
+ boost::asio::deadline_timer timer(*ioService);
+ timer.expires_from_now(boost::posix_time::seconds(1));
+
+ std::function<void(const boost::system::error_code& ec)> handler;
+ handler = [&](const boost::system::error_code& ec) {
+ if (ec)
+ {
+ return;
+ }
+ timerQueue.process();
+ timer.expires_from_now(boost::posix_time::seconds(1));
+ timer.async_wait(handler);
+ };
+ timer.async_wait(handler);
+
+ if (tickFunction && tickInterval.count() > 0)
+ {
+ tickTimer.expires_from_now(
+ boost::posix_time::milliseconds(tickInterval.count()));
+ tickTimer.async_wait([this](const boost::system::error_code& ec) {
+ if (ec)
+ {
+ return;
+ }
+ onTick();
+ });
}
- onTick();
- });
- }
- BMCWEB_LOG_INFO << serverName << " server is running, local endpoint "
- << acceptor->local_endpoint();
+ BMCWEB_LOG_INFO << serverName << " server is running, local endpoint "
+ << acceptor->local_endpoint();
- signals.async_wait([&](const boost::system::error_code& /*error*/,
- int /*signal_number*/) { stop(); });
+ signals.async_wait([&](const boost::system::error_code& /*error*/,
+ int /*signal_number*/) { stop(); });
- doAccept();
- }
+ doAccept();
+ }
- void stop() { ioService->stop(); }
+ void stop()
+ {
+ ioService->stop();
+ }
- void doAccept() {
- auto p = new Connection<Adaptor, Handler, Middlewares...>(
- *ioService, handler, serverName, middlewares, getCachedDateStr,
- timerQueue, adaptorCtx);
- acceptor->async_accept(p->socket(),
- [this, p](boost::system::error_code ec) {
- if (!ec) {
- this->ioService->post([p] { p->start(); });
- } else {
- delete p;
- }
- doAccept();
- });
- }
+ void doAccept()
+ {
+ auto p = new Connection<Adaptor, Handler, Middlewares...>(
+ *ioService, handler, serverName, middlewares, getCachedDateStr,
+ timerQueue, adaptorCtx);
+ acceptor->async_accept(
+ p->socket(), [this, p](boost::system::error_code ec) {
+ if (!ec)
+ {
+ this->ioService->post([p] { p->start(); });
+ }
+ else
+ {
+ delete p;
+ }
+ doAccept();
+ });
+ }
- private:
- std::shared_ptr<asio::io_service> ioService;
- detail::TimerQueue timerQueue;
- std::function<std::string()> getCachedDateStr;
- std::unique_ptr<tcp::acceptor> acceptor;
- boost::asio::signal_set signals;
- boost::asio::deadline_timer tickTimer;
+ private:
+ std::shared_ptr<asio::io_service> ioService;
+ detail::TimerQueue timerQueue;
+ std::function<std::string()> getCachedDateStr;
+ std::unique_ptr<tcp::acceptor> acceptor;
+ boost::asio::signal_set signals;
+ boost::asio::deadline_timer tickTimer;
- std::string dateStr;
+ std::string dateStr;
- Handler* handler;
- std::string serverName = "iBMC";
+ Handler* handler;
+ std::string serverName = "iBMC";
- std::chrono::milliseconds tickInterval{};
- std::function<void()> tickFunction;
+ std::chrono::milliseconds tickInterval{};
+ std::function<void()> tickFunction;
- std::tuple<Middlewares...>* middlewares;
+ std::tuple<Middlewares...>* middlewares;
#ifdef BMCWEB_ENABLE_SSL
- bool useSsl{false};
- boost::asio::ssl::context sslContext{boost::asio::ssl::context::sslv23};
+ bool useSsl{false};
+ boost::asio::ssl::context sslContext{boost::asio::ssl::context::sslv23};
#endif
- typename Adaptor::context* adaptorCtx;
-}; // namespace crow
-} // namespace crow
+ typename Adaptor::context* adaptorCtx;
+}; // namespace crow
+} // namespace crow
diff --git a/crow/include/crow/logging.h b/crow/include/crow/logging.h
index 4a68df38ce..353a448c95 100644
--- a/crow/include/crow/logging.h
+++ b/crow/include/crow/logging.h
@@ -7,117 +7,139 @@
#include <sstream>
#include <string>
-namespace crow {
-enum class LogLevel {
+namespace crow
+{
+enum class LogLevel
+{
#ifndef ERROR
- DEBUG = 0,
- INFO,
- WARNING,
- ERROR,
- CRITICAL,
+ DEBUG = 0,
+ INFO,
+ WARNING,
+ ERROR,
+ CRITICAL,
#endif
- Debug = 0,
- Info,
- Warning,
- Error,
- Critical,
+ Debug = 0,
+ Info,
+ Warning,
+ Error,
+ Critical,
};
-class ILogHandler {
- public:
- virtual void log(std::string message, LogLevel level) = 0;
+class ILogHandler
+{
+ public:
+ virtual void log(std::string message, LogLevel level) = 0;
};
-class CerrLogHandler : public ILogHandler {
- public:
- void log(std::string message, LogLevel /*level*/) override {
- std::cerr << message;
- }
+class CerrLogHandler : public ILogHandler
+{
+ public:
+ void log(std::string message, LogLevel /*level*/) override
+ {
+ std::cerr << message;
+ }
};
-class logger {
- private:
- //
- static std::string timestamp() {
- char date[32];
- time_t t = time(0);
+class logger
+{
+ private:
+ //
+ static std::string timestamp()
+ {
+ char date[32];
+ time_t t = time(0);
- tm myTm{};
+ tm myTm{};
#ifdef _MSC_VER
- gmtime_s(&my_tm, &t);
+ gmtime_s(&my_tm, &t);
#else
- gmtime_r(&t, &myTm);
+ gmtime_r(&t, &myTm);
#endif
- size_t sz = strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", &myTm);
- return std::string(date, date + sz);
- }
+ size_t sz = strftime(date, sizeof(date), "%Y-%m-%d %H:%M:%S", &myTm);
+ return std::string(date, date + sz);
+ }
- public:
- logger(const std::string& prefix, LogLevel level) : level(level) {
+ public:
+ logger(const std::string& prefix, LogLevel level) : level(level)
+ {
#ifdef BMCWEB_ENABLE_LOGGING
- stringstream << "(" << timestamp() << ") [" << prefix << "] ";
+ stringstream << "(" << timestamp() << ") [" << prefix << "] ";
#endif
- }
- ~logger() {
-#ifdef BMCWEB_ENABLE_LOGGING
- if (level >= get_current_log_level()) {
- stringstream << std::endl;
- getHandlerRef()->log(stringstream.str(), level);
}
+ ~logger()
+ {
+#ifdef BMCWEB_ENABLE_LOGGING
+ if (level >= get_current_log_level())
+ {
+ stringstream << std::endl;
+ getHandlerRef()->log(stringstream.str(), level);
+ }
#endif
- }
+ }
- //
- template <typename T>
- logger& operator<<(T const& value) {
+ //
+ template <typename T> logger& operator<<(T const& value)
+ {
#ifdef BMCWEB_ENABLE_LOGGING
- if (level >= get_current_log_level()) {
- stringstream << value;
- }
+ if (level >= get_current_log_level())
+ {
+ stringstream << value;
+ }
#endif
- return *this;
- }
-
- //
- static void setLogLevel(LogLevel level) { getLogLevelRef() = level; }
-
- static void setHandler(ILogHandler* handler) { getHandlerRef() = handler; }
-
- static LogLevel get_current_log_level() { return getLogLevelRef(); }
-
- private:
- //
- static LogLevel& getLogLevelRef() {
- static auto currentLevel = static_cast<LogLevel>(1);
- return currentLevel;
- }
- static ILogHandler*& getHandlerRef() {
- static CerrLogHandler defaultHandler;
- static ILogHandler* currentHandler = &defaultHandler;
- return currentHandler;
- }
-
- //
- std::ostringstream stringstream;
- LogLevel level;
+ return *this;
+ }
+
+ //
+ static void setLogLevel(LogLevel level)
+ {
+ getLogLevelRef() = level;
+ }
+
+ static void setHandler(ILogHandler* handler)
+ {
+ getHandlerRef() = handler;
+ }
+
+ static LogLevel get_current_log_level()
+ {
+ return getLogLevelRef();
+ }
+
+ private:
+ //
+ static LogLevel& getLogLevelRef()
+ {
+ static auto currentLevel = static_cast<LogLevel>(1);
+ return currentLevel;
+ }
+ static ILogHandler*& getHandlerRef()
+ {
+ static CerrLogHandler defaultHandler;
+ static ILogHandler* currentHandler = &defaultHandler;
+ return currentHandler;
+ }
+
+ //
+ std::ostringstream stringstream;
+ LogLevel level;
};
-} // namespace crow
-
-#define BMCWEB_LOG_CRITICAL \
- if (crow::logger::get_current_log_level() <= crow::LogLevel::Critical) \
- crow::logger("CRITICAL", crow::LogLevel::Critical)
-#define BMCWEB_LOG_ERROR \
- if (crow::logger::get_current_log_level() <= crow::LogLevel::Error) \
- crow::logger("ERROR ", crow::LogLevel::Error)
-#define BMCWEB_LOG_WARNING \
- if (crow::logger::get_current_log_level() <= crow::LogLevel::Warning) \
- crow::logger("WARNING ", crow::LogLevel::Warning)
-#define BMCWEB_LOG_INFO \
- if (crow::logger::get_current_log_level() <= crow::LogLevel::Info) \
- crow::logger("INFO ", crow::LogLevel::Info)
-#define BMCWEB_LOG_DEBUG \
- if (crow::logger::get_current_log_level() <= crow::LogLevel::Debug) \
- crow::logger("DEBUG ", crow::LogLevel::Debug)
+} // namespace crow
+
+#define BMCWEB_LOG_CRITICAL \
+ if (crow::logger::get_current_log_level() <= crow::LogLevel::Critical) \
+ crow::logger("CRITICAL", crow::LogLevel::Critical)
+#define BMCWEB_LOG_ERROR \
+ if (crow::logger::get_current_log_level() <= crow::LogLevel::Error) \
+ crow::logger("ERROR ", crow::LogLevel::Error)
+#define BMCWEB_LOG_WARNING \
+ if (crow::logger::get_current_log_level() <= crow::LogLevel::Warning) \
+ crow::logger("WARNING ", crow::LogLevel::Warning)
+#define BMCWEB_LOG_INFO \
+ if (crow::logger::get_current_log_level() <= crow::LogLevel::Info) \
+ crow::logger("INFO ", crow::LogLevel::Info)
+#define BMCWEB_LOG_DEBUG \
+ if (crow::logger::get_current_log_level() <= crow::LogLevel::Debug) \
+ crow::logger("DEBUG ", crow::LogLevel::Debug)
diff --git a/crow/include/crow/middleware_context.h b/crow/include/crow/middleware_context.h
index 03309f67c5..f109a44b1f 100644
--- a/crow/include/crow/middleware_context.h
+++ b/crow/include/crow/middleware_context.h
@@ -4,30 +4,32 @@
#include "crow/http_response.h"
#include "crow/utility.h"
-namespace crow {
-namespace detail {
+namespace crow
+{
+namespace detail
+{
template <typename... Middlewares>
struct PartialContext
: public black_magic::PopBack<Middlewares...>::template rebind<
PartialContext>,
- public black_magic::LastElementType<Middlewares...>::type::Context {
- using parent_context = typename black_magic::PopBack<
- Middlewares...>::template rebind<::crow::detail::PartialContext>;
- template <int N>
- using partial = typename std::conditional<
- N == sizeof...(Middlewares) - 1, PartialContext,
- typename parent_context::template partial<N>>::type;
-
- template <typename T>
- typename T::Context& get() {
- return static_cast<typename T::Context&>(*this);
- }
+ public black_magic::LastElementType<Middlewares...>::type::Context
+{
+ using parent_context = typename black_magic::PopBack<
+ Middlewares...>::template rebind<::crow::detail::PartialContext>;
+ template <int N>
+ using partial = typename std::conditional<
+ N == sizeof...(Middlewares) - 1, PartialContext,
+ typename parent_context::template partial<N>>::type;
+
+ template <typename T> typename T::Context& get()
+ {
+ return static_cast<typename T::Context&>(*this);
+ }
};
-template <>
-struct PartialContext<> {
- template <int>
- using partial = PartialContext;
+template <> struct PartialContext<>
+{
+ template <int> using partial = PartialContext;
};
template <int N, typename Context, typename Container, typename CurrentMW,
@@ -39,25 +41,28 @@ template <typename... Middlewares>
struct Context : private PartialContext<Middlewares...>
// struct Context : private Middlewares::context... // simple but less type-safe
{
- template <int N, typename Context, typename Container>
- friend typename std::enable_if<(N == 0)>::type afterHandlersCallHelper(
- Container& middlewares, Context& ctx, Request& req, Response& res);
- template <int N, typename Context, typename Container>
- friend typename std::enable_if<(N > 0)>::type afterHandlersCallHelper(
- Container& middlewares, Context& ctx, Request& req, Response& res);
-
- template <int N, typename Context, typename Container, typename CurrentMW,
- typename... Middlewares2>
- friend bool middlewareCallHelper(Container& middlewares, Request& req,
- Response& res, Context& ctx);
-
- template <typename T>
- typename T::Context& get() {
- return static_cast<typename T::Context&>(*this);
- }
-
- template <int N>
- using partial = typename PartialContext<Middlewares...>::template partial<N>;
+ template <int N, typename Context, typename Container>
+ friend typename std::enable_if<(N == 0)>::type
+ afterHandlersCallHelper(Container& middlewares, Context& ctx,
+ Request& req, Response& res);
+ template <int N, typename Context, typename Container>
+ friend typename std::enable_if<(N > 0)>::type
+ afterHandlersCallHelper(Container& middlewares, Context& ctx,
+ Request& req, Response& res);
+
+ template <int N, typename Context, typename Container, typename CurrentMW,
+ typename... Middlewares2>
+ friend bool middlewareCallHelper(Container& middlewares, Request& req,
+ Response& res, Context& ctx);
+
+ template <typename T> typename T::Context& get()
+ {
+ return static_cast<typename T::Context&>(*this);
+ }
+
+ template <int N>
+ using partial =
+ typename PartialContext<Middlewares...>::template partial<N>;
};
-} // namespace detail
-} // namespace crow
+} // namespace detail
+} // namespace crow
diff --git a/crow/include/crow/query_string.h b/crow/include/crow/query_string.h
index 060699477c..67e426acd7 100644
--- a/crow/include/crow/query_string.h
+++ b/crow/include/crow/query_string.h
@@ -6,7 +6,8 @@
#include <string>
#include <vector>
-namespace crow {
+namespace crow
+{
// ----------------------------------------------------------------------------
// qs_parse (modified)
// https://github.com/bartgrantham/qs_parse
@@ -37,306 +38,376 @@ char* qsScanvalue(const char* key, const char* qs, char* val, size_t val_len);
#undef _qsSORTING
// isxdigit _is_ available in <ctype.h>, but let's avoid another header instead
-#define BMCWEB_QS_ISHEX(x) \
- ((((x) >= '0' && (x) <= '9') || ((x) >= 'A' && (x) <= 'F') || \
- ((x) >= 'a' && (x) <= 'f')) \
- ? 1 \
- : 0)
-#define BMCWEB_QS_HEX2DEC(x) \
- (((x) >= '0' && (x) <= '9') \
- ? (x)-48 \
- : ((x) >= 'A' && (x) <= 'F') ? (x)-55 \
- : ((x) >= 'a' && (x) <= 'f') ? (x)-87 : 0)
-#define BMCWEB_QS_ISQSCHR(x) \
- ((((x) == '=') || ((x) == '#') || ((x) == '&') || ((x) == '\0')) ? 0 : 1)
-
-inline int qsStrncmp(const char* s, const char* qs, size_t n) {
- int i = 0;
- unsigned char u1, u2, unyb, lnyb;
-
- while (n-- > 0) {
- u1 = static_cast<unsigned char>(*s++);
- u2 = static_cast<unsigned char>(*qs++);
-
- if (!BMCWEB_QS_ISQSCHR(u1)) {
- u1 = '\0';
- }
- if (!BMCWEB_QS_ISQSCHR(u2)) {
- u2 = '\0';
+#define BMCWEB_QS_ISHEX(x) \
+ ((((x) >= '0' && (x) <= '9') || ((x) >= 'A' && (x) <= 'F') || \
+ ((x) >= 'a' && (x) <= 'f')) \
+ ? 1 \
+ : 0)
+#define BMCWEB_QS_HEX2DEC(x) \
+ (((x) >= '0' && (x) <= '9') \
+ ? (x)-48 \
+ : ((x) >= 'A' && (x) <= 'F') \
+ ? (x)-55 \
+ : ((x) >= 'a' && (x) <= 'f') ? (x)-87 : 0)
+#define BMCWEB_QS_ISQSCHR(x) \
+ ((((x) == '=') || ((x) == '#') || ((x) == '&') || ((x) == '\0')) ? 0 : 1)
+
+inline int qsStrncmp(const char* s, const char* qs, size_t n)
+{
+ int i = 0;
+ unsigned char u1, u2, unyb, lnyb;
+
+ while (n-- > 0)
+ {
+ u1 = static_cast<unsigned char>(*s++);
+ u2 = static_cast<unsigned char>(*qs++);
+
+ if (!BMCWEB_QS_ISQSCHR(u1))
+ {
+ u1 = '\0';
+ }
+ if (!BMCWEB_QS_ISQSCHR(u2))
+ {
+ u2 = '\0';
+ }
+
+ if (u1 == '+')
+ {
+ u1 = ' ';
+ }
+ if (u1 == '%') // easier/safer than scanf
+ {
+ unyb = static_cast<unsigned char>(*s++);
+ lnyb = static_cast<unsigned char>(*s++);
+ if (BMCWEB_QS_ISHEX(unyb) && BMCWEB_QS_ISHEX(lnyb))
+ {
+ u1 = (BMCWEB_QS_HEX2DEC(unyb) * 16) + BMCWEB_QS_HEX2DEC(lnyb);
+ }
+ else
+ {
+ u1 = '\0';
+ }
+ }
+
+ if (u2 == '+')
+ {
+ u2 = ' ';
+ }
+ if (u2 == '%') // easier/safer than scanf
+ {
+ unyb = static_cast<unsigned char>(*qs++);
+ lnyb = static_cast<unsigned char>(*qs++);
+ if (BMCWEB_QS_ISHEX(unyb) && BMCWEB_QS_ISHEX(lnyb))
+ {
+ u2 = (BMCWEB_QS_HEX2DEC(unyb) * 16) + BMCWEB_QS_HEX2DEC(lnyb);
+ }
+ else
+ {
+ u2 = '\0';
+ }
+ }
+
+ if (u1 != u2)
+ {
+ return u1 - u2;
+ }
+ if (u1 == '\0')
+ {
+ return 0;
+ }
+ i++;
}
-
- if (u1 == '+') {
- u1 = ' ';
+ if (BMCWEB_QS_ISQSCHR(*qs))
+ {
+ return -1;
}
- if (u1 == '%') // easier/safer than scanf
+ else
{
- unyb = static_cast<unsigned char>(*s++);
- lnyb = static_cast<unsigned char>(*s++);
- if (BMCWEB_QS_ISHEX(unyb) && BMCWEB_QS_ISHEX(lnyb)) {
- u1 = (BMCWEB_QS_HEX2DEC(unyb) * 16) + BMCWEB_QS_HEX2DEC(lnyb);
- } else {
- u1 = '\0';
- }
+ return 0;
}
+}
- if (u2 == '+') {
- u2 = ' ';
- }
- if (u2 == '%') // easier/safer than scanf
+inline int qsParse(char* qs, char* qs_kv[], int qs_kv_size)
+{
+ int i, j;
+ char* substrPtr;
+
+ for (i = 0; i < qs_kv_size; i++)
{
- unyb = static_cast<unsigned char>(*qs++);
- lnyb = static_cast<unsigned char>(*qs++);
- if (BMCWEB_QS_ISHEX(unyb) && BMCWEB_QS_ISHEX(lnyb)) {
- u2 = (BMCWEB_QS_HEX2DEC(unyb) * 16) + BMCWEB_QS_HEX2DEC(lnyb);
- } else {
- u2 = '\0';
- }
+ qs_kv[i] = NULL;
}
- if (u1 != u2) {
- return u1 - u2;
+ // find the beginning of the k/v substrings or the fragment
+ substrPtr = qs + strcspn(qs, "?#");
+ if (substrPtr[0] != '\0')
+ {
+ substrPtr++;
}
- if (u1 == '\0') {
- return 0;
+ else
+ {
+ return 0; // no query or fragment
}
- i++;
- }
- if (BMCWEB_QS_ISQSCHR(*qs)) {
- return -1;
- } else {
- return 0;
- }
-}
-inline int qsParse(char* qs, char* qs_kv[], int qs_kv_size) {
- int i, j;
- char* substrPtr;
-
- for (i = 0; i < qs_kv_size; i++) {
- qs_kv[i] = NULL;
- }
-
- // find the beginning of the k/v substrings or the fragment
- substrPtr = qs + strcspn(qs, "?#");
- if (substrPtr[0] != '\0') {
- substrPtr++;
- } else {
- return 0; // no query or fragment
- }
-
- i = 0;
- while (i < qs_kv_size) {
- qs_kv[i] = substrPtr;
- j = strcspn(substrPtr, "&");
- if (substrPtr[j] == '\0') {
- break;
+ i = 0;
+ while (i < qs_kv_size)
+ {
+ qs_kv[i] = substrPtr;
+ j = strcspn(substrPtr, "&");
+ if (substrPtr[j] == '\0')
+ {
+ break;
+ }
+ substrPtr += j + 1;
+ i++;
}
- substrPtr += j + 1;
- i++;
- }
- i++; // x &'s -> means x iterations of this loop -> means *x+1* k/v pairs
-
- // we only decode the values in place, the keys could have '='s in them
- // which will hose our ability to distinguish keys from values later
- for (j = 0; j < i; j++) {
- substrPtr = qs_kv[j] + strcspn(qs_kv[j], "=&#");
- if (substrPtr[0] == '&' ||
- substrPtr[0] == '\0') { // blank value: skip decoding
- substrPtr[0] = '\0';
- } else {
- qsDecode(++substrPtr);
+ i++; // x &'s -> means x iterations of this loop -> means *x+1* k/v pairs
+
+ // we only decode the values in place, the keys could have '='s in them
+ // which will hose our ability to distinguish keys from values later
+ for (j = 0; j < i; j++)
+ {
+ substrPtr = qs_kv[j] + strcspn(qs_kv[j], "=&#");
+ if (substrPtr[0] == '&' || substrPtr[0] == '\0')
+ { // blank value: skip decoding
+ substrPtr[0] = '\0';
+ }
+ else
+ {
+ qsDecode(++substrPtr);
+ }
}
- }
#ifdef _qsSORTING
// TODO: qsort qs_kv, using qs_strncmp() for the comparison
#endif
- return i;
+ return i;
}
-inline int qsDecode(char* qs) {
- int i = 0, j = 0;
+inline int qsDecode(char* qs)
+{
+ int i = 0, j = 0;
- while (BMCWEB_QS_ISQSCHR(qs[j])) {
- if (qs[j] == '+') {
- qs[i] = ' ';
- } else if (qs[j] == '%') // easier/safer than scanf
+ while (BMCWEB_QS_ISQSCHR(qs[j]))
{
- if (!BMCWEB_QS_ISHEX(qs[j + 1]) || !BMCWEB_QS_ISHEX(qs[j + 2])) {
- qs[i] = '\0';
- return i;
- }
- qs[i] =
- (BMCWEB_QS_HEX2DEC(qs[j + 1]) * 16) + BMCWEB_QS_HEX2DEC(qs[j + 2]);
- j += 2;
- } else {
- qs[i] = qs[j];
+ if (qs[j] == '+')
+ {
+ qs[i] = ' ';
+ }
+ else if (qs[j] == '%') // easier/safer than scanf
+ {
+ if (!BMCWEB_QS_ISHEX(qs[j + 1]) || !BMCWEB_QS_ISHEX(qs[j + 2]))
+ {
+ qs[i] = '\0';
+ return i;
+ }
+ qs[i] = (BMCWEB_QS_HEX2DEC(qs[j + 1]) * 16) +
+ BMCWEB_QS_HEX2DEC(qs[j + 2]);
+ j += 2;
+ }
+ else
+ {
+ qs[i] = qs[j];
+ }
+ i++;
+ j++;
}
- i++;
- j++;
- }
- qs[i] = '\0';
+ qs[i] = '\0';
- return i;
+ return i;
}
inline char* qsK2v(const char* key, char* const* qs_kv, int qs_kv_size,
- int nth = 0) {
- int i;
- size_t keyLen, skip;
+ int nth = 0)
+{
+ int i;
+ size_t keyLen, skip;
- keyLen = strlen(key);
+ keyLen = strlen(key);
#ifdef _qsSORTING
// TODO: binary search for key in the sorted qs_kv
-#else // _qsSORTING
- for (i = 0; i < qs_kv_size; i++) {
- // we rely on the unambiguous '=' to find the value in our k/v pair
- if (qsStrncmp(key, qs_kv[i], keyLen) == 0) {
- skip = strcspn(qs_kv[i], "=");
- if (qs_kv[i][skip] == '=') {
- skip++;
- }
- // return (zero-char value) ? ptr to trailing '\0' : ptr to value
- if (nth == 0) {
- return qs_kv[i] + skip;
- } else {
- --nth;
- }
+#else // _qsSORTING
+ for (i = 0; i < qs_kv_size; i++)
+ {
+ // we rely on the unambiguous '=' to find the value in our k/v pair
+ if (qsStrncmp(key, qs_kv[i], keyLen) == 0)
+ {
+ skip = strcspn(qs_kv[i], "=");
+ if (qs_kv[i][skip] == '=')
+ {
+ skip++;
+ }
+ // return (zero-char value) ? ptr to trailing '\0' : ptr to value
+ if (nth == 0)
+ {
+ return qs_kv[i] + skip;
+ }
+ else
+ {
+ --nth;
+ }
+ }
}
- }
-#endif // _qsSORTING
+#endif // _qsSORTING
- return NULL;
+ return NULL;
}
inline char* qsScanvalue(const char* key, const char* qs, char* val,
- size_t val_len) {
- size_t i, keyLen;
- const char* tmp;
-
- // find the beginning of the k/v substrings
- if ((tmp = strchr(qs, '?')) != NULL) {
- qs = tmp + 1;
- }
-
- keyLen = strlen(key);
- while (qs[0] != '#' && qs[0] != '\0') {
- if (qsStrncmp(key, qs, keyLen) == 0) {
- break;
+ size_t val_len)
+{
+ size_t i, keyLen;
+ const char* tmp;
+
+ // find the beginning of the k/v substrings
+ if ((tmp = strchr(qs, '?')) != NULL)
+ {
+ qs = tmp + 1;
}
- qs += strcspn(qs, "&") + 1;
- }
- if (qs[0] == '\0') {
- return NULL;
- }
-
- qs += strcspn(qs, "=&#");
- if (qs[0] == '=') {
- qs++;
- i = strcspn(qs, "&=#");
- strncpy(val, qs, (val_len - 1) < (i + 1) ? (val_len - 1) : (i + 1));
- qsDecode(val);
- } else {
- if (val_len > 0) {
- val[0] = '\0';
+ keyLen = strlen(key);
+ while (qs[0] != '#' && qs[0] != '\0')
+ {
+ if (qsStrncmp(key, qs, keyLen) == 0)
+ {
+ break;
+ }
+ qs += strcspn(qs, "&") + 1;
+ }
+
+ if (qs[0] == '\0')
+ {
+ return NULL;
}
- }
- return val;
+ qs += strcspn(qs, "=&#");
+ if (qs[0] == '=')
+ {
+ qs++;
+ i = strcspn(qs, "&=#");
+ strncpy(val, qs, (val_len - 1) < (i + 1) ? (val_len - 1) : (i + 1));
+ qsDecode(val);
+ }
+ else
+ {
+ if (val_len > 0)
+ {
+ val[0] = '\0';
+ }
+ }
+
+ return val;
}
-} // namespace crow
+} // namespace crow
// ----------------------------------------------------------------------------
-namespace crow {
-class QueryString {
- public:
- static const int maxKeyValuePairsCount = 256;
+namespace crow
+{
+class QueryString
+{
+ public:
+ static const int maxKeyValuePairsCount = 256;
- QueryString() = default;
+ QueryString() = default;
- QueryString(const QueryString& qs) : url(qs.url) {
- for (auto p : qs.keyValuePairs) {
- keyValuePairs.push_back(
- const_cast<char*>(p - qs.url.c_str() + url.c_str()));
- }
- }
-
- QueryString& operator=(const QueryString& qs) {
- url = qs.url;
- keyValuePairs.clear();
- for (auto p : qs.keyValuePairs) {
- keyValuePairs.push_back(
- const_cast<char*>(p - qs.url.c_str() + url.c_str()));
+ QueryString(const QueryString& qs) : url(qs.url)
+ {
+ for (auto p : qs.keyValuePairs)
+ {
+ keyValuePairs.push_back(
+ const_cast<char*>(p - qs.url.c_str() + url.c_str()));
+ }
}
- return *this;
- }
-
- QueryString& operator=(QueryString&& qs) {
- keyValuePairs = std::move(qs.keyValuePairs);
- auto* oldData = const_cast<char*>(qs.url.c_str());
- url = std::move(qs.url);
- for (auto& p : keyValuePairs) {
- p += const_cast<char*>(url.c_str()) - oldData;
+
+ QueryString& operator=(const QueryString& qs)
+ {
+ url = qs.url;
+ keyValuePairs.clear();
+ for (auto p : qs.keyValuePairs)
+ {
+ keyValuePairs.push_back(
+ const_cast<char*>(p - qs.url.c_str() + url.c_str()));
+ }
+ return *this;
}
- return *this;
- }
- explicit QueryString(std::string url) : url(std::move(url)) {
- if (url.empty()) {
- return;
+ QueryString& operator=(QueryString&& qs)
+ {
+ keyValuePairs = std::move(qs.keyValuePairs);
+ auto* oldData = const_cast<char*>(qs.url.c_str());
+ url = std::move(qs.url);
+ for (auto& p : keyValuePairs)
+ {
+ p += const_cast<char*>(url.c_str()) - oldData;
+ }
+ return *this;
}
- keyValuePairs.resize(maxKeyValuePairsCount);
+ explicit QueryString(std::string url) : url(std::move(url))
+ {
+ if (url.empty())
+ {
+ return;
+ }
- int count = qsParse(&url[0], &keyValuePairs[0], maxKeyValuePairsCount);
- keyValuePairs.resize(count);
- }
+ keyValuePairs.resize(maxKeyValuePairsCount);
- void clear() {
- keyValuePairs.clear();
- url.clear();
- }
+ int count = qsParse(&url[0], &keyValuePairs[0], maxKeyValuePairsCount);
+ keyValuePairs.resize(count);
+ }
+
+ void clear()
+ {
+ keyValuePairs.clear();
+ url.clear();
+ }
+
+ friend std::ostream& operator<<(std::ostream& os, const QueryString& qs)
+ {
+ os << "[ ";
+ for (size_t i = 0; i < qs.keyValuePairs.size(); ++i)
+ {
+ if (i != 0u)
+ {
+ os << ", ";
+ }
+ os << qs.keyValuePairs[i];
+ }
+ os << " ]";
+ return os;
+ }
- friend std::ostream& operator<<(std::ostream& os, const QueryString& qs) {
- os << "[ ";
- for (size_t i = 0; i < qs.keyValuePairs.size(); ++i) {
- if (i != 0u) {
- os << ", ";
- }
- os << qs.keyValuePairs[i];
+ char* get(const std::string& name) const
+ {
+ char* ret =
+ qsK2v(name.c_str(), keyValuePairs.data(), keyValuePairs.size());
+ return ret;
}
- os << " ]";
- return os;
- }
-
- char* get(const std::string& name) const {
- char* ret = qsK2v(name.c_str(), keyValuePairs.data(), keyValuePairs.size());
- return ret;
- }
-
- std::vector<char*> getList(const std::string& name) const {
- std::vector<char*> ret;
- std::string plus = name + "[]";
- char* element = nullptr;
-
- int count = 0;
- while (1) {
- element = qsK2v(plus.c_str(), keyValuePairs.data(), keyValuePairs.size(),
- count++);
- if (element == nullptr) {
- break;
- }
- ret.push_back(element);
+
+ std::vector<char*> getList(const std::string& name) const
+ {
+ std::vector<char*> ret;
+ std::string plus = name + "[]";
+ char* element = nullptr;
+
+ int count = 0;
+ while (1)
+ {
+ element = qsK2v(plus.c_str(), keyValuePairs.data(),
+ keyValuePairs.size(), count++);
+ if (element == nullptr)
+ {
+ break;
+ }
+ ret.push_back(element);
+ }
+ return ret;
}
- return ret;
- }
- private:
- std::string url;
- std::vector<char*> keyValuePairs;
+ private:
+ std::string url;
+ std::vector<char*> keyValuePairs;
};
-} // namespace crow
+} // namespace crow
diff --git a/crow/include/crow/routing.h b/crow/include/crow/routing.h
index ddf307aa63..945f3611d8 100644
--- a/crow/include/crow/routing.h
+++ b/crow/include/crow/routing.h
@@ -1,5 +1,8 @@
#pragma once
+#include "boost/container/flat_map.hpp"
+
+#include <boost/lexical_cast.hpp>
#include <cerrno>
#include <cstdint>
#include <cstdlib>
@@ -8,9 +11,6 @@
#include <tuple>
#include <utility>
#include <vector>
-#include <boost/lexical_cast.hpp>
-
-#include "boost/container/flat_map.hpp"
#include "crow/common.h"
#include "crow/http_request.h"
@@ -19,969 +19,1174 @@
#include "crow/utility.h"
#include "crow/websocket.h"
-namespace crow {
-class BaseRule {
- public:
- BaseRule(std::string rule) : rule(std::move(rule)) {}
+namespace crow
+{
+class BaseRule
+{
+ public:
+ BaseRule(std::string rule) : rule(std::move(rule))
+ {
+ }
- virtual ~BaseRule() {}
+ virtual ~BaseRule()
+ {
+ }
- virtual void validate() = 0;
- std::unique_ptr<BaseRule> upgrade() {
- if (ruleToUpgrade) return std::move(ruleToUpgrade);
- return {};
- }
+ virtual void validate() = 0;
+ std::unique_ptr<BaseRule> upgrade()
+ {
+ if (ruleToUpgrade)
+ return std::move(ruleToUpgrade);
+ return {};
+ }
- virtual void handle(const Request&, Response&, const RoutingParams&) = 0;
- virtual void handleUpgrade(const Request&, Response& res, SocketAdaptor&&) {
- res = Response(boost::beast::http::status::not_found);
- res.end();
- }
+ virtual void handle(const Request&, Response&, const RoutingParams&) = 0;
+ virtual void handleUpgrade(const Request&, Response& res, SocketAdaptor&&)
+ {
+ res = Response(boost::beast::http::status::not_found);
+ res.end();
+ }
#ifdef BMCWEB_ENABLE_SSL
- virtual void handleUpgrade(const Request&, Response& res, SSLAdaptor&&) {
- res = Response(boost::beast::http::status::not_found);
- res.end();
- }
+ virtual void handleUpgrade(const Request&, Response& res, SSLAdaptor&&)
+ {
+ res = Response(boost::beast::http::status::not_found);
+ res.end();
+ }
#endif
- uint32_t getMethods() { return methodsBitfield; }
+ uint32_t getMethods()
+ {
+ return methodsBitfield;
+ }
- protected:
- uint32_t methodsBitfield{1 << (int)boost::beast::http::verb::get};
+ protected:
+ uint32_t methodsBitfield{1 << (int)boost::beast::http::verb::get};
- std::string rule;
- std::string nameStr;
+ std::string rule;
+ std::string nameStr;
- std::unique_ptr<BaseRule> ruleToUpgrade;
+ std::unique_ptr<BaseRule> ruleToUpgrade;
- friend class Router;
- template <typename T>
- friend struct RuleParameterTraits;
+ friend class Router;
+ template <typename T> friend struct RuleParameterTraits;
};
-namespace detail {
-namespace routing_handler_call_helper {
-template <typename T, int Pos>
-struct CallPair {
- using type = T;
- static const int pos = Pos;
+namespace detail
+{
+namespace routing_handler_call_helper
+{
+template <typename T, int Pos> struct CallPair
+{
+ using type = T;
+ static const int pos = Pos;
};
-template <typename H1>
-struct CallParams {
- H1& handler;
- const RoutingParams& params;
- const Request& req;
- Response& res;
+template <typename H1> struct CallParams
+{
+ H1& handler;
+ const RoutingParams& params;
+ const Request& req;
+ Response& res;
};
template <typename F, int NInt, int NUint, int NDouble, int NString,
typename S1, typename S2>
-struct Call {};
+struct Call
+{
+};
template <typename F, int NInt, int NUint, int NDouble, int NString,
typename... Args1, typename... Args2>
struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<int64_t, Args1...>,
- black_magic::S<Args2...>> {
- void operator()(F cparams) {
- using pushed = typename black_magic::S<Args2...>::template push_back<
- CallPair<int64_t, NInt>>;
- Call<F, NInt + 1, NUint, NDouble, NString, black_magic::S<Args1...>,
- pushed>()(cparams);
- }
+ black_magic::S<Args2...>>
+{
+ void operator()(F cparams)
+ {
+ using pushed = typename black_magic::S<Args2...>::template push_back<
+ CallPair<int64_t, NInt>>;
+ Call<F, NInt + 1, NUint, NDouble, NString, black_magic::S<Args1...>,
+ pushed>()(cparams);
+ }
};
template <typename F, int NInt, int NUint, int NDouble, int NString,
typename... Args1, typename... Args2>
struct Call<F, NInt, NUint, NDouble, NString,
- black_magic::S<uint64_t, Args1...>, black_magic::S<Args2...>> {
- void operator()(F cparams) {
- using pushed = typename black_magic::S<Args2...>::template push_back<
- CallPair<uint64_t, NUint>>;
- Call<F, NInt, NUint + 1, NDouble, NString, black_magic::S<Args1...>,
- pushed>()(cparams);
- }
+ black_magic::S<uint64_t, Args1...>, black_magic::S<Args2...>>
+{
+ void operator()(F cparams)
+ {
+ using pushed = typename black_magic::S<Args2...>::template push_back<
+ CallPair<uint64_t, NUint>>;
+ Call<F, NInt, NUint + 1, NDouble, NString, black_magic::S<Args1...>,
+ pushed>()(cparams);
+ }
};
template <typename F, int NInt, int NUint, int NDouble, int NString,
typename... Args1, typename... Args2>
struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<double, Args1...>,
- black_magic::S<Args2...>> {
- void operator()(F cparams) {
- using pushed = typename black_magic::S<Args2...>::template push_back<
- CallPair<double, NDouble>>;
- Call<F, NInt, NUint, NDouble + 1, NString, black_magic::S<Args1...>,
- pushed>()(cparams);
- }
+ black_magic::S<Args2...>>
+{
+ void operator()(F cparams)
+ {
+ using pushed = typename black_magic::S<Args2...>::template push_back<
+ CallPair<double, NDouble>>;
+ Call<F, NInt, NUint, NDouble + 1, NString, black_magic::S<Args1...>,
+ pushed>()(cparams);
+ }
};
template <typename F, int NInt, int NUint, int NDouble, int NString,
typename... Args1, typename... Args2>
struct Call<F, NInt, NUint, NDouble, NString,
- black_magic::S<std::string, Args1...>, black_magic::S<Args2...>> {
- void operator()(F cparams) {
- using pushed = typename black_magic::S<Args2...>::template push_back<
- CallPair<std::string, NString>>;
- Call<F, NInt, NUint, NDouble, NString + 1, black_magic::S<Args1...>,
- pushed>()(cparams);
- }
+ black_magic::S<std::string, Args1...>, black_magic::S<Args2...>>
+{
+ void operator()(F cparams)
+ {
+ using pushed = typename black_magic::S<Args2...>::template push_back<
+ CallPair<std::string, NString>>;
+ Call<F, NInt, NUint, NDouble, NString + 1, black_magic::S<Args1...>,
+ pushed>()(cparams);
+ }
};
template <typename F, int NInt, int NUint, int NDouble, int NString,
typename... Args1>
struct Call<F, NInt, NUint, NDouble, NString, black_magic::S<>,
- black_magic::S<Args1...>> {
- void operator()(F cparams) {
- cparams.handler(
- cparams.req, cparams.res,
- cparams.params.template get<typename Args1::type>(Args1::pos)...);
- }
+ black_magic::S<Args1...>>
+{
+ void operator()(F cparams)
+ {
+ cparams.handler(
+ cparams.req, cparams.res,
+ cparams.params.template get<typename Args1::type>(Args1::pos)...);
+ }
};
-template <typename Func, typename... ArgsWrapped>
-struct Wrapped {
- template <typename... Args>
- void set(
- Func f,
- typename std::enable_if<
- !std::is_same<
- typename std::tuple_element<0, std::tuple<Args..., void>>::type,
- const Request&>::value,
- int>::type = 0) {
- handler = (
+template <typename Func, typename... ArgsWrapped> struct Wrapped
+{
+ template <typename... Args>
+ void set(
+ Func f,
+ typename std::enable_if<
+ !std::is_same<
+ typename std::tuple_element<0, std::tuple<Args..., void>>::type,
+ const Request&>::value,
+ int>::type = 0)
+ {
+ handler = (
#ifdef BMCWEB_CAN_USE_CPP14
- [f = std::move(f)]
+ [f = std::move(f)]
#else
- [f]
+ [f]
#endif
- (const Request&, Response& res, Args... args) {
- res = Response(f(args...));
- res.end();
- });
- }
-
- template <typename Req, typename... Args>
- struct ReqHandlerWrapper {
- ReqHandlerWrapper(Func f) : f(std::move(f)) {}
-
- void operator()(const Request& req, Response& res, Args... args) {
- res = Response(f(req, args...));
- res.end();
- }
-
- Func f;
- };
-
- template <typename... Args>
- void set(
- Func f,
- typename std::enable_if<
- std::is_same<
- typename std::tuple_element<0, std::tuple<Args..., void>>::type,
- const Request&>::value &&
- !std::is_same<typename std::tuple_element<
- 1, std::tuple<Args..., void, void>>::type,
- Response&>::value,
- int>::type = 0) {
- handler = ReqHandlerWrapper<Args...>(std::move(f));
- /*handler = (
- [f = std::move(f)]
- (const Request& req, Response& res, Args... args){
- res = Response(f(req, args...));
- res.end();
- });*/
- }
-
- template <typename... Args>
- void set(
- Func f,
- typename std::enable_if<
- std::is_same<
- typename std::tuple_element<0, std::tuple<Args..., void>>::type,
- const Request&>::value &&
- std::is_same<typename std::tuple_element<
- 1, std::tuple<Args..., void, void>>::type,
- Response&>::value,
- int>::type = 0) {
- handler = std::move(f);
- }
-
- template <typename... Args>
- struct HandlerTypeHelper {
- using type =
- std::function<void(const crow::Request&, crow::Response&, Args...)>;
- using args_type = black_magic::S<typename black_magic::promote_t<Args>...>;
- };
-
- template <typename... Args>
- struct HandlerTypeHelper<const Request&, Args...> {
- using type =
- std::function<void(const crow::Request&, crow::Response&, Args...)>;
- using args_type = black_magic::S<typename black_magic::promote_t<Args>...>;
- };
-
- template <typename... Args>
- struct HandlerTypeHelper<const Request&, Response&, Args...> {
- using type =
- std::function<void(const crow::Request&, crow::Response&, Args...)>;
- using args_type = black_magic::S<typename black_magic::promote_t<Args>...>;
- };
-
- typename HandlerTypeHelper<ArgsWrapped...>::type handler;
-
- void operator()(const Request& req, Response& res,
- const RoutingParams& params) {
- detail::routing_handler_call_helper::Call<
- detail::routing_handler_call_helper::CallParams<decltype(handler)>, 0,
- 0, 0, 0, typename HandlerTypeHelper<ArgsWrapped...>::args_type,
- black_magic::S<>>()(
- detail::routing_handler_call_helper::CallParams<decltype(handler)>{
- handler, params, req, res});
- }
+ (const Request&, Response& res, Args... args) {
+ res = Response(f(args...));
+ res.end();
+ });
+ }
+
+ template <typename Req, typename... Args> struct ReqHandlerWrapper
+ {
+ ReqHandlerWrapper(Func f) : f(std::move(f))
+ {
+ }
+
+ void operator()(const Request& req, Response& res, Args... args)
+ {
+ res = Response(f(req, args...));
+ res.end();
+ }
+
+ Func f;
+ };
+
+ template <typename... Args>
+ void set(
+ Func f,
+ typename std::enable_if<
+ std::is_same<
+ typename std::tuple_element<0, std::tuple<Args..., void>>::type,
+ const Request&>::value &&
+ !std::is_same<typename std::tuple_element<
+ 1, std::tuple<Args..., void, void>>::type,
+ Response&>::value,
+ int>::type = 0)
+ {
+ handler = ReqHandlerWrapper<Args...>(std::move(f));
+ /*handler = (
+ [f = std::move(f)]
+ (const Request& req, Response& res, Args... args){
+ res = Response(f(req, args...));
+ res.end();
+ });*/
+ }
+
+ template <typename... Args>
+ void set(
+ Func f,
+ typename std::enable_if<
+ std::is_same<
+ typename std::tuple_element<0, std::tuple<Args..., void>>::type,
+ const Request&>::value &&
+ std::is_same<typename std::tuple_element<
+ 1, std::tuple<Args..., void, void>>::type,
+ Response&>::value,
+ int>::type = 0)
+ {
+ handler = std::move(f);
+ }
+
+ template <typename... Args> struct HandlerTypeHelper
+ {
+ using type =
+ std::function<void(const crow::Request&, crow::Response&, Args...)>;
+ using args_type =
+ black_magic::S<typename black_magic::promote_t<Args>...>;
+ };
+
+ template <typename... Args>
+ struct HandlerTypeHelper<const Request&, Args...>
+ {
+ using type =
+ std::function<void(const crow::Request&, crow::Response&, Args...)>;
+ using args_type =
+ black_magic::S<typename black_magic::promote_t<Args>...>;
+ };
+
+ template <typename... Args>
+ struct HandlerTypeHelper<const Request&, Response&, Args...>
+ {
+ using type =
+ std::function<void(const crow::Request&, crow::Response&, Args...)>;
+ using args_type =
+ black_magic::S<typename black_magic::promote_t<Args>...>;
+ };
+
+ typename HandlerTypeHelper<ArgsWrapped...>::type handler;
+
+ void operator()(const Request& req, Response& res,
+ const RoutingParams& params)
+ {
+ detail::routing_handler_call_helper::Call<
+ detail::routing_handler_call_helper::CallParams<decltype(handler)>,
+ 0, 0, 0, 0, typename HandlerTypeHelper<ArgsWrapped...>::args_type,
+ black_magic::S<>>()(
+ detail::routing_handler_call_helper::CallParams<decltype(handler)>{
+ handler, params, req, res});
+ }
};
-} // namespace routing_handler_call_helper
-} // namespace detail
+} // namespace routing_handler_call_helper
+} // namespace detail
-class WebSocketRule : public BaseRule {
- using self_t = WebSocketRule;
+class WebSocketRule : public BaseRule
+{
+ using self_t = WebSocketRule;
- public:
- WebSocketRule(std::string rule) : BaseRule(std::move(rule)) {}
+ public:
+ WebSocketRule(std::string rule) : BaseRule(std::move(rule))
+ {
+ }
- void validate() override {}
+ void validate() override
+ {
+ }
- void handle(const Request&, Response& res, const RoutingParams&) override {
- res = Response(boost::beast::http::status::not_found);
- res.end();
- }
+ void handle(const Request&, Response& res, const RoutingParams&) override
+ {
+ res = Response(boost::beast::http::status::not_found);
+ res.end();
+ }
- void handleUpgrade(const Request& req, Response&,
- SocketAdaptor&& adaptor) override {
- new crow::websocket::ConnectionImpl<SocketAdaptor>(
- req, std::move(adaptor), openHandler, messageHandler, closeHandler,
- errorHandler);
- }
-#ifdef BMCWEB_ENABLE_SSL
- void handleUpgrade(const Request& req, Response&,
- SSLAdaptor&& adaptor) override {
- std::shared_ptr<crow::websocket::ConnectionImpl<SSLAdaptor>> myConnection =
- std::make_shared<crow::websocket::ConnectionImpl<SSLAdaptor>>(
+ void handleUpgrade(const Request& req, Response&,
+ SocketAdaptor&& adaptor) override
+ {
+ new crow::websocket::ConnectionImpl<SocketAdaptor>(
req, std::move(adaptor), openHandler, messageHandler, closeHandler,
errorHandler);
- myConnection->start();
- }
+ }
+#ifdef BMCWEB_ENABLE_SSL
+ void handleUpgrade(const Request& req, Response&,
+ SSLAdaptor&& adaptor) override
+ {
+ std::shared_ptr<crow::websocket::ConnectionImpl<SSLAdaptor>>
+ myConnection =
+ std::make_shared<crow::websocket::ConnectionImpl<SSLAdaptor>>(
+ req, std::move(adaptor), openHandler, messageHandler,
+ closeHandler, errorHandler);
+ myConnection->start();
+ }
#endif
- template <typename Func>
- self_t& onopen(Func f) {
- openHandler = f;
- return *this;
- }
-
- template <typename Func>
- self_t& onmessage(Func f) {
- messageHandler = f;
- return *this;
- }
-
- template <typename Func>
- self_t& onclose(Func f) {
- closeHandler = f;
- return *this;
- }
-
- template <typename Func>
- self_t& onerror(Func f) {
- errorHandler = f;
- return *this;
- }
-
- protected:
- std::function<void(crow::websocket::Connection&)> openHandler;
- std::function<void(crow::websocket::Connection&, const std::string&, bool)>
- messageHandler;
- std::function<void(crow::websocket::Connection&, const std::string&)>
- closeHandler;
- std::function<void(crow::websocket::Connection&)> errorHandler;
+ template <typename Func> self_t& onopen(Func f)
+ {
+ openHandler = f;
+ return *this;
+ }
+
+ template <typename Func> self_t& onmessage(Func f)
+ {
+ messageHandler = f;
+ return *this;
+ }
+
+ template <typename Func> self_t& onclose(Func f)
+ {
+ closeHandler = f;
+ return *this;
+ }
+
+ template <typename Func> self_t& onerror(Func f)
+ {
+ errorHandler = f;
+ return *this;
+ }
+
+ protected:
+ std::function<void(crow::websocket::Connection&)> openHandler;
+ std::function<void(crow::websocket::Connection&, const std::string&, bool)>
+ messageHandler;
+ std::function<void(crow::websocket::Connection&, const std::string&)>
+ closeHandler;
+ std::function<void(crow::websocket::Connection&)> errorHandler;
};
-template <typename T>
-struct RuleParameterTraits {
- using self_t = T;
- WebSocketRule& websocket() {
- auto p = new WebSocketRule(((self_t*)this)->rule);
- ((self_t*)this)->ruleToUpgrade.reset(p);
- return *p;
- }
-
- self_t& name(std::string name) noexcept {
- ((self_t*)this)->nameStr = std::move(name);
- return (self_t&)*this;
- }
-
- self_t& methods(boost::beast::http::verb method) {
- ((self_t*)this)->methodsBitfield = 1 << (int)method;
- return (self_t&)*this;
- }
-
- template <typename... MethodArgs>
- self_t& methods(boost::beast::http::verb method, MethodArgs... args_method) {
- methods(args_method...);
- ((self_t*)this)->methodsBitfield |= 1 << (int)method;
- return (self_t&)*this;
- }
+template <typename T> struct RuleParameterTraits
+{
+ using self_t = T;
+ WebSocketRule& websocket()
+ {
+ auto p = new WebSocketRule(((self_t*)this)->rule);
+ ((self_t*)this)->ruleToUpgrade.reset(p);
+ return *p;
+ }
+
+ self_t& name(std::string name) noexcept
+ {
+ ((self_t*)this)->nameStr = std::move(name);
+ return (self_t&)*this;
+ }
+
+ self_t& methods(boost::beast::http::verb method)
+ {
+ ((self_t*)this)->methodsBitfield = 1 << (int)method;
+ return (self_t&)*this;
+ }
+
+ template <typename... MethodArgs>
+ self_t& methods(boost::beast::http::verb method, MethodArgs... args_method)
+ {
+ methods(args_method...);
+ ((self_t*)this)->methodsBitfield |= 1 << (int)method;
+ return (self_t&)*this;
+ }
};
-class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule> {
- public:
- DynamicRule(std::string rule) : BaseRule(std::move(rule)) {}
-
- void validate() override {
- if (!erasedHandler) {
- throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
- "no handler for url " + rule);
- }
- }
-
- void handle(const Request& req, Response& res,
- const RoutingParams& params) override {
- erasedHandler(req, res, params);
- }
-
- template <typename Func>
- void operator()(Func f) {
- using function_t = utility::function_traits<Func>;
-
- erasedHandler =
- wrap(std::move(f), black_magic::gen_seq<function_t::arity>());
- }
-
- // enable_if Arg1 == request && Arg2 == Response
- // enable_if Arg1 == request && Arg2 != resposne
- // enable_if Arg1 != request
-
- template <typename Func, unsigned... Indices>
-
- std::function<void(const Request&, Response&, const RoutingParams&)> wrap(
- Func f, black_magic::Seq<Indices...>) {
- using function_t = utility::function_traits<Func>;
-
- if (!black_magic::isParameterTagCompatible(
- black_magic::getParameterTagRuntime(rule.c_str()),
- black_magic::compute_parameter_tag_from_args_list<
- typename function_t::template arg<Indices>...>::value)) {
- throw std::runtime_error(
- "routeDynamic: Handler type is mismatched with URL parameters: " +
- rule);
- }
- auto ret = detail::routing_handler_call_helper::Wrapped<
- Func, typename function_t::template arg<Indices>...>();
- ret.template set<typename function_t::template arg<Indices>...>(
- std::move(f));
- return ret;
- }
-
- template <typename Func>
- void operator()(std::string name, Func&& f) {
- nameStr = std::move(name);
- (*this).template operator()<Func>(std::forward(f));
- }
-
- private:
- std::function<void(const Request&, Response&, const RoutingParams&)>
- erasedHandler;
+class DynamicRule : public BaseRule, public RuleParameterTraits<DynamicRule>
+{
+ public:
+ DynamicRule(std::string rule) : BaseRule(std::move(rule))
+ {
+ }
+
+ void validate() override
+ {
+ if (!erasedHandler)
+ {
+ throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
+ "no handler for url " + rule);
+ }
+ }
+
+ void handle(const Request& req, Response& res,
+ const RoutingParams& params) override
+ {
+ erasedHandler(req, res, params);
+ }
+
+ template <typename Func> void operator()(Func f)
+ {
+ using function_t = utility::function_traits<Func>;
+
+ erasedHandler =
+ wrap(std::move(f), black_magic::gen_seq<function_t::arity>());
+ }
+
+ // enable_if Arg1 == request && Arg2 == Response
+ // enable_if Arg1 == request && Arg2 != resposne
+ // enable_if Arg1 != request
+
+ template <typename Func, unsigned... Indices>
+
+ std::function<void(const Request&, Response&, const RoutingParams&)>
+ wrap(Func f, black_magic::Seq<Indices...>)
+ {
+ using function_t = utility::function_traits<Func>;
+
+ if (!black_magic::isParameterTagCompatible(
+ black_magic::getParameterTagRuntime(rule.c_str()),
+ black_magic::compute_parameter_tag_from_args_list<
+ typename function_t::template arg<Indices>...>::value))
+ {
+ throw std::runtime_error("routeDynamic: Handler type is mismatched "
+ "with URL parameters: " +
+ rule);
+ }
+ auto ret = detail::routing_handler_call_helper::Wrapped<
+ Func, typename function_t::template arg<Indices>...>();
+ ret.template set<typename function_t::template arg<Indices>...>(
+ std::move(f));
+ return ret;
+ }
+
+ template <typename Func> void operator()(std::string name, Func&& f)
+ {
+ nameStr = std::move(name);
+ (*this).template operator()<Func>(std::forward(f));
+ }
+
+ private:
+ std::function<void(const Request&, Response&, const RoutingParams&)>
+ erasedHandler;
};
template <typename... Args>
class TaggedRule : public BaseRule,
- public RuleParameterTraits<TaggedRule<Args...>> {
- public:
- using self_t = TaggedRule<Args...>;
+ public RuleParameterTraits<TaggedRule<Args...>>
+{
+ public:
+ using self_t = TaggedRule<Args...>;
+
+ TaggedRule(std::string rule) : BaseRule(std::move(rule))
+ {
+ }
- TaggedRule(std::string rule) : BaseRule(std::move(rule)) {}
+ void validate() override
+ {
+ if (!handler)
+ {
+ throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
+ "no handler for url " + rule);
+ }
+ }
- void validate() override {
- if (!handler) {
- throw std::runtime_error(nameStr + (!nameStr.empty() ? ": " : "") +
- "no handler for url " + rule);
+ template <typename Func>
+ typename std::enable_if<
+ black_magic::CallHelper<Func, black_magic::S<Args...>>::value,
+ void>::type
+ operator()(Func&& f)
+ {
+ static_assert(
+ black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
+ black_magic::CallHelper<
+ Func, black_magic::S<crow::Request, Args...>>::value,
+ "Handler type is mismatched with URL parameters");
+ static_assert(
+ !std::is_same<void, decltype(f(std::declval<Args>()...))>::value,
+ "Handler function cannot have void return type; valid return "
+ "types: "
+ "string, int, crow::resposne, nlohmann::json");
+
+ handler = [f = std::move(f)](const Request&, Response& res,
+ Args... args) {
+ res = Response(f(args...));
+ res.end();
+ };
}
- }
- template <typename Func>
- typename std::enable_if<
- black_magic::CallHelper<Func, black_magic::S<Args...>>::value, void>::type
- operator()(Func&& f) {
- static_assert(
- black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
+ template <typename Func>
+ typename std::enable_if<
+ !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
black_magic::CallHelper<
Func, black_magic::S<crow::Request, Args...>>::value,
- "Handler type is mismatched with URL parameters");
- static_assert(
- !std::is_same<void, decltype(f(std::declval<Args>()...))>::value,
- "Handler function cannot have void return type; valid return types: "
- "string, int, crow::resposne, nlohmann::json");
-
- handler = [f = std::move(f)](const Request&, Response& res, Args... args) {
- res = Response(f(args...));
- res.end();
- };
- }
-
- template <typename Func>
- typename std::enable_if<
- !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
- black_magic::CallHelper<
- Func, black_magic::S<crow::Request, Args...>>::value,
- void>::type
- operator()(Func&& f) {
- static_assert(
- black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
- black_magic::CallHelper<
+ void>::type
+ operator()(Func&& f)
+ {
+ static_assert(
+ black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
+ black_magic::CallHelper<
+ Func, black_magic::S<crow::Request, Args...>>::value,
+ "Handler type is mismatched with URL parameters");
+ static_assert(
+ !std::is_same<void, decltype(f(std::declval<crow::Request>(),
+ std::declval<Args>()...))>::value,
+ "Handler function cannot have void return type; valid return "
+ "types: "
+ "string, int, crow::resposne,nlohmann::json");
+
+ handler = [f = std::move(f)](const crow::Request& req,
+ crow::Response& res, Args... args) {
+ res = Response(f(req, args...));
+ res.end();
+ };
+ }
+
+ template <typename Func>
+ typename std::enable_if<
+ !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
+ !black_magic::CallHelper<
Func, black_magic::S<crow::Request, Args...>>::value,
- "Handler type is mismatched with URL parameters");
- static_assert(
- !std::is_same<void, decltype(f(std::declval<crow::Request>(),
- std::declval<Args>()...))>::value,
- "Handler function cannot have void return type; valid return types: "
- "string, int, crow::resposne,nlohmann::json");
-
- handler = [f = std::move(f)](const crow::Request& req, crow::Response& res,
- Args... args) {
- res = Response(f(req, args...));
- res.end();
- };
- }
-
- template <typename Func>
- typename std::enable_if<
- !black_magic::CallHelper<Func, black_magic::S<Args...>>::value &&
- !black_magic::CallHelper<
- Func, black_magic::S<crow::Request, Args...>>::value,
- void>::type
- operator()(Func&& f) {
- static_assert(
- black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
- black_magic::CallHelper<
- Func, black_magic::S<crow::Request, Args...>>::value ||
- black_magic::CallHelper<
- Func,
- black_magic::S<crow::Request, crow::Response&, Args...>>::value,
- "Handler type is mismatched with URL parameters");
- static_assert(
- std::is_same<void, decltype(f(std::declval<crow::Request>(),
- std::declval<crow::Response&>(),
- std::declval<Args>()...))>::value,
- "Handler function with response argument should have void return type");
-
- handler = std::move(f);
- }
-
- template <typename Func>
- void operator()(std::string name, Func&& f) {
- nameStr = std::move(name);
- (*this).template operator()<Func>(std::forward(f));
- }
-
- void handle(const Request& req, Response& res,
- const RoutingParams& params) override {
- detail::routing_handler_call_helper::Call<
- detail::routing_handler_call_helper::CallParams<decltype(handler)>, 0,
- 0, 0, 0, black_magic::S<Args...>, black_magic::S<>>()(
- detail::routing_handler_call_helper::CallParams<decltype(handler)>{
- handler, params, req, res});
- }
-
- private:
- std::function<void(const crow::Request&, crow::Response&, Args...)> handler;
+ void>::type
+ operator()(Func&& f)
+ {
+ static_assert(
+ black_magic::CallHelper<Func, black_magic::S<Args...>>::value ||
+ black_magic::CallHelper<
+ Func, black_magic::S<crow::Request, Args...>>::value ||
+ black_magic::CallHelper<
+ Func, black_magic::S<crow::Request, crow::Response&,
+ Args...>>::value,
+ "Handler type is mismatched with URL parameters");
+ static_assert(
+ std::is_same<void, decltype(f(std::declval<crow::Request>(),
+ std::declval<crow::Response&>(),
+ std::declval<Args>()...))>::value,
+ "Handler function with response argument should have void return "
+ "type");
+
+ handler = std::move(f);
+ }
+
+ template <typename Func> void operator()(std::string name, Func&& f)
+ {
+ nameStr = std::move(name);
+ (*this).template operator()<Func>(std::forward(f));
+ }
+
+ void handle(const Request& req, Response& res,
+ const RoutingParams& params) override
+ {
+ detail::routing_handler_call_helper::Call<
+ detail::routing_handler_call_helper::CallParams<decltype(handler)>,
+ 0, 0, 0, 0, black_magic::S<Args...>, black_magic::S<>>()(
+ detail::routing_handler_call_helper::CallParams<decltype(handler)>{
+ handler, params, req, res});
+ }
+
+ private:
+ std::function<void(const crow::Request&, crow::Response&, Args...)> handler;
};
const int ruleSpecialRedirectSlash = 1;
-class Trie {
- public:
- struct Node {
- unsigned ruleIndex{};
- std::array<unsigned, (int)ParamType::MAX> paramChildrens{};
- boost::container::flat_map<std::string, unsigned> children;
-
- bool isSimpleNode() const {
- return !ruleIndex &&
- std::all_of(std::begin(paramChildrens), std::end(paramChildrens),
- [](unsigned x) { return !x; });
- }
- };
-
- Trie() : nodes(1) {}
-
- private:
- void optimizeNode(Node* node) {
- for (auto x : node->paramChildrens) {
- if (!x) continue;
- Node* child = &nodes[x];
- optimizeNode(child);
- }
- if (node->children.empty()) return;
- bool mergeWithChild = true;
- for (auto& kv : node->children) {
- Node* child = &nodes[kv.second];
- if (!child->isSimpleNode()) {
- mergeWithChild = false;
- break;
- }
- }
- if (mergeWithChild) {
- decltype(node->children) merged;
- for (auto& kv : node->children) {
- Node* child = &nodes[kv.second];
- for (auto& childKv : child->children) {
- merged[kv.first + childKv.first] = childKv.second;
- }
- }
- node->children = std::move(merged);
- optimizeNode(node);
- } else {
- for (auto& kv : node->children) {
- Node* child = &nodes[kv.second];
- optimizeNode(child);
- }
- }
- }
-
- void optimize() { optimizeNode(head()); }
-
- public:
- void validate() {
- if (!head()->isSimpleNode())
- throw std::runtime_error("Internal error: Trie header should be simple!");
- optimize();
- }
-
- void findRouteIndexes(const std::string& req_url,
- std::vector<unsigned>& route_indexes,
- const Node* node = nullptr, unsigned pos = 0) {
- if (node == nullptr) {
- node = head();
- }
- for (auto& kv : node->children) {
- const std::string& fragment = kv.first;
- const Node* child = &nodes[kv.second];
- if (pos >= req_url.size()) {
- if (child->ruleIndex != 0 && fragment != "/") {
- route_indexes.push_back(child->ruleIndex);
- }
- findRouteIndexes(req_url, route_indexes, child, pos + fragment.size());
- } else {
- if (req_url.compare(pos, fragment.size(), fragment) == 0) {
- findRouteIndexes(req_url, route_indexes, child,
- pos + fragment.size());
- }
- }
- }
- }
-
- std::pair<unsigned, RoutingParams> find(
- const boost::string_view req_url, const Node* node = nullptr,
- unsigned pos = 0, RoutingParams* params = nullptr) const {
- RoutingParams empty;
- if (params == nullptr) params = &empty;
-
- unsigned found{};
- RoutingParams matchParams;
-
- if (node == nullptr) node = head();
- if (pos == req_url.size()) return {node->ruleIndex, *params};
-
- auto updateFound = [&found,
- &matchParams](std::pair<unsigned, RoutingParams>& ret) {
- if (ret.first && (!found || found > ret.first)) {
- found = ret.first;
- matchParams = std::move(ret.second);
- }
+class Trie
+{
+ public:
+ struct Node
+ {
+ unsigned ruleIndex{};
+ std::array<unsigned, (int)ParamType::MAX> paramChildrens{};
+ boost::container::flat_map<std::string, unsigned> children;
+
+ bool isSimpleNode() const
+ {
+ return !ruleIndex && std::all_of(std::begin(paramChildrens),
+ std::end(paramChildrens),
+ [](unsigned x) { return !x; });
+ }
};
- if (node->paramChildrens[(int)ParamType::INT]) {
- char c = req_url[pos];
- if ((c >= '0' && c <= '9') || c == '+' || c == '-') {
- char* eptr;
- errno = 0;
- long long int value = std::strtoll(req_url.data() + pos, &eptr, 10);
- if (errno != ERANGE && eptr != req_url.data() + pos) {
- params->intParams.push_back(value);
- auto ret =
- find(req_url, &nodes[node->paramChildrens[(int)ParamType::INT]],
- eptr - req_url.data(), params);
- updateFound(ret);
- params->intParams.pop_back();
- }
- }
- }
-
- if (node->paramChildrens[(int)ParamType::UINT]) {
- char c = req_url[pos];
- if ((c >= '0' && c <= '9') || c == '+') {
- char* eptr;
- errno = 0;
- unsigned long long int value =
- std::strtoull(req_url.data() + pos, &eptr, 10);
- if (errno != ERANGE && eptr != req_url.data() + pos) {
- params->uintParams.push_back(value);
- auto ret =
- find(req_url, &nodes[node->paramChildrens[(int)ParamType::UINT]],
- eptr - req_url.data(), params);
- updateFound(ret);
- params->uintParams.pop_back();
- }
- }
- }
-
- if (node->paramChildrens[(int)ParamType::DOUBLE]) {
- char c = req_url[pos];
- if ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.') {
- char* eptr;
- errno = 0;
- double value = std::strtod(req_url.data() + pos, &eptr);
- if (errno != ERANGE && eptr != req_url.data() + pos) {
- params->doubleParams.push_back(value);
- auto ret = find(req_url,
- &nodes[node->paramChildrens[(int)ParamType::DOUBLE]],
- eptr - req_url.data(), params);
- updateFound(ret);
- params->doubleParams.pop_back();
- }
- }
- }
-
- if (node->paramChildrens[(int)ParamType::STRING]) {
- size_t epos = pos;
- for (; epos < req_url.size(); epos++) {
- if (req_url[epos] == '/') break;
- }
-
- if (epos != pos) {
- params->stringParams.emplace_back(req_url.substr(pos, epos - pos));
- auto ret =
- find(req_url, &nodes[node->paramChildrens[(int)ParamType::STRING]],
- epos, params);
- updateFound(ret);
- params->stringParams.pop_back();
- }
- }
-
- if (node->paramChildrens[(int)ParamType::PATH]) {
- size_t epos = req_url.size();
-
- if (epos != pos) {
- params->stringParams.emplace_back(req_url.substr(pos, epos - pos));
- auto ret =
- find(req_url, &nodes[node->paramChildrens[(int)ParamType::PATH]],
- epos, params);
- updateFound(ret);
- params->stringParams.pop_back();
- }
- }
-
- for (auto& kv : node->children) {
- const std::string& fragment = kv.first;
- const Node* child = &nodes[kv.second];
-
- if (req_url.compare(pos, fragment.size(), fragment) == 0) {
- auto ret = find(req_url, child, pos + fragment.size(), params);
- updateFound(ret);
- }
- }
-
- return {found, matchParams};
- }
-
- void add(const std::string& url, unsigned ruleIndex) {
- unsigned idx{0};
-
- for (unsigned i = 0; i < url.size(); i++) {
- char c = url[i];
- if (c == '<') {
- static struct ParamTraits {
- ParamType type;
- std::string name;
- } paramTraits[] = {
- {ParamType::INT, "<int>"}, {ParamType::UINT, "<uint>"},
- {ParamType::DOUBLE, "<float>"}, {ParamType::DOUBLE, "<double>"},
- {ParamType::STRING, "<str>"}, {ParamType::STRING, "<string>"},
- {ParamType::PATH, "<path>"},
- };
+ Trie() : nodes(1)
+ {
+ }
+
+ private:
+ void optimizeNode(Node* node)
+ {
+ for (auto x : node->paramChildrens)
+ {
+ if (!x)
+ continue;
+ Node* child = &nodes[x];
+ optimizeNode(child);
+ }
+ if (node->children.empty())
+ return;
+ bool mergeWithChild = true;
+ for (auto& kv : node->children)
+ {
+ Node* child = &nodes[kv.second];
+ if (!child->isSimpleNode())
+ {
+ mergeWithChild = false;
+ break;
+ }
+ }
+ if (mergeWithChild)
+ {
+ decltype(node->children) merged;
+ for (auto& kv : node->children)
+ {
+ Node* child = &nodes[kv.second];
+ for (auto& childKv : child->children)
+ {
+ merged[kv.first + childKv.first] = childKv.second;
+ }
+ }
+ node->children = std::move(merged);
+ optimizeNode(node);
+ }
+ else
+ {
+ for (auto& kv : node->children)
+ {
+ Node* child = &nodes[kv.second];
+ optimizeNode(child);
+ }
+ }
+ }
- for (auto& x : paramTraits) {
- if (url.compare(i, x.name.size(), x.name) == 0) {
- if (!nodes[idx].paramChildrens[(int)x.type]) {
- auto newNodeIdx = newNode();
- nodes[idx].paramChildrens[(int)x.type] = newNodeIdx;
+ void optimize()
+ {
+ optimizeNode(head());
+ }
+
+ public:
+ void validate()
+ {
+ if (!head()->isSimpleNode())
+ throw std::runtime_error(
+ "Internal error: Trie header should be simple!");
+ optimize();
+ }
+
+ void findRouteIndexes(const std::string& req_url,
+ std::vector<unsigned>& route_indexes,
+ const Node* node = nullptr, unsigned pos = 0)
+ {
+ if (node == nullptr)
+ {
+ node = head();
+ }
+ for (auto& kv : node->children)
+ {
+ const std::string& fragment = kv.first;
+ const Node* child = &nodes[kv.second];
+ if (pos >= req_url.size())
+ {
+ if (child->ruleIndex != 0 && fragment != "/")
+ {
+ route_indexes.push_back(child->ruleIndex);
+ }
+ findRouteIndexes(req_url, route_indexes, child,
+ pos + fragment.size());
+ }
+ else
+ {
+ if (req_url.compare(pos, fragment.size(), fragment) == 0)
+ {
+ findRouteIndexes(req_url, route_indexes, child,
+ pos + fragment.size());
+ }
+ }
+ }
+ }
+
+ std::pair<unsigned, RoutingParams>
+ find(const boost::string_view req_url, const Node* node = nullptr,
+ unsigned pos = 0, RoutingParams* params = nullptr) const
+ {
+ RoutingParams empty;
+ if (params == nullptr)
+ params = &empty;
+
+ unsigned found{};
+ RoutingParams matchParams;
+
+ if (node == nullptr)
+ node = head();
+ if (pos == req_url.size())
+ return {node->ruleIndex, *params};
+
+ auto updateFound =
+ [&found, &matchParams](std::pair<unsigned, RoutingParams>& ret) {
+ if (ret.first && (!found || found > ret.first))
+ {
+ found = ret.first;
+ matchParams = std::move(ret.second);
+ }
+ };
+
+ if (node->paramChildrens[(int)ParamType::INT])
+ {
+ char c = req_url[pos];
+ if ((c >= '0' && c <= '9') || c == '+' || c == '-')
+ {
+ char* eptr;
+ errno = 0;
+ long long int value =
+ std::strtoll(req_url.data() + pos, &eptr, 10);
+ if (errno != ERANGE && eptr != req_url.data() + pos)
+ {
+ params->intParams.push_back(value);
+ auto ret =
+ find(req_url,
+ &nodes[node->paramChildrens[(int)ParamType::INT]],
+ eptr - req_url.data(), params);
+ updateFound(ret);
+ params->intParams.pop_back();
+ }
}
- idx = nodes[idx].paramChildrens[(int)x.type];
- i += x.name.size();
- break;
- }
- }
-
- i--;
- } else {
- std::string piece(&c, 1);
- if (!nodes[idx].children.count(piece)) {
- auto newNodeIdx = newNode();
- nodes[idx].children.emplace(piece, newNodeIdx);
- }
- idx = nodes[idx].children[piece];
- }
- }
- if (nodes[idx].ruleIndex)
- throw std::runtime_error("handler already exists for " + url);
- nodes[idx].ruleIndex = ruleIndex;
- }
-
- private:
- void debugNodePrint(Node* n, int level) {
- for (int i = 0; i < (int)ParamType::MAX; i++) {
- if (n->paramChildrens[i]) {
- BMCWEB_LOG_DEBUG << std::string(
- 2 * level, ' ') /*<< "("<<n->paramChildrens[i]<<") "*/;
- switch ((ParamType)i) {
- case ParamType::INT:
- BMCWEB_LOG_DEBUG << "<int>";
- break;
- case ParamType::UINT:
- BMCWEB_LOG_DEBUG << "<uint>";
- break;
- case ParamType::DOUBLE:
- BMCWEB_LOG_DEBUG << "<float>";
- break;
- case ParamType::STRING:
- BMCWEB_LOG_DEBUG << "<str>";
- break;
- case ParamType::PATH:
- BMCWEB_LOG_DEBUG << "<path>";
- break;
- default:
- BMCWEB_LOG_DEBUG << "<ERROR>";
- break;
- }
-
- debugNodePrint(&nodes[n->paramChildrens[i]], level + 1);
- }
- }
- for (auto& kv : n->children) {
- BMCWEB_LOG_DEBUG << std::string(2 * level,
- ' ') /*<< "(" << kv.second << ") "*/
- << kv.first;
- debugNodePrint(&nodes[kv.second], level + 1);
- }
- }
-
- public:
- void debugPrint() { debugNodePrint(head(), 0); }
-
- private:
- const Node* head() const { return &nodes.front(); }
-
- Node* head() { return &nodes.front(); }
-
- unsigned newNode() {
- nodes.resize(nodes.size() + 1);
- return nodes.size() - 1;
- }
-
- std::vector<Node> nodes;
+ }
+
+ if (node->paramChildrens[(int)ParamType::UINT])
+ {
+ char c = req_url[pos];
+ if ((c >= '0' && c <= '9') || c == '+')
+ {
+ char* eptr;
+ errno = 0;
+ unsigned long long int value =
+ std::strtoull(req_url.data() + pos, &eptr, 10);
+ if (errno != ERANGE && eptr != req_url.data() + pos)
+ {
+ params->uintParams.push_back(value);
+ auto ret =
+ find(req_url,
+ &nodes[node->paramChildrens[(int)ParamType::UINT]],
+ eptr - req_url.data(), params);
+ updateFound(ret);
+ params->uintParams.pop_back();
+ }
+ }
+ }
+
+ if (node->paramChildrens[(int)ParamType::DOUBLE])
+ {
+ char c = req_url[pos];
+ if ((c >= '0' && c <= '9') || c == '+' || c == '-' || c == '.')
+ {
+ char* eptr;
+ errno = 0;
+ double value = std::strtod(req_url.data() + pos, &eptr);
+ if (errno != ERANGE && eptr != req_url.data() + pos)
+ {
+ params->doubleParams.push_back(value);
+ auto ret = find(
+ req_url,
+ &nodes[node->paramChildrens[(int)ParamType::DOUBLE]],
+ eptr - req_url.data(), params);
+ updateFound(ret);
+ params->doubleParams.pop_back();
+ }
+ }
+ }
+
+ if (node->paramChildrens[(int)ParamType::STRING])
+ {
+ size_t epos = pos;
+ for (; epos < req_url.size(); epos++)
+ {
+ if (req_url[epos] == '/')
+ break;
+ }
+
+ if (epos != pos)
+ {
+ params->stringParams.emplace_back(
+ req_url.substr(pos, epos - pos));
+ auto ret =
+ find(req_url,
+ &nodes[node->paramChildrens[(int)ParamType::STRING]],
+ epos, params);
+ updateFound(ret);
+ params->stringParams.pop_back();
+ }
+ }
+
+ if (node->paramChildrens[(int)ParamType::PATH])
+ {
+ size_t epos = req_url.size();
+
+ if (epos != pos)
+ {
+ params->stringParams.emplace_back(
+ req_url.substr(pos, epos - pos));
+ auto ret = find(
+ req_url, &nodes[node->paramChildrens[(int)ParamType::PATH]],
+ epos, params);
+ updateFound(ret);
+ params->stringParams.pop_back();
+ }
+ }
+
+ for (auto& kv : node->children)
+ {
+ const std::string& fragment = kv.first;
+ const Node* child = &nodes[kv.second];
+
+ if (req_url.compare(pos, fragment.size(), fragment) == 0)
+ {
+ auto ret = find(req_url, child, pos + fragment.size(), params);
+ updateFound(ret);
+ }
+ }
+
+ return {found, matchParams};
+ }
+
+ void add(const std::string& url, unsigned ruleIndex)
+ {
+ unsigned idx{0};
+
+ for (unsigned i = 0; i < url.size(); i++)
+ {
+ char c = url[i];
+ if (c == '<')
+ {
+ static struct ParamTraits
+ {
+ ParamType type;
+ std::string name;
+ } paramTraits[] = {
+ {ParamType::INT, "<int>"},
+ {ParamType::UINT, "<uint>"},
+ {ParamType::DOUBLE, "<float>"},
+ {ParamType::DOUBLE, "<double>"},
+ {ParamType::STRING, "<str>"},
+ {ParamType::STRING, "<string>"},
+ {ParamType::PATH, "<path>"},
+ };
+
+ for (auto& x : paramTraits)
+ {
+ if (url.compare(i, x.name.size(), x.name) == 0)
+ {
+ if (!nodes[idx].paramChildrens[(int)x.type])
+ {
+ auto newNodeIdx = newNode();
+ nodes[idx].paramChildrens[(int)x.type] = newNodeIdx;
+ }
+ idx = nodes[idx].paramChildrens[(int)x.type];
+ i += x.name.size();
+ break;
+ }
+ }
+
+ i--;
+ }
+ else
+ {
+ std::string piece(&c, 1);
+ if (!nodes[idx].children.count(piece))
+ {
+ auto newNodeIdx = newNode();
+ nodes[idx].children.emplace(piece, newNodeIdx);
+ }
+ idx = nodes[idx].children[piece];
+ }
+ }
+ if (nodes[idx].ruleIndex)
+ throw std::runtime_error("handler already exists for " + url);
+ nodes[idx].ruleIndex = ruleIndex;
+ }
+
+ private:
+ void debugNodePrint(Node* n, int level)
+ {
+ for (int i = 0; i < (int)ParamType::MAX; i++)
+ {
+ if (n->paramChildrens[i])
+ {
+ BMCWEB_LOG_DEBUG << std::string(
+ 2 * level, ' ') /*<< "("<<n->paramChildrens[i]<<") "*/;
+ switch ((ParamType)i)
+ {
+ case ParamType::INT:
+ BMCWEB_LOG_DEBUG << "<int>";
+ break;
+ case ParamType::UINT:
+ BMCWEB_LOG_DEBUG << "<uint>";
+ break;
+ case ParamType::DOUBLE:
+ BMCWEB_LOG_DEBUG << "<float>";
+ break;
+ case ParamType::STRING:
+ BMCWEB_LOG_DEBUG << "<str>";
+ break;
+ case ParamType::PATH:
+ BMCWEB_LOG_DEBUG << "<path>";
+ break;
+ default:
+ BMCWEB_LOG_DEBUG << "<ERROR>";
+ break;
+ }
+
+ debugNodePrint(&nodes[n->paramChildrens[i]], level + 1);
+ }
+ }
+ for (auto& kv : n->children)
+ {
+ BMCWEB_LOG_DEBUG
+ << std::string(2 * level, ' ') /*<< "(" << kv.second << ") "*/
+ << kv.first;
+ debugNodePrint(&nodes[kv.second], level + 1);
+ }
+ }
+
+ public:
+ void debugPrint()
+ {
+ debugNodePrint(head(), 0);
+ }
+
+ private:
+ const Node* head() const
+ {
+ return &nodes.front();
+ }
+
+ Node* head()
+ {
+ return &nodes.front();
+ }
+
+ unsigned newNode()
+ {
+ nodes.resize(nodes.size() + 1);
+ return nodes.size() - 1;
+ }
+
+ std::vector<Node> nodes;
};
-class Router {
- public:
- Router() : rules(2) {}
-
- DynamicRule& newRuleDynamic(const std::string& rule) {
- std::unique_ptr<DynamicRule> ruleObject =
- std::make_unique<DynamicRule>(rule);
- DynamicRule* ptr = ruleObject.get();
- internalAddRuleObject(rule, std::move(ruleObject));
-
- return *ptr;
- }
-
- template <uint64_t N>
- typename black_magic::Arguments<N>::type::template rebind<TaggedRule>&
- newRuleTagged(const std::string& rule) {
- using RuleT =
- typename black_magic::Arguments<N>::type::template rebind<TaggedRule>;
- std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
- RuleT* ptr = ruleObject.get();
-
- internalAddRuleObject(rule, std::move(ruleObject));
-
- return *ptr;
- }
-
- void internalAddRuleObject(const std::string& rule,
- std::unique_ptr<BaseRule> ruleObject) {
- rules.emplace_back(std::move(ruleObject));
- trie.add(rule, rules.size() - 1);
-
- // directory case:
- // request to `/about' url matches `/about/' rule
- if (rule.size() > 2 && rule.back() == '/') {
- trie.add(rule.substr(0, rule.size() - 1), rules.size() - 1);
- }
- }
-
- void validate() {
- trie.validate();
- for (auto& rule : rules) {
- if (rule) {
- auto upgraded = rule->upgrade();
- if (upgraded) rule = std::move(upgraded);
- rule->validate();
- }
- }
- }
-
- template <typename Adaptor>
- void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor) {
- auto found = trie.find(req.url);
- unsigned ruleIndex = found.first;
- if (!ruleIndex) {
- BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
- res = Response(boost::beast::http::status::not_found);
- res.end();
- return;
- }
-
- if (ruleIndex >= rules.size())
- throw std::runtime_error("Trie internal structure corrupted!");
-
- if (ruleIndex == ruleSpecialRedirectSlash) {
- BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
- << req.url;
- res = Response(boost::beast::http::status::moved_permanently);
-
- // TODO absolute url building
- if (req.getHeaderValue("Host").empty()) {
- res.addHeader("Location", std::string(req.url) + "/");
- } else {
- res.addHeader(
- "Location",
- req.isSecure ? "https://"
- : "http://" + std::string(req.getHeaderValue("Host")) +
- std::string(req.url) + "/");
- }
- res.end();
- return;
- }
-
- if ((rules[ruleIndex]->getMethods() & (1 << (uint32_t)req.method())) == 0) {
- BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
- << " with " << req.methodString() << "("
- << (uint32_t)req.method() << ") / "
- << rules[ruleIndex]->getMethods();
- res = Response(boost::beast::http::status::not_found);
- res.end();
- return;
- }
-
- BMCWEB_LOG_DEBUG << "Matched rule (upgrade) '" << rules[ruleIndex]->rule
- << "' " << (uint32_t)req.method() << " / "
- << rules[ruleIndex]->getMethods();
-
- // any uncaught exceptions become 500s
- try {
- rules[ruleIndex]->handleUpgrade(req, res, std::move(adaptor));
- } catch (std::exception& e) {
- BMCWEB_LOG_ERROR << "An uncaught exception occurred: " << e.what();
- res = Response(boost::beast::http::status::internal_server_error);
- res.end();
- return;
- } catch (...) {
- BMCWEB_LOG_ERROR
- << "An uncaught exception occurred. The type was unknown "
- "so no information was available.";
- res = Response(boost::beast::http::status::internal_server_error);
- res.end();
- return;
- }
- }
-
- void handle(const Request& req, Response& res) {
- auto found = trie.find(req.url);
-
- unsigned ruleIndex = found.first;
-
- if (!ruleIndex) {
- BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
- res.result(boost::beast::http::status::not_found);
- res.end();
- return;
- }
-
- if (ruleIndex >= rules.size())
- throw std::runtime_error("Trie internal structure corrupted!");
-
- if (ruleIndex == ruleSpecialRedirectSlash) {
- BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
- << req.url;
- res = Response(boost::beast::http::status::moved_permanently);
-
- // TODO absolute url building
- if (req.getHeaderValue("Host").empty()) {
- res.addHeader("Location", std::string(req.url) + "/");
- } else {
- res.addHeader("Location", (req.isSecure ? "https://" : "http://") +
- std::string(req.getHeaderValue("Host")) +
- std::string(req.url) + "/");
- }
- res.end();
- return;
- }
-
- if ((rules[ruleIndex]->getMethods() & (1 << (uint32_t)req.method())) == 0) {
- BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
- << " with " << req.methodString() << "("
- << (uint32_t)req.method() << ") / "
- << rules[ruleIndex]->getMethods();
- res = Response(boost::beast::http::status::not_found);
- res.end();
- return;
- }
-
- BMCWEB_LOG_DEBUG << "Matched rule '" << rules[ruleIndex]->rule << "' "
- << (uint32_t)req.method() << " / "
- << rules[ruleIndex]->getMethods();
-
- // any uncaught exceptions become 500s
- try {
- rules[ruleIndex]->handle(req, res, found.second);
- } catch (std::exception& e) {
- BMCWEB_LOG_ERROR << "An uncaught exception occurred: " << e.what();
- res = Response(boost::beast::http::status::internal_server_error);
- res.end();
- return;
- } catch (...) {
- BMCWEB_LOG_ERROR
- << "An uncaught exception occurred. The type was unknown "
- "so no information was available.";
- res = Response(boost::beast::http::status::internal_server_error);
- res.end();
- return;
- }
- }
-
- void debugPrint() { trie.debugPrint(); }
-
- std::vector<const std::string*> getRoutes(const std::string& parent) {
- std::vector<unsigned> x;
- std::vector<const std::string*> ret;
- trie.findRouteIndexes(parent, x);
- for (unsigned index : x) {
- ret.push_back(&rules[index]->rule);
- }
- return ret;
- }
-
- private:
- std::vector<std::unique_ptr<BaseRule>> rules;
- Trie trie;
+class Router
+{
+ public:
+ Router() : rules(2)
+ {
+ }
+
+ DynamicRule& newRuleDynamic(const std::string& rule)
+ {
+ std::unique_ptr<DynamicRule> ruleObject =
+ std::make_unique<DynamicRule>(rule);
+ DynamicRule* ptr = ruleObject.get();
+ internalAddRuleObject(rule, std::move(ruleObject));
+
+ return *ptr;
+ }
+
+ template <uint64_t N>
+ typename black_magic::Arguments<N>::type::template rebind<TaggedRule>&
+ newRuleTagged(const std::string& rule)
+ {
+ using RuleT = typename black_magic::Arguments<N>::type::template rebind<
+ TaggedRule>;
+ std::unique_ptr<RuleT> ruleObject = std::make_unique<RuleT>(rule);
+ RuleT* ptr = ruleObject.get();
+
+ internalAddRuleObject(rule, std::move(ruleObject));
+
+ return *ptr;
+ }
+
+ void internalAddRuleObject(const std::string& rule,
+ std::unique_ptr<BaseRule> ruleObject)
+ {
+ rules.emplace_back(std::move(ruleObject));
+ trie.add(rule, rules.size() - 1);
+
+ // directory case:
+ // request to `/about' url matches `/about/' rule
+ if (rule.size() > 2 && rule.back() == '/')
+ {
+ trie.add(rule.substr(0, rule.size() - 1), rules.size() - 1);
+ }
+ }
+
+ void validate()
+ {
+ trie.validate();
+ for (auto& rule : rules)
+ {
+ if (rule)
+ {
+ auto upgraded = rule->upgrade();
+ if (upgraded)
+ rule = std::move(upgraded);
+ rule->validate();
+ }
+ }
+ }
+
+ template <typename Adaptor>
+ void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor)
+ {
+ auto found = trie.find(req.url);
+ unsigned ruleIndex = found.first;
+ if (!ruleIndex)
+ {
+ BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
+ res = Response(boost::beast::http::status::not_found);
+ res.end();
+ return;
+ }
+
+ if (ruleIndex >= rules.size())
+ throw std::runtime_error("Trie internal structure corrupted!");
+
+ if (ruleIndex == ruleSpecialRedirectSlash)
+ {
+ BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
+ << req.url;
+ res = Response(boost::beast::http::status::moved_permanently);
+
+ // TODO absolute url building
+ if (req.getHeaderValue("Host").empty())
+ {
+ res.addHeader("Location", std::string(req.url) + "/");
+ }
+ else
+ {
+ res.addHeader(
+ "Location",
+ req.isSecure
+ ? "https://"
+ : "http://" + std::string(req.getHeaderValue("Host")) +
+ std::string(req.url) + "/");
+ }
+ res.end();
+ return;
+ }
+
+ if ((rules[ruleIndex]->getMethods() & (1 << (uint32_t)req.method())) ==
+ 0)
+ {
+ BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
+ << " with " << req.methodString() << "("
+ << (uint32_t)req.method() << ") / "
+ << rules[ruleIndex]->getMethods();
+ res = Response(boost::beast::http::status::not_found);
+ res.end();
+ return;
+ }
+
+ BMCWEB_LOG_DEBUG << "Matched rule (upgrade) '" << rules[ruleIndex]->rule
+ << "' " << (uint32_t)req.method() << " / "
+ << rules[ruleIndex]->getMethods();
+
+ // any uncaught exceptions become 500s
+ try
+ {
+ rules[ruleIndex]->handleUpgrade(req, res, std::move(adaptor));
+ }
+ catch (std::exception& e)
+ {
+ BMCWEB_LOG_ERROR << "An uncaught exception occurred: " << e.what();
+ res = Response(boost::beast::http::status::internal_server_error);
+ res.end();
+ return;
+ }
+ catch (...)
+ {
+ BMCWEB_LOG_ERROR
+ << "An uncaught exception occurred. The type was unknown "
+ "so no information was available.";
+ res = Response(boost::beast::http::status::internal_server_error);
+ res.end();
+ return;
+ }
+ }
+
+ void handle(const Request& req, Response& res)
+ {
+ auto found = trie.find(req.url);
+
+ unsigned ruleIndex = found.first;
+
+ if (!ruleIndex)
+ {
+ BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
+ res.result(boost::beast::http::status::not_found);
+ res.end();
+ return;
+ }
+
+ if (ruleIndex >= rules.size())
+ throw std::runtime_error("Trie internal structure corrupted!");
+
+ if (ruleIndex == ruleSpecialRedirectSlash)
+ {
+ BMCWEB_LOG_INFO << "Redirecting to a url with trailing slash: "
+ << req.url;
+ res = Response(boost::beast::http::status::moved_permanently);
+
+ // TODO absolute url building
+ if (req.getHeaderValue("Host").empty())
+ {
+ res.addHeader("Location", std::string(req.url) + "/");
+ }
+ else
+ {
+ res.addHeader("Location",
+ (req.isSecure ? "https://" : "http://") +
+ std::string(req.getHeaderValue("Host")) +
+ std::string(req.url) + "/");
+ }
+ res.end();
+ return;
+ }
+
+ if ((rules[ruleIndex]->getMethods() & (1 << (uint32_t)req.method())) ==
+ 0)
+ {
+ BMCWEB_LOG_DEBUG << "Rule found but method mismatch: " << req.url
+ << " with " << req.methodString() << "("
+ << (uint32_t)req.method() << ") / "
+ << rules[ruleIndex]->getMethods();
+ res = Response(boost::beast::http::status::not_found);
+ res.end();
+ return;
+ }
+
+ BMCWEB_LOG_DEBUG << "Matched rule '" << rules[ruleIndex]->rule << "' "
+ << (uint32_t)req.method() << " / "
+ << rules[ruleIndex]->getMethods();
+
+ // any uncaught exceptions become 500s
+ try
+ {
+ rules[ruleIndex]->handle(req, res, found.second);
+ }
+ catch (std::exception& e)
+ {
+ BMCWEB_LOG_ERROR << "An uncaught exception occurred: " << e.what();
+ res = Response(boost::beast::http::status::internal_server_error);
+ res.end();
+ return;
+ }
+ catch (...)
+ {
+ BMCWEB_LOG_ERROR
+ << "An uncaught exception occurred. The type was unknown "
+ "so no information was available.";
+ res = Response(boost::beast::http::status::internal_server_error);
+ res.end();
+ return;
+ }
+ }
+
+ void debugPrint()
+ {
+ trie.debugPrint();
+ }
+
+ std::vector<const std::string*> getRoutes(const std::string& parent)
+ {
+ std::vector<unsigned> x;
+ std::vector<const std::string*> ret;
+ trie.findRouteIndexes(parent, x);
+ for (unsigned index : x)
+ {
+ ret.push_back(&rules[index]->rule);
+ }
+ return ret;
+ }
+
+ private:
+ std::vector<std::unique_ptr<BaseRule>> rules;
+ Trie trie;
};
-} // namespace crow
+} // namespace crow
diff --git a/crow/include/crow/socket_adaptors.h b/crow/include/crow/socket_adaptors.h
index 1d43ca2faa..a47697f2a5 100644
--- a/crow/include/crow/socket_adaptors.h
+++ b/crow/include/crow/socket_adaptors.h
@@ -1,144 +1,200 @@
#pragma once
-#include "crow/logging.h"
-
#include <boost/asio.hpp>
#include <boost/lexical_cast.hpp>
+#include "crow/logging.h"
+
#ifdef BMCWEB_ENABLE_SSL
#include <boost/asio/ssl.hpp>
#endif
-namespace crow {
+namespace crow
+{
using namespace boost;
using tcp = asio::ip::tcp;
-struct SocketAdaptor {
- using streamType = tcp::socket;
- using secure = std::false_type;
- using context = void;
- SocketAdaptor(boost::asio::io_service& ioService, context* /*unused*/)
- : socketCls(ioService) {}
+struct SocketAdaptor
+{
+ using streamType = tcp::socket;
+ using secure = std::false_type;
+ using context = void;
+ SocketAdaptor(boost::asio::io_service& ioService, context* /*unused*/) :
+ socketCls(ioService)
+ {
+ }
- boost::asio::io_service& getIoService() { return socketCls.get_io_service(); }
+ boost::asio::io_service& getIoService()
+ {
+ return socketCls.get_io_service();
+ }
- tcp::socket& rawSocket() { return socketCls; }
+ tcp::socket& rawSocket()
+ {
+ return socketCls;
+ }
- tcp::socket& socket() { return socketCls; }
+ tcp::socket& socket()
+ {
+ return socketCls;
+ }
- std::string remoteEndpoint() {
- boost::system::error_code ec;
- tcp::endpoint ep = socketCls.remote_endpoint(ec);
- if (ec) {
- return "";
+ std::string remoteEndpoint()
+ {
+ boost::system::error_code ec;
+ tcp::endpoint ep = socketCls.remote_endpoint(ec);
+ if (ec)
+ {
+ return "";
+ }
+ return boost::lexical_cast<std::string>(ep);
}
- return boost::lexical_cast<std::string>(ep);
- }
- bool isOpen() { return socketCls.is_open(); }
+ bool isOpen()
+ {
+ return socketCls.is_open();
+ }
- void close() { socketCls.close(); }
+ void close()
+ {
+ socketCls.close();
+ }
- template <typename F>
- void start(F f) {
- boost::system::error_code ec;
- f(ec);
- }
+ template <typename F> void start(F f)
+ {
+ boost::system::error_code ec;
+ f(ec);
+ }
- tcp::socket socketCls;
+ tcp::socket socketCls;
};
-struct TestSocketAdaptor {
- using secure = std::false_type;
- using context = void;
- TestSocketAdaptor(boost::asio::io_service& ioService, context* /*unused*/)
- : socketCls(ioService) {}
+struct TestSocketAdaptor
+{
+ using secure = std::false_type;
+ using context = void;
+ TestSocketAdaptor(boost::asio::io_service& ioService, context* /*unused*/) :
+ socketCls(ioService)
+ {
+ }
- boost::asio::io_service& getIoService() { return socketCls.get_io_service(); }
+ boost::asio::io_service& getIoService()
+ {
+ return socketCls.get_io_service();
+ }
- tcp::socket& rawSocket() { return socketCls; }
+ tcp::socket& rawSocket()
+ {
+ return socketCls;
+ }
- tcp::socket& socket() { return socketCls; }
+ tcp::socket& socket()
+ {
+ return socketCls;
+ }
- std::string remoteEndpoint() { return "Testhost"; }
+ std::string remoteEndpoint()
+ {
+ return "Testhost";
+ }
- bool isOpen() { return socketCls.is_open(); }
+ bool isOpen()
+ {
+ return socketCls.is_open();
+ }
- void close() { socketCls.close(); }
+ void close()
+ {
+ socketCls.close();
+ }
- template <typename F>
- void start(F f) {
- f(boost::system::error_code());
- }
+ template <typename F> void start(F f)
+ {
+ f(boost::system::error_code());
+ }
- tcp::socket socketCls;
+ tcp::socket socketCls;
};
#ifdef BMCWEB_ENABLE_SSL
-struct SSLAdaptor {
- using streamType = boost::asio::ssl::stream<tcp::socket>;
- using secure = std::true_type;
- using context = boost::asio::ssl::context;
- using ssl_socket_t = boost::asio::ssl::stream<tcp::socket>;
- SSLAdaptor(boost::asio::io_service& ioService, context* ctx)
- : sslSocket(new ssl_socket_t(ioService, *ctx)) {}
-
- boost::asio::ssl::stream<tcp::socket>& socket() { return *sslSocket; }
-
- tcp::socket::lowest_layer_type& rawSocket() {
- return sslSocket->lowest_layer();
- }
-
- std::string remoteEndpoint() {
- boost::system::error_code ec;
- tcp::endpoint ep = rawSocket().remote_endpoint(ec);
- if (ec) {
- return "";
- }
- return boost::lexical_cast<std::string>(ep);
- }
-
- bool isOpen() {
- /*TODO(ed) this is a bit of a cheat.
- There are cases when running a websocket where sslSocket might have
- std::move() called on it (to transfer ownership to websocket::Connection)
- and be empty. This (and the check on close()) is a cheat to do something
- sane in this scenario. the correct fix would likely involve changing the
- http parser to return a specific code meaning "has been upgraded" so that
- the doRead function knows not to try to close the Connection which would
- fail, because the adapter is gone. As is, doRead believes the parse
- failed, because isOpen now returns False (which could also mean the client
- disconnected during parse)
- UPdate: The parser does in fact have an "isUpgrade" method that is
- intended for exactly this purpose. Todo is now to make doRead obey the
- flag appropriately so this code can be changed back.
- */
- if (sslSocket != nullptr) {
- return sslSocket->lowest_layer().is_open();
- }
- return false;
- }
-
- void close() {
- if (sslSocket == nullptr) {
- return;
- }
- boost::system::error_code ec;
-
- // Shut it down
- this->sslSocket->lowest_layer().close();
- }
-
- boost::asio::io_service& getIoService() {
- return rawSocket().get_io_service();
- }
-
- template <typename F>
- void start(F f) {
- sslSocket->async_handshake(
- boost::asio::ssl::stream_base::server,
- [f](const boost::system::error_code& ec) { f(ec); });
- }
-
- std::unique_ptr<boost::asio::ssl::stream<tcp::socket>> sslSocket;
+struct SSLAdaptor
+{
+ using streamType = boost::asio::ssl::stream<tcp::socket>;
+ using secure = std::true_type;
+ using context = boost::asio::ssl::context;
+ using ssl_socket_t = boost::asio::ssl::stream<tcp::socket>;
+ SSLAdaptor(boost::asio::io_service& ioService, context* ctx) :
+ sslSocket(new ssl_socket_t(ioService, *ctx))
+ {
+ }
+
+ boost::asio::ssl::stream<tcp::socket>& socket()
+ {
+ return *sslSocket;
+ }
+
+ tcp::socket::lowest_layer_type& rawSocket()
+ {
+ return sslSocket->lowest_layer();
+ }
+
+ std::string remoteEndpoint()
+ {
+ boost::system::error_code ec;
+ tcp::endpoint ep = rawSocket().remote_endpoint(ec);
+ if (ec)
+ {
+ return "";
+ }
+ return boost::lexical_cast<std::string>(ep);
+ }
+
+ bool isOpen()
+ {
+ /*TODO(ed) this is a bit of a cheat.
+ There are cases when running a websocket where sslSocket might have
+ std::move() called on it (to transfer ownership to
+ websocket::Connection) and be empty. This (and the check on close()) is
+ a cheat to do something sane in this scenario. the correct fix would
+ likely involve changing the http parser to return a specific code
+ meaning "has been upgraded" so that the doRead function knows not to try
+ to close the Connection which would fail, because the adapter is gone.
+ As is, doRead believes the parse failed, because isOpen now returns
+ False (which could also mean the client disconnected during parse)
+ UPdate: The parser does in fact have an "isUpgrade" method that is
+ intended for exactly this purpose. Todo is now to make doRead obey the
+ flag appropriately so this code can be changed back.
+ */
+ if (sslSocket != nullptr)
+ {
+ return sslSocket->lowest_layer().is_open();
+ }
+ return false;
+ }
+
+ void close()
+ {
+ if (sslSocket == nullptr)
+ {
+ return;
+ }
+ boost::system::error_code ec;
+
+ // Shut it down
+ this->sslSocket->lowest_layer().close();
+ }
+
+ boost::asio::io_service& getIoService()
+ {
+ return rawSocket().get_io_service();
+ }
+
+ template <typename F> void start(F f)
+ {
+ sslSocket->async_handshake(
+ boost::asio::ssl::stream_base::server,
+ [f](const boost::system::error_code& ec) { f(ec); });
+ }
+
+ std::unique_ptr<boost::asio::ssl::stream<tcp::socket>> sslSocket;
};
#endif
-} // namespace crow
+} // namespace crow
diff --git a/crow/include/crow/timer_queue.h b/crow/include/crow/timer_queue.h
index f5bb467a1f..bf1e084a00 100644
--- a/crow/include/crow/timer_queue.h
+++ b/crow/include/crow/timer_queue.h
@@ -1,63 +1,78 @@
#pragma once
+#include <boost/circular_buffer.hpp>
+#include <boost/circular_buffer/space_optimized.hpp>
#include <chrono>
#include <functional>
+
#include "crow/logging.h"
-#include <boost/circular_buffer.hpp>
-#include <boost/circular_buffer/space_optimized.hpp>
-namespace crow {
-namespace detail {
+namespace crow
+{
+namespace detail
+{
// fast timer queue for fixed tick value.
-class TimerQueue {
- public:
- TimerQueue() { dq.set_capacity(100); }
-
- void cancel(int k) {
- unsigned int index = static_cast<unsigned int>(k - step);
- if (index < dq.size()) {
- dq[index].second = nullptr;
+class TimerQueue
+{
+ public:
+ TimerQueue()
+ {
+ dq.set_capacity(100);
}
- }
-
- int add(std::function<void()> f) {
- dq.push_back(
- std::make_pair(std::chrono::steady_clock::now(), std::move(f)));
- int ret = step + dq.size() - 1;
-
- BMCWEB_LOG_DEBUG << "timer add inside: " << this << ' ' << ret;
- return ret;
- }
-
- void process() {
- auto now = std::chrono::steady_clock::now();
- while (!dq.empty()) {
- auto& x = dq.front();
- if (now - x.first < std::chrono::seconds(5)) {
- break;
- }
- if (x.second) {
- BMCWEB_LOG_DEBUG << "timer call: " << this << ' ' << step;
- // we know that timer handlers are very simple currenty; call here
- x.second();
- }
- dq.pop_front();
- step++;
+
+ void cancel(int k)
+ {
+ unsigned int index = static_cast<unsigned int>(k - step);
+ if (index < dq.size())
+ {
+ dq[index].second = nullptr;
+ }
+ }
+
+ int add(std::function<void()> f)
+ {
+ dq.push_back(
+ std::make_pair(std::chrono::steady_clock::now(), std::move(f)));
+ int ret = step + dq.size() - 1;
+
+ BMCWEB_LOG_DEBUG << "timer add inside: " << this << ' ' << ret;
+ return ret;
+ }
+
+ void process()
+ {
+ auto now = std::chrono::steady_clock::now();
+ while (!dq.empty())
+ {
+ auto& x = dq.front();
+ if (now - x.first < std::chrono::seconds(5))
+ {
+ break;
+ }
+ if (x.second)
+ {
+ BMCWEB_LOG_DEBUG << "timer call: " << this << ' ' << step;
+ // we know that timer handlers are very simple currenty; call
+ // here
+ x.second();
+ }
+ dq.pop_front();
+ step++;
+ }
}
- }
- private:
- using storage_type =
- std::pair<std::chrono::time_point<std::chrono::steady_clock>,
- std::function<void()>>;
+ private:
+ using storage_type =
+ std::pair<std::chrono::time_point<std::chrono::steady_clock>,
+ std::function<void()>>;
- boost::circular_buffer_space_optimized<storage_type,
- std::allocator<storage_type>>
- dq{};
+ boost::circular_buffer_space_optimized<storage_type,
+ std::allocator<storage_type>>
+ dq{};
- // boost::circular_buffer<storage_type> dq{20};
- // std::deque<storage_type> dq{};
- int step{};
+ // boost::circular_buffer<storage_type> dq{20};
+ // std::deque<storage_type> dq{};
+ int step{};
};
-} // namespace detail
-} // namespace crow
+} // namespace detail
+} // namespace crow
diff --git a/crow/include/crow/utility.h b/crow/include/crow/utility.h
index d2557b0af5..9d34e7113b 100644
--- a/crow/include/crow/utility.h
+++ b/crow/include/crow/utility.h
@@ -1,105 +1,136 @@
#pragma once
+#include "nlohmann/json.hpp"
+
+#include <boost/utility/string_view.hpp>
#include <cstdint>
#include <cstring>
#include <functional>
#include <stdexcept>
#include <string>
#include <tuple>
-#include "nlohmann/json.hpp"
-#include <boost/utility/string_view.hpp>
-namespace crow {
-namespace black_magic {
-struct OutOfRange {
- OutOfRange(unsigned /*pos*/, unsigned /*length*/) {}
+namespace crow
+{
+namespace black_magic
+{
+struct OutOfRange
+{
+ OutOfRange(unsigned /*pos*/, unsigned /*length*/)
+ {
+ }
};
-constexpr unsigned requiresInRange(unsigned i, unsigned len) {
- return i >= len ? throw OutOfRange(i, len) : i;
+constexpr unsigned requiresInRange(unsigned i, unsigned len)
+{
+ return i >= len ? throw OutOfRange(i, len) : i;
}
-class ConstStr {
- const char* const beginPtr;
- unsigned sizeUint;
-
- public:
- template <unsigned N>
- constexpr ConstStr(const char (&arr)[N]) : beginPtr(arr), sizeUint(N - 1) {
- static_assert(N >= 1, "not a string literal");
- }
- constexpr char operator[](unsigned i) const {
- return requiresInRange(i, sizeUint), beginPtr[i];
- }
+class ConstStr
+{
+ const char* const beginPtr;
+ unsigned sizeUint;
+
+ public:
+ template <unsigned N>
+ constexpr ConstStr(const char (&arr)[N]) : beginPtr(arr), sizeUint(N - 1)
+ {
+ static_assert(N >= 1, "not a string literal");
+ }
+ constexpr char operator[](unsigned i) const
+ {
+ return requiresInRange(i, sizeUint), beginPtr[i];
+ }
- constexpr operator const char*() const { return beginPtr; }
+ constexpr operator const char*() const
+ {
+ return beginPtr;
+ }
- constexpr const char* begin() const { return beginPtr; }
- constexpr const char* end() const { return beginPtr + sizeUint; }
+ constexpr const char* begin() const
+ {
+ return beginPtr;
+ }
+ constexpr const char* end() const
+ {
+ return beginPtr + sizeUint;
+ }
- constexpr unsigned size() const { return sizeUint; }
+ constexpr unsigned size() const
+ {
+ return sizeUint;
+ }
};
-constexpr unsigned findClosingTag(ConstStr s, unsigned p) {
- return s[p] == '>' ? p : findClosingTag(s, p + 1);
+constexpr unsigned findClosingTag(ConstStr s, unsigned p)
+{
+ return s[p] == '>' ? p : findClosingTag(s, p + 1);
}
-constexpr bool isValid(ConstStr s, unsigned i = 0, int f = 0) {
- return i == s.size()
- ? f == 0
- : f < 0 || f >= 2
- ? false
- : s[i] == '<' ? isValid(s, i + 1, f + 1)
- : s[i] == '>' ? isValid(s, i + 1, f - 1)
- : isValid(s, i + 1, f);
+constexpr bool isValid(ConstStr s, unsigned i = 0, int f = 0)
+{
+ return i == s.size()
+ ? f == 0
+ : f < 0 || f >= 2
+ ? false
+ : s[i] == '<' ? isValid(s, i + 1, f + 1)
+ : s[i] == '>' ? isValid(s, i + 1, f - 1)
+ : isValid(s, i + 1, f);
}
-constexpr bool isEquP(const char* a, const char* b, unsigned n) {
- return *a == 0 && *b == 0 && n == 0
- ? true
- : (*a == 0 || *b == 0)
- ? false
- : n == 0 ? true
- : *a != *b ? false : isEquP(a + 1, b + 1, n - 1);
+constexpr bool isEquP(const char* a, const char* b, unsigned n)
+{
+ return *a == 0 && *b == 0 && n == 0
+ ? true
+ : (*a == 0 || *b == 0)
+ ? false
+ : n == 0 ? true
+ : *a != *b ? false : isEquP(a + 1, b + 1, n - 1);
}
constexpr bool isEquN(ConstStr a, unsigned ai, ConstStr b, unsigned bi,
- unsigned n) {
- return ai + n > a.size() || bi + n > b.size()
- ? false
- : n == 0 ? true
- : a[ai] != b[bi] ? false
- : isEquN(a, ai + 1, b, bi + 1, n - 1);
+ unsigned n)
+{
+ return ai + n > a.size() || bi + n > b.size()
+ ? false
+ : n == 0 ? true
+ : a[ai] != b[bi] ? false
+ : isEquN(a, ai + 1, b, bi + 1, n - 1);
}
-constexpr bool isInt(ConstStr s, unsigned i) {
- return isEquN(s, i, "<int>", 0, 5);
+constexpr bool isInt(ConstStr s, unsigned i)
+{
+ return isEquN(s, i, "<int>", 0, 5);
}
-constexpr bool isUint(ConstStr s, unsigned i) {
- return isEquN(s, i, "<uint>", 0, 6);
+constexpr bool isUint(ConstStr s, unsigned i)
+{
+ return isEquN(s, i, "<uint>", 0, 6);
}
-constexpr bool isFloat(ConstStr s, unsigned i) {
- return isEquN(s, i, "<float>", 0, 7) || isEquN(s, i, "<double>", 0, 8);
+constexpr bool isFloat(ConstStr s, unsigned i)
+{
+ return isEquN(s, i, "<float>", 0, 7) || isEquN(s, i, "<double>", 0, 8);
}
-constexpr bool isStr(ConstStr s, unsigned i) {
- return isEquN(s, i, "<str>", 0, 5) || isEquN(s, i, "<string>", 0, 8);
+constexpr bool isStr(ConstStr s, unsigned i)
+{
+ return isEquN(s, i, "<str>", 0, 5) || isEquN(s, i, "<string>", 0, 8);
}
-constexpr bool isPath(ConstStr s, unsigned i) {
- return isEquN(s, i, "<path>", 0, 6);
+constexpr bool isPath(ConstStr s, unsigned i)
+{
+ return isEquN(s, i, "<path>", 0, 6);
}
-template <typename T>
-struct parameter_tag {
- static const int value = 0;
-};
-#define BMCWEB_INTERNAL_PARAMETER_TAG(t, i) \
- template <> \
- struct parameter_tag<t> { \
- static const int value = i; \
- }
+template <typename T> struct parameter_tag
+{
+ static const int value = 0;
+};
+#define BMCWEB_INTERNAL_PARAMETER_TAG(t, i) \
+ template <> struct parameter_tag<t> \
+ { \
+ static const int value = i; \
+ }
BMCWEB_INTERNAL_PARAMETER_TAG(int, 1);
BMCWEB_INTERNAL_PARAMETER_TAG(char, 1);
BMCWEB_INTERNAL_PARAMETER_TAG(short, 1);
@@ -113,279 +144,290 @@ BMCWEB_INTERNAL_PARAMETER_TAG(unsigned long long, 2);
BMCWEB_INTERNAL_PARAMETER_TAG(double, 3);
BMCWEB_INTERNAL_PARAMETER_TAG(std::string, 4);
#undef BMCWEB_INTERNAL_PARAMETER_TAG
-template <typename... Args>
-struct compute_parameter_tag_from_args_list;
+template <typename... Args> struct compute_parameter_tag_from_args_list;
-template <>
-struct compute_parameter_tag_from_args_list<> {
- static const int value = 0;
+template <> struct compute_parameter_tag_from_args_list<>
+{
+ static const int value = 0;
};
template <typename Arg, typename... Args>
-struct compute_parameter_tag_from_args_list<Arg, Args...> {
- static const int subValue =
- compute_parameter_tag_from_args_list<Args...>::value;
- static const int value =
- parameter_tag<typename std::decay<Arg>::type>::value
- ? subValue * 6 + parameter_tag<typename std::decay<Arg>::type>::value
- : subValue;
-};
-
-static inline bool isParameterTagCompatible(uint64_t a, uint64_t b) {
- if (a == 0) {
- return b == 0;
- }
- if (b == 0) {
- return a == 0;
- }
- int sa = a % 6;
- int sb = a % 6;
- if (sa == 5) {
- sa = 4;
- }
- if (sb == 5) {
- sb = 4;
- }
- if (sa != sb) {
- return false;
- }
- return isParameterTagCompatible(a / 6, b / 6);
+struct compute_parameter_tag_from_args_list<Arg, Args...>
+{
+ static const int subValue =
+ compute_parameter_tag_from_args_list<Args...>::value;
+ static const int value =
+ parameter_tag<typename std::decay<Arg>::type>::value
+ ? subValue * 6 +
+ parameter_tag<typename std::decay<Arg>::type>::value
+ : subValue;
+};
+
+static inline bool isParameterTagCompatible(uint64_t a, uint64_t b)
+{
+ if (a == 0)
+ {
+ return b == 0;
+ }
+ if (b == 0)
+ {
+ return a == 0;
+ }
+ int sa = a % 6;
+ int sb = a % 6;
+ if (sa == 5)
+ {
+ sa = 4;
+ }
+ if (sb == 5)
+ {
+ sb = 4;
+ }
+ if (sa != sb)
+ {
+ return false;
+ }
+ return isParameterTagCompatible(a / 6, b / 6);
}
-static inline unsigned findClosingTagRuntime(const char* s, unsigned p) {
- return s[p] == 0 ? throw std::runtime_error("unmatched tag <")
- : s[p] == '>' ? p : findClosingTagRuntime(s, p + 1);
+static inline unsigned findClosingTagRuntime(const char* s, unsigned p)
+{
+ return s[p] == 0 ? throw std::runtime_error("unmatched tag <")
+ : s[p] == '>' ? p : findClosingTagRuntime(s, p + 1);
}
-static inline uint64_t getParameterTagRuntime(const char* s, unsigned p = 0) {
- return s[p] == 0
- ? 0
- : s[p] == '<'
- ? (std::strncmp(s + p, "<int>", 5) == 0
- ? getParameterTagRuntime(
- s, findClosingTagRuntime(s, p)) *
- 6 +
- 1
- : std::strncmp(s + p, "<uint>", 6) == 0
- ? getParameterTagRuntime(
- s, findClosingTagRuntime(s, p)) *
- 6 +
- 2
- : (std::strncmp(s + p, "<float>", 7) == 0 ||
- std::strncmp(s + p, "<double>", 8) == 0)
- ? getParameterTagRuntime(
- s, findClosingTagRuntime(s, p)) *
- 6 +
- 3
- : (std::strncmp(s + p, "<str>", 5) == 0 ||
- std::strncmp(s + p, "<string>", 8) ==
- 0)
- ? getParameterTagRuntime(
- s,
- findClosingTagRuntime(s, p)) *
- 6 +
- 4
- : std::strncmp(s + p, "<path>",
- 6) == 0
- ? getParameterTagRuntime(
- s,
- findClosingTagRuntime(
- s, p)) *
- 6 +
- 5
- : throw std::runtime_error(
- "invalid parameter "
- "type"))
- : getParameterTagRuntime(s, p + 1);
+static inline uint64_t getParameterTagRuntime(const char* s, unsigned p = 0)
+{
+ return s[p] == 0
+ ? 0
+ : s[p] == '<'
+ ? (std::strncmp(s + p, "<int>", 5) == 0
+ ? getParameterTagRuntime(
+ s, findClosingTagRuntime(s, p)) *
+ 6 +
+ 1
+ : std::strncmp(s + p, "<uint>", 6) == 0
+ ? getParameterTagRuntime(
+ s, findClosingTagRuntime(s, p)) *
+ 6 +
+ 2
+ : (std::strncmp(s + p, "<float>", 7) == 0 ||
+ std::strncmp(s + p, "<double>", 8) == 0)
+ ? getParameterTagRuntime(
+ s, findClosingTagRuntime(s, p)) *
+ 6 +
+ 3
+ : (std::strncmp(s + p, "<str>", 5) ==
+ 0 ||
+ std::strncmp(s + p, "<string>", 8) ==
+ 0)
+ ? getParameterTagRuntime(
+ s, findClosingTagRuntime(
+ s, p)) *
+ 6 +
+ 4
+ : std::strncmp(s + p, "<path>",
+ 6) == 0
+ ? getParameterTagRuntime(
+ s,
+ findClosingTagRuntime(
+ s, p)) *
+ 6 +
+ 5
+ : throw std::runtime_error(
+ "invalid parameter "
+ "type"))
+ : getParameterTagRuntime(s, p + 1);
}
-constexpr uint64_t get_parameter_tag(ConstStr s, unsigned p = 0) {
- return p == s.size()
- ? 0
- : s[p] == '<'
- ? (isInt(s, p)
- ? get_parameter_tag(s, findClosingTag(s, p)) * 6 + 1
- : isUint(s, p)
- ? get_parameter_tag(s, findClosingTag(s, p)) *
- 6 +
- 2
- : isFloat(s, p)
- ? get_parameter_tag(
- s, findClosingTag(s, p)) *
- 6 +
- 3
- : isStr(s, p)
- ? get_parameter_tag(
- s, findClosingTag(s, p)) *
- 6 +
- 4
- : isPath(s, p)
- ? get_parameter_tag(
- s,
- findClosingTag(s, p)) *
- 6 +
- 5
- : throw std::runtime_error(
- "invalid parameter "
- "type"))
- : get_parameter_tag(s, p + 1);
+constexpr uint64_t get_parameter_tag(ConstStr s, unsigned p = 0)
+{
+ return p == s.size()
+ ? 0
+ : s[p] == '<'
+ ? (isInt(s, p)
+ ? get_parameter_tag(s, findClosingTag(s, p)) * 6 + 1
+ : isUint(s, p)
+ ? get_parameter_tag(s, findClosingTag(s, p)) *
+ 6 +
+ 2
+ : isFloat(s, p)
+ ? get_parameter_tag(
+ s, findClosingTag(s, p)) *
+ 6 +
+ 3
+ : isStr(s, p)
+ ? get_parameter_tag(
+ s, findClosingTag(s, p)) *
+ 6 +
+ 4
+ : isPath(s, p)
+ ? get_parameter_tag(
+ s, findClosingTag(
+ s, p)) *
+ 6 +
+ 5
+ : throw std::runtime_error(
+ "invalid parameter "
+ "type"))
+ : get_parameter_tag(s, p + 1);
}
-template <typename... T>
-struct S {
- template <typename U>
- using push = S<U, T...>;
- template <typename U>
- using push_back = S<T..., U>;
- template <template <typename... Args> class U>
- using rebind = U<T...>;
+template <typename... T> struct S
+{
+ template <typename U> using push = S<U, T...>;
+ template <typename U> using push_back = S<T..., U>;
+ template <template <typename... Args> class U> using rebind = U<T...>;
};
-template <typename F, typename Set>
-struct CallHelper;
-template <typename F, typename... Args>
-struct CallHelper<F, S<Args...>> {
- template <typename F1, typename... Args1,
- typename = decltype(std::declval<F1>()(std::declval<Args1>()...))>
- static char __test(int);
+template <typename F, typename Set> struct CallHelper;
+template <typename F, typename... Args> struct CallHelper<F, S<Args...>>
+{
+ template <typename F1, typename... Args1,
+ typename = decltype(std::declval<F1>()(std::declval<Args1>()...))>
+ static char __test(int);
- template <typename...>
- static int __test(...);
+ template <typename...> static int __test(...);
- static constexpr bool value = sizeof(__test<F, Args...>(0)) == sizeof(char);
+ static constexpr bool value = sizeof(__test<F, Args...>(0)) == sizeof(char);
};
-template <int N>
-struct SingleTagToType {};
+template <int N> struct SingleTagToType
+{
+};
-template <>
-struct SingleTagToType<1> {
- using type = int64_t;
+template <> struct SingleTagToType<1>
+{
+ using type = int64_t;
};
-template <>
-struct SingleTagToType<2> {
- using type = uint64_t;
+template <> struct SingleTagToType<2>
+{
+ using type = uint64_t;
};
-template <>
-struct SingleTagToType<3> {
- using type = double;
+template <> struct SingleTagToType<3>
+{
+ using type = double;
};
-template <>
-struct SingleTagToType<4> {
- using type = std::string;
+template <> struct SingleTagToType<4>
+{
+ using type = std::string;
};
-template <>
-struct SingleTagToType<5> {
- using type = std::string;
+template <> struct SingleTagToType<5>
+{
+ using type = std::string;
};
-template <uint64_t Tag>
-struct Arguments {
- using subarguments = typename Arguments<Tag / 6>::type;
- using type = typename subarguments::template push<
- typename SingleTagToType<Tag % 6>::type>;
+template <uint64_t Tag> struct Arguments
+{
+ using subarguments = typename Arguments<Tag / 6>::type;
+ using type = typename subarguments::template push<
+ typename SingleTagToType<Tag % 6>::type>;
};
-template <>
-struct Arguments<0> {
- using type = S<>;
+template <> struct Arguments<0>
+{
+ using type = S<>;
};
-template <typename... T>
-struct LastElementType {
- using type =
- typename std::tuple_element<sizeof...(T) - 1, std::tuple<T...>>::type;
+template <typename... T> struct LastElementType
+{
+ using type =
+ typename std::tuple_element<sizeof...(T) - 1, std::tuple<T...>>::type;
};
-template <>
-struct LastElementType<> {};
+template <> struct LastElementType<>
+{
+};
// from
// http://stackoverflow.com/questions/13072359/c11-compile-time-array-with-logarithmic-evaluation-depth
-template <class T>
-using Invoke = typename T::type;
+template <class T> using Invoke = typename T::type;
-template <unsigned...>
-struct Seq {
- using type = Seq;
+template <unsigned...> struct Seq
+{
+ using type = Seq;
};
-template <class S1, class S2>
-struct concat;
+template <class S1, class S2> struct concat;
template <unsigned... I1, unsigned... I2>
-struct concat<Seq<I1...>, Seq<I2...>> : Seq<I1..., (sizeof...(I1) + I2)...> {};
+struct concat<Seq<I1...>, Seq<I2...>> : Seq<I1..., (sizeof...(I1) + I2)...>
+{
+};
-template <class S1, class S2>
-using Concat = Invoke<concat<S1, S2>>;
+template <class S1, class S2> using Concat = Invoke<concat<S1, S2>>;
-template <unsigned N>
-struct gen_seq;
-template <unsigned N>
-using GenSeq = Invoke<gen_seq<N>>;
+template <unsigned N> struct gen_seq;
+template <unsigned N> using GenSeq = Invoke<gen_seq<N>>;
-template <unsigned N>
-struct gen_seq : Concat<GenSeq<N / 2>, GenSeq<N - N / 2>> {};
+template <unsigned N> struct gen_seq : Concat<GenSeq<N / 2>, GenSeq<N - N / 2>>
+{
+};
-template <>
-struct gen_seq<0> : Seq<> {};
-template <>
-struct gen_seq<1> : Seq<0> {};
+template <> struct gen_seq<0> : Seq<>
+{
+};
+template <> struct gen_seq<1> : Seq<0>
+{
+};
-template <typename Seq, typename Tuple>
-struct PopBackHelper;
+template <typename Seq, typename Tuple> struct PopBackHelper;
-template <unsigned... N, typename Tuple>
-struct PopBackHelper<Seq<N...>, Tuple> {
- template <template <typename... Args> class U>
- using rebind = U<typename std::tuple_element<N, Tuple>::type...>;
+template <unsigned... N, typename Tuple> struct PopBackHelper<Seq<N...>, Tuple>
+{
+ template <template <typename... Args> class U>
+ using rebind = U<typename std::tuple_element<N, Tuple>::type...>;
};
template <typename... T>
-struct PopBack //: public PopBackHelper<typename
- // gen_seq<sizeof...(T)-1>::type, std::tuple<T...>>
+struct PopBack //: public PopBackHelper<typename
+ // gen_seq<sizeof...(T)-1>::type, std::tuple<T...>>
{
- template <template <typename... Args> class U>
- using rebind =
- typename PopBackHelper<typename gen_seq<sizeof...(T) - 1>::type,
- std::tuple<T...>>::template rebind<U>;
+ template <template <typename... Args> class U>
+ using rebind =
+ typename PopBackHelper<typename gen_seq<sizeof...(T) - 1>::type,
+ std::tuple<T...>>::template rebind<U>;
};
-template <>
-struct PopBack<> {
- template <template <typename... Args> class U>
- using rebind = U<>;
+template <> struct PopBack<>
+{
+ template <template <typename... Args> class U> using rebind = U<>;
};
// from
// http://stackoverflow.com/questions/2118541/check-if-c0x-parameter-pack-contains-a-type
-template <typename Tp, typename... List>
-struct Contains : std::true_type {};
+template <typename Tp, typename... List> struct Contains : std::true_type
+{
+};
template <typename Tp, typename Head, typename... Rest>
struct Contains<Tp, Head, Rest...>
: std::conditional<std::is_same<Tp, Head>::value, std::true_type,
- Contains<Tp, Rest...>>::type {};
+ Contains<Tp, Rest...>>::type
+{
+};
-template <typename Tp>
-struct Contains<Tp> : std::false_type {};
+template <typename Tp> struct Contains<Tp> : std::false_type
+{
+};
-template <typename T>
-struct EmptyContext {};
+template <typename T> struct EmptyContext
+{
+};
-template <typename T>
-struct promote {
- using type = T;
+template <typename T> struct promote
+{
+ using type = T;
};
-#define BMCWEB_INTERNAL_PROMOTE_TYPE(t1, t2) \
- template <> \
- struct promote<t1> { \
- using type = t2; \
- }
+#define BMCWEB_INTERNAL_PROMOTE_TYPE(t1, t2) \
+ template <> struct promote<t1> \
+ { \
+ using type = t2; \
+ }
BMCWEB_INTERNAL_PROMOTE_TYPE(char, int64_t);
BMCWEB_INTERNAL_PROMOTE_TYPE(short, int64_t);
@@ -400,204 +442,229 @@ BMCWEB_INTERNAL_PROMOTE_TYPE(unsigned long long, uint64_t);
BMCWEB_INTERNAL_PROMOTE_TYPE(float, double);
#undef BMCWEB_INTERNAL_PROMOTE_TYPE
-template <typename T>
-using promote_t = typename promote<T>::type;
+template <typename T> using promote_t = typename promote<T>::type;
-} // namespace black_magic
+} // namespace black_magic
-namespace detail {
+namespace detail
+{
template <class T, std::size_t N, class... Args>
-struct GetIndexOfElementFromTupleByTypeImpl {
- static constexpr auto value = N;
+struct GetIndexOfElementFromTupleByTypeImpl
+{
+ static constexpr auto value = N;
};
template <class T, std::size_t N, class... Args>
-struct GetIndexOfElementFromTupleByTypeImpl<T, N, T, Args...> {
- static constexpr auto value = N;
+struct GetIndexOfElementFromTupleByTypeImpl<T, N, T, Args...>
+{
+ static constexpr auto value = N;
};
template <class T, std::size_t N, class U, class... Args>
-struct GetIndexOfElementFromTupleByTypeImpl<T, N, U, Args...> {
- static constexpr auto value =
- GetIndexOfElementFromTupleByTypeImpl<T, N + 1, Args...>::value;
+struct GetIndexOfElementFromTupleByTypeImpl<T, N, U, Args...>
+{
+ static constexpr auto value =
+ GetIndexOfElementFromTupleByTypeImpl<T, N + 1, Args...>::value;
};
-} // namespace detail
+} // namespace detail
-namespace utility {
-template <class T, class... Args>
-T& getElementByType(std::tuple<Args...>& t) {
- return std::get<
- detail::GetIndexOfElementFromTupleByTypeImpl<T, 0, Args...>::value>(t);
+namespace utility
+{
+template <class T, class... Args> T& getElementByType(std::tuple<Args...>& t)
+{
+ return std::get<
+ detail::GetIndexOfElementFromTupleByTypeImpl<T, 0, Args...>::value>(t);
}
-template <typename T>
-struct function_traits;
+template <typename T> struct function_traits;
template <typename T>
-struct function_traits : public function_traits<decltype(&T::operator())> {
- using parent_t = function_traits<decltype(&T::operator())>;
- static const size_t arity = parent_t::arity;
- using result_type = typename parent_t::result_type;
- template <size_t i>
- using arg = typename parent_t::template arg<i>;
+struct function_traits : public function_traits<decltype(&T::operator())>
+{
+ using parent_t = function_traits<decltype(&T::operator())>;
+ static const size_t arity = parent_t::arity;
+ using result_type = typename parent_t::result_type;
+ template <size_t i> using arg = typename parent_t::template arg<i>;
};
template <typename ClassType, typename r, typename... Args>
-struct function_traits<r (ClassType::*)(Args...) const> {
- static const size_t arity = sizeof...(Args);
+struct function_traits<r (ClassType::*)(Args...) const>
+{
+ static const size_t arity = sizeof...(Args);
- using result_type = r;
+ using result_type = r;
- template <size_t i>
- using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
+ template <size_t i>
+ using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
};
template <typename ClassType, typename r, typename... Args>
-struct function_traits<r (ClassType::*)(Args...)> {
- static const size_t arity = sizeof...(Args);
+struct function_traits<r (ClassType::*)(Args...)>
+{
+ static const size_t arity = sizeof...(Args);
- using result_type = r;
+ using result_type = r;
- template <size_t i>
- using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
+ template <size_t i>
+ using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
};
template <typename r, typename... Args>
-struct function_traits<std::function<r(Args...)>> {
- static const size_t arity = sizeof...(Args);
+struct function_traits<std::function<r(Args...)>>
+{
+ static const size_t arity = sizeof...(Args);
- using result_type = r;
+ using result_type = r;
- template <size_t i>
- using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
+ template <size_t i>
+ using arg = typename std::tuple_element<i, std::tuple<Args...>>::type;
};
inline static std::string base64encode(
const char* data, size_t size,
const char* key =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/") {
- std::string ret;
- ret.resize((size + 2) / 3 * 4);
- auto it = ret.begin();
- while (size >= 3) {
- *it++ = key[(((unsigned char)*data) & 0xFC) >> 2];
- unsigned char h = (((unsigned char)*data++) & 0x03) << 4;
- *it++ = key[h | ((((unsigned char)*data) & 0xF0) >> 4)];
- h = (((unsigned char)*data++) & 0x0F) << 2;
- *it++ = key[h | ((((unsigned char)*data) & 0xC0) >> 6)];
- *it++ = key[((unsigned char)*data++) & 0x3F];
-
- size -= 3;
- }
- if (size == 1) {
- *it++ = key[(((unsigned char)*data) & 0xFC) >> 2];
- unsigned char h = (((unsigned char)*data++) & 0x03) << 4;
- *it++ = key[h];
- *it++ = '=';
- *it++ = '=';
- } else if (size == 2) {
- *it++ = key[(((unsigned char)*data) & 0xFC) >> 2];
- unsigned char h = (((unsigned char)*data++) & 0x03) << 4;
- *it++ = key[h | ((((unsigned char)*data) & 0xF0) >> 4)];
- h = (((unsigned char)*data++) & 0x0F) << 2;
- *it++ = key[h];
- *it++ = '=';
- }
- return ret;
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/")
+{
+ std::string ret;
+ ret.resize((size + 2) / 3 * 4);
+ auto it = ret.begin();
+ while (size >= 3)
+ {
+ *it++ = key[(((unsigned char)*data) & 0xFC) >> 2];
+ unsigned char h = (((unsigned char)*data++) & 0x03) << 4;
+ *it++ = key[h | ((((unsigned char)*data) & 0xF0) >> 4)];
+ h = (((unsigned char)*data++) & 0x0F) << 2;
+ *it++ = key[h | ((((unsigned char)*data) & 0xC0) >> 6)];
+ *it++ = key[((unsigned char)*data++) & 0x3F];
+
+ size -= 3;
+ }
+ if (size == 1)
+ {
+ *it++ = key[(((unsigned char)*data) & 0xFC) >> 2];
+ unsigned char h = (((unsigned char)*data++) & 0x03) << 4;
+ *it++ = key[h];
+ *it++ = '=';
+ *it++ = '=';
+ }
+ else if (size == 2)
+ {
+ *it++ = key[(((unsigned char)*data) & 0xFC) >> 2];
+ unsigned char h = (((unsigned char)*data++) & 0x03) << 4;
+ *it++ = key[h | ((((unsigned char)*data) & 0xF0) >> 4)];
+ h = (((unsigned char)*data++) & 0x0F) << 2;
+ *it++ = key[h];
+ *it++ = '=';
+ }
+ return ret;
}
-inline static std::string base64encodeUrlsafe(const char* data, size_t size) {
- return base64encode(
- data, size,
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
+inline static std::string base64encodeUrlsafe(const char* data, size_t size)
+{
+ return base64encode(
+ data, size,
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_");
}
// TODO this is temporary and should be deleted once base64 is refactored out of
// crow
-inline bool base64Decode(const boost::string_view input, std::string& output) {
- static const char nop = -1;
- // See note on encoding_data[] in above function
- static const char decodingData[] = {
- nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
- nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
- nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, 62, nop,
- nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, nop, nop,
- nop, nop, nop, nop, nop, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,
- 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24,
- 25, nop, nop, nop, nop, nop, nop, 26, 27, 28, 29, 30, 31, 32, 33,
- 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48,
- 49, 50, 51, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
- nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
- nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
- nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
- nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
- nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
- nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
- nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
- nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
- nop};
-
- size_t inputLength = input.size();
-
- // allocate space for output string
- output.clear();
- output.reserve(((inputLength + 2) / 3) * 4);
-
- // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
- // droping first two bits
- // and regenerate into 3 8-bits sequences
-
- for (size_t i = 0; i < inputLength; i++) {
- char base64code0;
- char base64code1;
- char base64code2 = 0; // initialized to 0 to suppress warnings
- char base64code3;
-
- base64code0 = decodingData[static_cast<int>(input[i])]; // NOLINT
- if (base64code0 == nop) { // non base64 character
- return false;
- }
- if (!(++i < inputLength)) { // we need at least two input bytes for first
- // byte output
- return false;
- }
- base64code1 = decodingData[static_cast<int>(input[i])]; // NOLINT
- if (base64code1 == nop) { // non base64 character
- return false;
- }
- output +=
- static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
-
- if (++i < inputLength) {
- char c = input[i];
- if (c == '=') { // padding , end of input
- return (base64code1 & 0x0f) == 0;
- }
- base64code2 = decodingData[static_cast<int>(input[i])]; // NOLINT
- if (base64code2 == nop) { // non base64 character
- return false;
- }
- output += static_cast<char>(((base64code1 << 4) & 0xf0) |
- ((base64code2 >> 2) & 0x0f));
- }
-
- if (++i < inputLength) {
- char c = input[i];
- if (c == '=') { // padding , end of input
- return (base64code2 & 0x03) == 0;
- }
- base64code3 = decodingData[static_cast<int>(input[i])]; // NOLINT
- if (base64code3 == nop) { // non base64 character
- return false;
- }
- output += static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
+inline bool base64Decode(const boost::string_view input, std::string& output)
+{
+ static const char nop = -1;
+ // See note on encoding_data[] in above function
+ static const char decodingData[] = {
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, 62, nop, nop, nop, 63, 52, 53, 54, 55, 56, 57, 58, 59,
+ 60, 61, nop, nop, nop, nop, nop, nop, nop, 0, 1, 2, 3, 4,
+ 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18,
+ 19, 20, 21, 22, 23, 24, 25, nop, nop, nop, nop, nop, nop, 26,
+ 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+ 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop, nop,
+ nop, nop, nop, nop};
+
+ size_t inputLength = input.size();
+
+ // allocate space for output string
+ output.clear();
+ output.reserve(((inputLength + 2) / 3) * 4);
+
+ // for each 4-bytes sequence from the input, extract 4 6-bits sequences by
+ // droping first two bits
+ // and regenerate into 3 8-bits sequences
+
+ for (size_t i = 0; i < inputLength; i++)
+ {
+ char base64code0;
+ char base64code1;
+ char base64code2 = 0; // initialized to 0 to suppress warnings
+ char base64code3;
+
+ base64code0 = decodingData[static_cast<int>(input[i])]; // NOLINT
+ if (base64code0 == nop)
+ { // non base64 character
+ return false;
+ }
+ if (!(++i < inputLength))
+ { // we need at least two input bytes for first
+ // byte output
+ return false;
+ }
+ base64code1 = decodingData[static_cast<int>(input[i])]; // NOLINT
+ if (base64code1 == nop)
+ { // non base64 character
+ return false;
+ }
+ output +=
+ static_cast<char>((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
+
+ if (++i < inputLength)
+ {
+ char c = input[i];
+ if (c == '=')
+ { // padding , end of input
+ return (base64code1 & 0x0f) == 0;
+ }
+ base64code2 = decodingData[static_cast<int>(input[i])]; // NOLINT
+ if (base64code2 == nop)
+ { // non base64 character
+ return false;
+ }
+ output += static_cast<char>(((base64code1 << 4) & 0xf0) |
+ ((base64code2 >> 2) & 0x0f));
+ }
+
+ if (++i < inputLength)
+ {
+ char c = input[i];
+ if (c == '=')
+ { // padding , end of input
+ return (base64code2 & 0x03) == 0;
+ }
+ base64code3 = decodingData[static_cast<int>(input[i])]; // NOLINT
+ if (base64code3 == nop)
+ { // non base64 character
+ return false;
+ }
+ output +=
+ static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
+ }
}
- }
- return true;
+ return true;
}
-} // namespace utility
-} // namespace crow
+} // namespace utility
+} // namespace crow
diff --git a/crow/include/crow/websocket.h b/crow/include/crow/websocket.h
index 82c6db8d73..f345223ebc 100644
--- a/crow/include/crow/websocket.h
+++ b/crow/include/crow/websocket.h
@@ -1,206 +1,240 @@
#pragma once
#include <array>
+#include <boost/algorithm/string/predicate.hpp>
+#include <boost/beast/websocket.hpp>
#include <functional>
+
#include "crow/http_request.h"
#include "crow/socket_adaptors.h"
-#include <boost/algorithm/string/predicate.hpp>
-#include <boost/beast/websocket.hpp>
#ifdef BMCWEB_ENABLE_SSL
#include <boost/beast/websocket/ssl.hpp>
#endif
-namespace crow {
-namespace websocket {
-struct Connection : std::enable_shared_from_this<Connection> {
- public:
- explicit Connection(const crow::Request& req)
- : req(req), userdataPtr(nullptr){};
-
- virtual void sendBinary(const boost::beast::string_view msg) = 0;
- virtual void sendBinary(std::string&& msg) = 0;
- virtual void sendText(const boost::beast::string_view msg) = 0;
- virtual void sendText(std::string&& msg) = 0;
- virtual void close(const boost::beast::string_view msg = "quit") = 0;
- virtual boost::asio::io_service& getIoService() = 0;
- virtual ~Connection() = default;
-
- void userdata(void* u) { userdataPtr = u; }
- void* userdata() { return userdataPtr; }
+namespace crow
+{
+namespace websocket
+{
+struct Connection : std::enable_shared_from_this<Connection>
+{
+ public:
+ explicit Connection(const crow::Request& req) :
+ req(req), userdataPtr(nullptr){};
+
+ virtual void sendBinary(const boost::beast::string_view msg) = 0;
+ virtual void sendBinary(std::string&& msg) = 0;
+ virtual void sendText(const boost::beast::string_view msg) = 0;
+ virtual void sendText(std::string&& msg) = 0;
+ virtual void close(const boost::beast::string_view msg = "quit") = 0;
+ virtual boost::asio::io_service& getIoService() = 0;
+ virtual ~Connection() = default;
+
+ void userdata(void* u)
+ {
+ userdataPtr = u;
+ }
+ void* userdata()
+ {
+ return userdataPtr;
+ }
- crow::Request req;
+ crow::Request req;
- private:
- void* userdataPtr;
+ private:
+ void* userdataPtr;
};
-template <typename Adaptor>
-class ConnectionImpl : public Connection {
- public:
- ConnectionImpl(
- const crow::Request& req, Adaptor&& adaptorIn,
- std::function<void(Connection&)> open_handler,
- std::function<void(Connection&, const std::string&, bool)>
- message_handler,
- std::function<void(Connection&, const std::string&)> close_handler,
- std::function<void(Connection&)> error_handler)
- : adaptor(std::move(adaptorIn)),
- ws(adaptor.socket()),
- Connection(req),
+template <typename Adaptor> class ConnectionImpl : public Connection
+{
+ public:
+ ConnectionImpl(
+ const crow::Request& req, Adaptor&& adaptorIn,
+ std::function<void(Connection&)> open_handler,
+ std::function<void(Connection&, const std::string&, bool)>
+ message_handler,
+ std::function<void(Connection&, const std::string&)> close_handler,
+ std::function<void(Connection&)> error_handler) :
+ adaptor(std::move(adaptorIn)),
+ ws(adaptor.socket()), Connection(req),
openHandler(std::move(open_handler)),
messageHandler(std::move(message_handler)),
closeHandler(std::move(close_handler)),
- errorHandler(std::move(error_handler)) {
- BMCWEB_LOG_DEBUG << "Creating new connection " << this;
- }
-
- boost::asio::io_service& getIoService() override {
- return adaptor.getIoService();
- }
-
- void start() {
- BMCWEB_LOG_DEBUG << "starting connection " << this;
-
- boost::string_view protocol =
- req.getHeaderValue(boost::beast::http::field::sec_websocket_protocol);
-
- // Perform the websocket upgrade
- ws.async_accept_ex(
- req.req,
- [protocol{std::string(protocol)}](
- boost::beast::websocket::response_type & m) {
- if (!protocol.empty()) {
- m.insert(boost::beast::http::field::sec_websocket_protocol,
- protocol);
- }
- },
- [ this, self(shared_from_this()) ](boost::system::error_code ec) {
- if (ec) {
- BMCWEB_LOG_ERROR << "Error in ws.async_accept " << ec;
- return;
- }
- acceptDone();
- });
- }
-
- void sendBinary(const boost::beast::string_view msg) override {
- ws.binary(true);
- outBuffer.emplace_back(msg);
- doWrite();
- }
-
- void sendBinary(std::string&& msg) override {
- ws.binary(true);
- outBuffer.emplace_back(std::move(msg));
- doWrite();
- }
-
- void sendText(const boost::beast::string_view msg) override {
- ws.text(true);
- outBuffer.emplace_back(msg);
- doWrite();
- }
-
- void sendText(std::string&& msg) override {
- ws.text(true);
- outBuffer.emplace_back(std::move(msg));
- doWrite();
- }
-
- void close(const boost::beast::string_view msg) override {
- ws.async_close(
- boost::beast::websocket::close_code::normal,
- [ this, self(shared_from_this()) ](boost::system::error_code ec) {
- if (ec) {
- BMCWEB_LOG_ERROR << "Error closing websocket " << ec;
- return;
- }
- adaptor.close();
- });
- }
+ errorHandler(std::move(error_handler))
+ {
+ BMCWEB_LOG_DEBUG << "Creating new connection " << this;
+ }
- void acceptDone() {
- BMCWEB_LOG_DEBUG << "Websocket accepted connection";
+ boost::asio::io_service& getIoService() override
+ {
+ return adaptor.getIoService();
+ }
- if (openHandler) {
- openHandler(*this);
+ void start()
+ {
+ BMCWEB_LOG_DEBUG << "starting connection " << this;
+
+ boost::string_view protocol = req.getHeaderValue(
+ boost::beast::http::field::sec_websocket_protocol);
+
+ // Perform the websocket upgrade
+ ws.async_accept_ex(
+ req.req,
+ [protocol{std::string(protocol)}](
+ boost::beast::websocket::response_type& m) {
+ if (!protocol.empty())
+ {
+ m.insert(boost::beast::http::field::sec_websocket_protocol,
+ protocol);
+ }
+ },
+ [this, self(shared_from_this())](boost::system::error_code ec) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "Error in ws.async_accept " << ec;
+ return;
+ }
+ acceptDone();
+ });
}
- doRead();
- }
-
- void doRead() {
- ws.async_read(
- inBuffer, [ this, self(shared_from_this()) ](
- boost::beast::error_code ec, std::size_t bytes_read) {
- if (ec) {
- if (ec != boost::beast::websocket::error::closed) {
- BMCWEB_LOG_ERROR << "doRead error " << ec;
- }
- if (closeHandler) {
- boost::beast::string_view reason = ws.reason().reason;
- closeHandler(*this, std::string(reason));
- }
- return;
- }
- if (messageHandler) {
- // TODO(Ed) There must be a more direct way to do this conversion,
- // but I can't find it at the moment. It should get optimized away
- boost::asio::const_buffer cb =
- boost::beast::buffers_front(inBuffer.data());
- boost::beast::string_view message(
- reinterpret_cast<char const*>(cb.data()), cb.size());
- messageHandler(*this, std::string(message), ws.got_text());
- }
- doRead();
- });
- }
-
- void doWrite() {
- // If we're already doing a write, ignore the request, it will be picked up
- // when the current write is complete
- if (doingWrite) {
- return;
+
+ void sendBinary(const boost::beast::string_view msg) override
+ {
+ ws.binary(true);
+ outBuffer.emplace_back(msg);
+ doWrite();
+ }
+
+ void sendBinary(std::string&& msg) override
+ {
+ ws.binary(true);
+ outBuffer.emplace_back(std::move(msg));
+ doWrite();
}
- if (outBuffer.empty()) {
- // Done for now
- return;
+ void sendText(const boost::beast::string_view msg) override
+ {
+ ws.text(true);
+ outBuffer.emplace_back(msg);
+ doWrite();
}
- doingWrite = true;
- ws.async_write(boost::asio::buffer(outBuffer.front()),
- [ this, self(shared_from_this()) ](
- boost::beast::error_code ec, std::size_t bytes_written) {
- doingWrite = false;
- outBuffer.erase(outBuffer.begin());
- if (ec == boost::beast::websocket::error::closed) {
- // Do nothing here. doRead handler will call the
- // closeHandler.
- close("Write error");
- return;
- }
- if (ec) {
- BMCWEB_LOG_ERROR << "Error in ws.async_write " << ec;
- return;
- }
- doWrite();
- });
- }
-
- private:
- Adaptor adaptor;
-
- boost::beast::websocket::stream<
- std::add_lvalue_reference_t<typename Adaptor::streamType>>
- ws;
-
- boost::beast::flat_static_buffer<4096> inBuffer;
- std::vector<std::string> outBuffer;
- bool doingWrite = false;
-
- std::function<void(Connection&)> openHandler;
- std::function<void(Connection&, const std::string&, bool)> messageHandler;
- std::function<void(Connection&, const std::string&)> closeHandler;
- std::function<void(Connection&)> errorHandler;
+
+ void sendText(std::string&& msg) override
+ {
+ ws.text(true);
+ outBuffer.emplace_back(std::move(msg));
+ doWrite();
+ }
+
+ void close(const boost::beast::string_view msg) override
+ {
+ ws.async_close(
+ boost::beast::websocket::close_code::normal,
+ [this, self(shared_from_this())](boost::system::error_code ec) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "Error closing websocket " << ec;
+ return;
+ }
+ adaptor.close();
+ });
+ }
+
+ void acceptDone()
+ {
+ BMCWEB_LOG_DEBUG << "Websocket accepted connection";
+
+ if (openHandler)
+ {
+ openHandler(*this);
+ }
+ doRead();
+ }
+
+ void doRead()
+ {
+ ws.async_read(
+ inBuffer, [this, self(shared_from_this())](
+ boost::beast::error_code ec, std::size_t bytes_read) {
+ if (ec)
+ {
+ if (ec != boost::beast::websocket::error::closed)
+ {
+ BMCWEB_LOG_ERROR << "doRead error " << ec;
+ }
+ if (closeHandler)
+ {
+ boost::beast::string_view reason = ws.reason().reason;
+ closeHandler(*this, std::string(reason));
+ }
+ return;
+ }
+ if (messageHandler)
+ {
+ // TODO(Ed) There must be a more direct way to do this
+ // conversion, but I can't find it at the moment. It should
+ // get optimized away
+ boost::asio::const_buffer cb =
+ boost::beast::buffers_front(inBuffer.data());
+ boost::beast::string_view message(
+ reinterpret_cast<char const*>(cb.data()), cb.size());
+ messageHandler(*this, std::string(message), ws.got_text());
+ }
+ doRead();
+ });
+ }
+
+ void doWrite()
+ {
+ // If we're already doing a write, ignore the request, it will be picked
+ // up when the current write is complete
+ if (doingWrite)
+ {
+ return;
+ }
+
+ if (outBuffer.empty())
+ {
+ // Done for now
+ return;
+ }
+ doingWrite = true;
+ ws.async_write(
+ boost::asio::buffer(outBuffer.front()),
+ [this, self(shared_from_this())](boost::beast::error_code ec,
+ std::size_t bytes_written) {
+ doingWrite = false;
+ outBuffer.erase(outBuffer.begin());
+ if (ec == boost::beast::websocket::error::closed)
+ {
+ // Do nothing here. doRead handler will call the
+ // closeHandler.
+ close("Write error");
+ return;
+ }
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "Error in ws.async_write " << ec;
+ return;
+ }
+ doWrite();
+ });
+ }
+
+ private:
+ Adaptor adaptor;
+
+ boost::beast::websocket::stream<
+ std::add_lvalue_reference_t<typename Adaptor::streamType>>
+ ws;
+
+ boost::beast::flat_static_buffer<4096> inBuffer;
+ std::vector<std::string> outBuffer;
+ bool doingWrite = false;
+
+ std::function<void(Connection&)> openHandler;
+ std::function<void(Connection&, const std::string&, bool)> messageHandler;
+ std::function<void(Connection&, const std::string&)> closeHandler;
+ std::function<void(Connection&)> errorHandler;
};
-} // namespace websocket
-} // namespace crow
+} // namespace websocket
+} // namespace crow