summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEd Tanous <ed.tanous@intel.com>2018-09-05 18:30:59 +0300
committerEd Tanous <ed.tanous@intel.com>2018-09-05 18:44:12 +0300
commit1abe55ef9844afcddcab9d862ae06118f3a2390c (patch)
treed0b5fcfd0b1cd679a8995af3eb0b6d31b368380e
parenta38b0b206300c792979b900f506b85e535f5708a (diff)
downloadbmcweb-1abe55ef9844afcddcab9d862ae06118f3a2390c.tar.xz
Move to clang-format-6.0
This commit moves the codebase to the lastest clang-format file from upstream, as well as clang-format-6.0. Change-Id: Ice8313468097c0c42317fbb9e10ddf036e8cff4c Signed-off-by: Ed Tanous <ed.tanous@intel.com>
-rw-r--r--.clang-format79
-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
-rw-r--r--include/ast_jpeg_decoder.hpp2685
-rw-r--r--include/ast_video_puller.hpp318
-rw-r--r--include/ast_video_types.hpp32
-rw-r--r--include/dbus_monitor.hpp370
-rw-r--r--include/dbus_singleton.hpp33
-rw-r--r--include/gzip_helper.hpp85
-rw-r--r--include/http_utility.hpp38
-rw-r--r--include/image_upload.hpp170
-rw-r--r--include/openbmc_dbus_rest.hpp2407
-rw-r--r--include/pam_authenticate.hpp112
-rw-r--r--include/persistent_data_middleware.hpp234
-rw-r--r--include/redfish_v1.hpp241
-rw-r--r--include/security_headers_middleware.hpp63
-rw-r--r--include/sessions.hpp444
-rw-r--r--include/ssl_key_handler.hpp567
-rw-r--r--include/token_authorization_middleware.hpp711
-rw-r--r--include/web_kvm.hpp665
-rw-r--r--include/webassets.hpp250
-rw-r--r--redfish-core/include/error_messages.hpp10
-rw-r--r--redfish-core/include/node.hpp277
-rw-r--r--redfish-core/include/privileges.hpp261
-rw-r--r--redfish-core/include/redfish.hpp79
-rw-r--r--redfish-core/include/utils/json_utils.hpp30
-rw-r--r--redfish-core/lib/account_service.hpp69
-rw-r--r--redfish-core/lib/chassis.hpp415
-rw-r--r--redfish-core/lib/ethernet.hpp3448
-rw-r--r--redfish-core/lib/managers.hpp182
-rw-r--r--redfish-core/lib/network_protocol.hpp311
-rw-r--r--redfish-core/lib/redfish_sessions.hpp604
-rw-r--r--redfish-core/lib/roles.hpp134
-rw-r--r--redfish-core/lib/sensors.hpp788
-rw-r--r--redfish-core/lib/service_root.hpp99
-rw-r--r--redfish-core/lib/systems.hpp1431
-rw-r--r--redfish-core/lib/thermal.hpp75
-rw-r--r--redfish-core/lib/update_service.hpp771
-rw-r--r--redfish-core/src/error_messages.cpp1286
-rw-r--r--redfish-core/src/utils/json_utils.cpp670
-rw-r--r--redfish-core/ut/privileges_test.cpp167
-rw-r--r--src/ast_jpeg_decoder_test.cpp283
-rw-r--r--src/ast_video_puller_test.cpp65
-rw-r--r--src/base64.cpp290
-rw-r--r--src/crow_getroutes_test.cpp58
-rw-r--r--src/crow_test.cpp1508
-rw-r--r--src/getvideo_main.cpp94
-rw-r--r--src/gtest_main.cpp7
-rw-r--r--src/kvm_websocket_test.cpp191
-rw-r--r--src/msan_test.cpp8
-rw-r--r--src/openbmc_jtag_rest_test.cpp92
-rw-r--r--src/security_headers_middleware_test.cpp126
-rw-r--r--src/token_authorization_middleware_test.cpp527
-rw-r--r--src/webassets_test.cpp234
-rw-r--r--src/webserver_main.cpp105
68 files changed, 16973 insertions, 13975 deletions
diff --git a/.clang-format b/.clang-format
index b98e24fe47..dd27708378 100644
--- a/.clang-format
+++ b/.clang-format
@@ -1,97 +1,98 @@
---
-BasedOnStyle: Google
-AccessModifierOffset: -1
+Language: Cpp
+# BasedOnStyle: LLVM
+AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: false
AlignConsecutiveDeclarations: false
-AlignEscapedNewlinesLeft: true
+AlignEscapedNewlinesLeft: false
AlignOperands: true
AlignTrailingComments: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: false
AllowShortCaseLabelsOnASingleLine: false
-AllowShortFunctionsOnASingleLine: All
-AllowShortIfStatementsOnASingleLine: true
-AllowShortLoopsOnASingleLine: true
+AllowShortFunctionsOnASingleLine: None
+AllowShortIfStatementsOnASingleLine: false
+AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
-AlwaysBreakBeforeMultilineStrings: true
-AlwaysBreakTemplateDeclarations: true
+AlwaysBreakBeforeMultilineStrings: false
+AlwaysBreakTemplateDeclarations: false
BinPackArguments: true
BinPackParameters: true
BraceWrapping:
- AfterClass: false
- AfterControlStatement: false
- AfterEnum: false
- AfterFunction: false
- AfterNamespace: false
- AfterObjCDeclaration: false
- AfterStruct: false
- AfterUnion: false
- BeforeCatch: false
- BeforeElse: false
+ AfterClass: true
+ AfterControlStatement: true
+ AfterEnum: true
+ AfterFunction: true
+ AfterNamespace: true
+ AfterObjCDeclaration: true
+ AfterStruct: true
+ AfterUnion: true
+ BeforeCatch: true
+ BeforeElse: true
IndentBraces: false
BreakBeforeBinaryOperators: None
-BreakBeforeBraces: Attach
+BreakBeforeBraces: Custom
BreakBeforeTernaryOperators: true
-BreakConstructorInitializersBeforeComma: false
+BreakConstructorInitializers: AfterColon
ColumnLimit: 80
CommentPragmas: '^ IWYU pragma:'
-ConstructorInitializerAllOnOneLineOrOnePerLine: true
+ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 4
ContinuationIndentWidth: 4
Cpp11BracedListStyle: true
DerivePointerAlignment: true
+PointerAlignment: Left
DisableFormat: false
ExperimentalAutoDetectBinPacking: false
+FixNamespaceComments: true
ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ]
+IncludeBlocks: Regroup
IncludeCategories:
- - Regex: '^[<"](crow)'
- Priority: 5
- - Regex: '^[<"](boost)'
- Priority: 6
- Regex: '^[<"](gtest|gmock)'
- Priority: 7
- - Regex: '^<.*\.h>'
+ Priority: 5
+ - Regex: '^"config.h"'
+ Priority: -1
+ - Regex: '^".*\.hpp"'
Priority: 1
- - Regex: '^<.*\.hpp>'
+ - Regex: '^<.*\.h>'
Priority: 2
- Regex: '^<.*'
Priority: 3
- Regex: '.*'
Priority: 4
IndentCaseLabels: true
-IndentWidth: 2
-IndentWrappedFunctionNames: false
-KeepEmptyLinesAtTheStartOfBlocks: false
+IndentWidth: 4
+IndentWrappedFunctionNames: true
+KeepEmptyLinesAtTheStartOfBlocks: true
MacroBlockBegin: ''
MacroBlockEnd: ''
MaxEmptyLinesToKeep: 1
NamespaceIndentation: None
ObjCBlockIndentWidth: 2
ObjCSpaceAfterProperty: false
-ObjCSpaceBeforeProtocolList: false
-PenaltyBreakBeforeFirstCallParameter: 1
+ObjCSpaceBeforeProtocolList: true
+PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakString: 1000
PenaltyExcessCharacter: 1000000
-PenaltyReturnTypeOnItsOwnLine: 200
-PointerAlignment: Left
+PenaltyReturnTypeOnItsOwnLine: 60
+PointerAlignment: Right
ReflowComments: true
SortIncludes: true
SpaceAfterCStyleCast: false
SpaceBeforeAssignmentOperators: true
SpaceBeforeParens: ControlStatements
SpaceInEmptyParentheses: false
-SpacesBeforeTrailingComments: 2
+SpacesBeforeTrailingComments: 1
SpacesInAngles: false
SpacesInContainerLiterals: true
SpacesInCStyleCastParentheses: false
SpacesInParentheses: false
SpacesInSquareBrackets: false
-Standard: Auto
-TabWidth: 8
+Standard: Cpp11
+TabWidth: 4
UseTab: Never
...
-
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
diff --git a/include/ast_jpeg_decoder.hpp b/include/ast_jpeg_decoder.hpp
index e6e0f08efb..e8bdddbf59 100644
--- a/include/ast_jpeg_decoder.hpp
+++ b/include/ast_jpeg_decoder.hpp
@@ -1,345 +1,390 @@
#pragma once
#include <aspeed/JTABLES.H>
-#include <ast_video_types.hpp>
+
#include <array>
+#include <ast_video_types.hpp>
#include <cassert>
#include <cstdint>
#include <cstring>
#include <iostream>
#include <vector>
-namespace ast_video {
+namespace ast_video
+{
-struct ColorCache {
- ColorCache()
- : color{0x008080, 0xFF8080, 0x808080, 0xC08080}, index{0, 1, 2, 3} {}
+struct ColorCache
+{
+ ColorCache() :
+ color{0x008080, 0xFF8080, 0x808080, 0xC08080}, index{0, 1, 2, 3}
+ {
+ }
- unsigned long color[4];
- unsigned char index[4];
- unsigned char bitMapBits{};
+ unsigned long color[4];
+ unsigned char index[4];
+ unsigned char bitMapBits{};
};
-struct RGB {
- unsigned char b;
- unsigned char g;
- unsigned char r;
- unsigned char reserved;
+struct RGB
+{
+ unsigned char b;
+ unsigned char g;
+ unsigned char r;
+ unsigned char reserved;
};
-enum class JpgBlock {
- JPEG_NO_SKIP_CODE = 0x00,
- JPEG_SKIP_CODE = 0x08,
+enum class JpgBlock
+{
+ JPEG_NO_SKIP_CODE = 0x00,
+ JPEG_SKIP_CODE = 0x08,
- JPEG_PASS2_CODE = 0x02,
- JPEG_SKIP_PASS2_CODE = 0x0A,
+ JPEG_PASS2_CODE = 0x02,
+ JPEG_SKIP_PASS2_CODE = 0x0A,
- LOW_JPEG_NO_SKIP_CODE = 0x04,
- LOW_JPEG_SKIP_CODE = 0x0C,
+ LOW_JPEG_NO_SKIP_CODE = 0x04,
+ LOW_JPEG_SKIP_CODE = 0x0C,
- VQ_NO_SKIP_1_COLOR_CODE = 0x05,
- VQ_SKIP_1_COLOR_CODE = 0x0D,
+ VQ_NO_SKIP_1_COLOR_CODE = 0x05,
+ VQ_SKIP_1_COLOR_CODE = 0x0D,
- VQ_NO_SKIP_2_COLOR_CODE = 0x06,
- VQ_SKIP_2_COLOR_CODE = 0x0E,
+ VQ_NO_SKIP_2_COLOR_CODE = 0x06,
+ VQ_SKIP_2_COLOR_CODE = 0x0E,
- VQ_NO_SKIP_4_COLOR_CODE = 0x07,
- VQ_SKIP_4_COLOR_CODE = 0x0F,
+ VQ_NO_SKIP_4_COLOR_CODE = 0x07,
+ VQ_SKIP_4_COLOR_CODE = 0x0F,
- FRAME_END_CODE = 0x09,
+ FRAME_END_CODE = 0x09,
};
-class AstJpegDecoder {
- public:
- AstJpegDecoder() {
- // TODO(ed) figure out how to init this in the constructor
- yuvBuffer.resize(1920 * 1200);
- outBuffer.resize(1920 * 1200);
- for (auto &r : outBuffer) {
- r.r = 0x00;
- r.g = 0x00;
- r.b = 0x00;
- r.reserved = 0xAA;
- }
+class AstJpegDecoder
+{
+ public:
+ AstJpegDecoder()
+ {
+ // TODO(ed) figure out how to init this in the constructor
+ yuvBuffer.resize(1920 * 1200);
+ outBuffer.resize(1920 * 1200);
+ for (auto &r : outBuffer)
+ {
+ r.r = 0x00;
+ r.g = 0x00;
+ r.b = 0x00;
+ r.reserved = 0xAA;
+ }
- int qfactor = 16;
-
- scalefactor = qfactor;
- scalefactoruv = qfactor;
- advancescalefactor = 16;
- advancescalefactoruv = 16;
- initJpgTable();
- }
-
- void loadQuantTable(std::array<long, 64> &quant_table) {
- float scalefactorF[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
- 1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
- uint8_t j, row, col;
- std::array<uint8_t, 64> tempQT{};
-
- // Load quantization coefficients from JPG file, scale them for DCT and
- // reorder
- // from zig-zag order
- switch (ySelector) {
- case 0:
- stdLuminanceQt = tbl000Y;
- break;
- case 1:
- stdLuminanceQt = tbl014Y;
- break;
- case 2:
- stdLuminanceQt = tbl029Y;
- break;
- case 3:
- stdLuminanceQt = tbl043Y;
- break;
- case 4:
- stdLuminanceQt = tbl057Y;
- break;
- case 5:
- stdLuminanceQt = tbl071Y;
- break;
- case 6:
- stdLuminanceQt = tbl086Y;
- break;
- case 7:
- stdLuminanceQt = tbl100Y;
- break;
- }
- setQuantTable(stdLuminanceQt, static_cast<uint8_t>(scalefactor), tempQT);
+ int qfactor = 16;
- for (j = 0; j <= 63; j++) {
- quant_table[j] = tempQT[zigzag[j]];
- }
- j = 0;
- for (row = 0; row <= 7; row++) {
- for (col = 0; col <= 7; col++) {
- quant_table[j] = static_cast<long>(
- (quant_table[j] * scalefactorF[row] * scalefactorF[col]) * 65536);
- j++;
- }
- }
- bytePos += 64;
- }
-
- void loadQuantTableCb(std::array<long, 64> &quant_table) {
- float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
- 1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
- uint8_t j, row, col;
- std::array<uint8_t, 64> tempQT{};
-
- // Load quantization coefficients from JPG file, scale them for DCT and
- // reorder from zig-zag order
- if (mapping == 0) {
- switch (uvSelector) {
- case 0:
- stdChrominanceQt = tbl000Y;
- break;
- case 1:
- stdChrominanceQt = tbl014Y;
- break;
- case 2:
- stdChrominanceQt = tbl029Y;
- break;
- case 3:
- stdChrominanceQt = tbl043Y;
- break;
- case 4:
- stdChrominanceQt = tbl057Y;
- break;
- case 5:
- stdChrominanceQt = tbl071Y;
- break;
- case 6:
- stdChrominanceQt = tbl086Y;
- break;
- case 7:
- stdChrominanceQt = tbl100Y;
- break;
- }
- } else {
- switch (uvSelector) {
- case 0:
- stdChrominanceQt = tbl000Uv;
- break;
- case 1:
- stdChrominanceQt = tbl014Uv;
- break;
- case 2:
- stdChrominanceQt = tbl029Uv;
- break;
- case 3:
- stdChrominanceQt = tbl043Uv;
- break;
- case 4:
- stdChrominanceQt = tbl057Uv;
- break;
- case 5:
- stdChrominanceQt = tbl071Uv;
- break;
- case 6:
- stdChrominanceQt = tbl086Uv;
- break;
- case 7:
- stdChrominanceQt = tbl100Uv;
- break;
- }
+ scalefactor = qfactor;
+ scalefactoruv = qfactor;
+ advancescalefactor = 16;
+ advancescalefactoruv = 16;
+ initJpgTable();
}
- setQuantTable(stdChrominanceQt, static_cast<uint8_t>(scalefactoruv),
- tempQT);
- for (j = 0; j <= 63; j++) {
- quant_table[j] = tempQT[zigzag[j]];
- }
- j = 0;
- for (row = 0; row <= 7; row++) {
- for (col = 0; col <= 7; col++) {
- quant_table[j] = static_cast<long>(
- (quant_table[j] * scalefactor[row] * scalefactor[col]) * 65536);
- j++;
- }
- }
- bytePos += 64;
- }
- // Note: Added for Dual_JPEG
- void loadAdvanceQuantTable(std::array<long, 64> &quant_table) {
- float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
- 1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
- uint8_t j, row, col;
- std::array<uint8_t, 64> tempQT{};
-
- // Load quantization coefficients from JPG file, scale them for DCT and
- // reorder
- // from zig-zag order
- switch (advanceSelector) {
- case 0:
- stdLuminanceQt = tbl000Y;
- break;
- case 1:
- stdLuminanceQt = tbl014Y;
- break;
- case 2:
- stdLuminanceQt = tbl029Y;
- break;
- case 3:
- stdLuminanceQt = tbl043Y;
- break;
- case 4:
- stdLuminanceQt = tbl057Y;
- break;
- case 5:
- stdLuminanceQt = tbl071Y;
- break;
- case 6:
- stdLuminanceQt = tbl086Y;
- break;
- case 7:
- stdLuminanceQt = tbl100Y;
- break;
- }
- // Note: pass ADVANCE SCALE FACTOR to sub-function in Dual-JPEG
- setQuantTable(stdLuminanceQt, static_cast<uint8_t>(advancescalefactor),
- tempQT);
+ void loadQuantTable(std::array<long, 64> &quant_table)
+ {
+ float scalefactorF[8] = {1.0f, 1.387039845f, 1.306562965f,
+ 1.175875602f, 1.0f, 0.785694958f,
+ 0.541196100f, 0.275899379f};
+ uint8_t j, row, col;
+ std::array<uint8_t, 64> tempQT{};
+
+ // Load quantization coefficients from JPG file, scale them for DCT and
+ // reorder
+ // from zig-zag order
+ switch (ySelector)
+ {
+ case 0:
+ stdLuminanceQt = tbl000Y;
+ break;
+ case 1:
+ stdLuminanceQt = tbl014Y;
+ break;
+ case 2:
+ stdLuminanceQt = tbl029Y;
+ break;
+ case 3:
+ stdLuminanceQt = tbl043Y;
+ break;
+ case 4:
+ stdLuminanceQt = tbl057Y;
+ break;
+ case 5:
+ stdLuminanceQt = tbl071Y;
+ break;
+ case 6:
+ stdLuminanceQt = tbl086Y;
+ break;
+ case 7:
+ stdLuminanceQt = tbl100Y;
+ break;
+ }
+ setQuantTable(stdLuminanceQt, static_cast<uint8_t>(scalefactor),
+ tempQT);
- for (j = 0; j <= 63; j++) {
- quant_table[j] = tempQT[zigzag[j]];
- }
- j = 0;
- for (row = 0; row <= 7; row++) {
- for (col = 0; col <= 7; col++) {
- quant_table[j] = static_cast<long>(
- (quant_table[j] * scalefactor[row] * scalefactor[col]) * 65536);
- j++;
- }
+ for (j = 0; j <= 63; j++)
+ {
+ quant_table[j] = tempQT[zigzag[j]];
+ }
+ j = 0;
+ for (row = 0; row <= 7; row++)
+ {
+ for (col = 0; col <= 7; col++)
+ {
+ quant_table[j] = static_cast<long>(
+ (quant_table[j] * scalefactorF[row] * scalefactorF[col]) *
+ 65536);
+ j++;
+ }
+ }
+ bytePos += 64;
}
- bytePos += 64;
- }
-
- // Note: Added for Dual-JPEG
- void loadAdvanceQuantTableCb(std::array<long, 64> &quant_table) {
- float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
- 1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
- uint8_t j, row, col;
- std::array<uint8_t, 64> tempQT{};
-
- // Load quantization coefficients from JPG file, scale them for DCT and
- // reorder
- // from zig-zag order
- if (mapping == 1) {
- switch (advanceSelector) {
- case 0:
- stdChrominanceQt = tbl000Y;
- break;
- case 1:
- stdChrominanceQt = tbl014Y;
- break;
- case 2:
- stdChrominanceQt = tbl029Y;
- break;
- case 3:
- stdChrominanceQt = tbl043Y;
- break;
- case 4:
- stdChrominanceQt = tbl057Y;
- break;
- case 5:
- stdChrominanceQt = tbl071Y;
- break;
- case 6:
- stdChrominanceQt = tbl086Y;
- break;
- case 7:
- stdChrominanceQt = tbl100Y;
- break;
- }
- } else {
- switch (advanceSelector) {
- case 0:
- stdChrominanceQt = tbl000Uv;
- break;
- case 1:
- stdChrominanceQt = tbl014Uv;
- break;
- case 2:
- stdChrominanceQt = tbl029Uv;
- break;
- case 3:
- stdChrominanceQt = tbl043Uv;
- break;
- case 4:
- stdChrominanceQt = tbl057Uv;
- break;
- case 5:
- stdChrominanceQt = tbl071Uv;
- break;
- case 6:
- stdChrominanceQt = tbl086Uv;
- break;
- case 7:
- stdChrominanceQt = tbl100Uv;
- break;
- }
+
+ void loadQuantTableCb(std::array<long, 64> &quant_table)
+ {
+ float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
+ 1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
+ uint8_t j, row, col;
+ std::array<uint8_t, 64> tempQT{};
+
+ // Load quantization coefficients from JPG file, scale them for DCT and
+ // reorder from zig-zag order
+ if (mapping == 0)
+ {
+ switch (uvSelector)
+ {
+ case 0:
+ stdChrominanceQt = tbl000Y;
+ break;
+ case 1:
+ stdChrominanceQt = tbl014Y;
+ break;
+ case 2:
+ stdChrominanceQt = tbl029Y;
+ break;
+ case 3:
+ stdChrominanceQt = tbl043Y;
+ break;
+ case 4:
+ stdChrominanceQt = tbl057Y;
+ break;
+ case 5:
+ stdChrominanceQt = tbl071Y;
+ break;
+ case 6:
+ stdChrominanceQt = tbl086Y;
+ break;
+ case 7:
+ stdChrominanceQt = tbl100Y;
+ break;
+ }
+ }
+ else
+ {
+ switch (uvSelector)
+ {
+ case 0:
+ stdChrominanceQt = tbl000Uv;
+ break;
+ case 1:
+ stdChrominanceQt = tbl014Uv;
+ break;
+ case 2:
+ stdChrominanceQt = tbl029Uv;
+ break;
+ case 3:
+ stdChrominanceQt = tbl043Uv;
+ break;
+ case 4:
+ stdChrominanceQt = tbl057Uv;
+ break;
+ case 5:
+ stdChrominanceQt = tbl071Uv;
+ break;
+ case 6:
+ stdChrominanceQt = tbl086Uv;
+ break;
+ case 7:
+ stdChrominanceQt = tbl100Uv;
+ break;
+ }
+ }
+ setQuantTable(stdChrominanceQt, static_cast<uint8_t>(scalefactoruv),
+ tempQT);
+
+ for (j = 0; j <= 63; j++)
+ {
+ quant_table[j] = tempQT[zigzag[j]];
+ }
+ j = 0;
+ for (row = 0; row <= 7; row++)
+ {
+ for (col = 0; col <= 7; col++)
+ {
+ quant_table[j] = static_cast<long>(
+ (quant_table[j] * scalefactor[row] * scalefactor[col]) *
+ 65536);
+ j++;
+ }
+ }
+ bytePos += 64;
}
- // Note: pass ADVANCE SCALE FACTOR to sub-function in Dual-JPEG
- setQuantTable(stdChrominanceQt, static_cast<uint8_t>(advancescalefactoruv),
- tempQT);
+ // Note: Added for Dual_JPEG
+ void loadAdvanceQuantTable(std::array<long, 64> &quant_table)
+ {
+ float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
+ 1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
+ uint8_t j, row, col;
+ std::array<uint8_t, 64> tempQT{};
+
+ // Load quantization coefficients from JPG file, scale them for DCT and
+ // reorder
+ // from zig-zag order
+ switch (advanceSelector)
+ {
+ case 0:
+ stdLuminanceQt = tbl000Y;
+ break;
+ case 1:
+ stdLuminanceQt = tbl014Y;
+ break;
+ case 2:
+ stdLuminanceQt = tbl029Y;
+ break;
+ case 3:
+ stdLuminanceQt = tbl043Y;
+ break;
+ case 4:
+ stdLuminanceQt = tbl057Y;
+ break;
+ case 5:
+ stdLuminanceQt = tbl071Y;
+ break;
+ case 6:
+ stdLuminanceQt = tbl086Y;
+ break;
+ case 7:
+ stdLuminanceQt = tbl100Y;
+ break;
+ }
+ // Note: pass ADVANCE SCALE FACTOR to sub-function in Dual-JPEG
+ setQuantTable(stdLuminanceQt, static_cast<uint8_t>(advancescalefactor),
+ tempQT);
- for (j = 0; j <= 63; j++) {
- quant_table[j] = tempQT[zigzag[j]];
+ for (j = 0; j <= 63; j++)
+ {
+ quant_table[j] = tempQT[zigzag[j]];
+ }
+ j = 0;
+ for (row = 0; row <= 7; row++)
+ {
+ for (col = 0; col <= 7; col++)
+ {
+ quant_table[j] = static_cast<long>(
+ (quant_table[j] * scalefactor[row] * scalefactor[col]) *
+ 65536);
+ j++;
+ }
+ }
+ bytePos += 64;
}
- j = 0;
- for (row = 0; row <= 7; row++) {
- for (col = 0; col <= 7; col++) {
- quant_table[j] = static_cast<long>(
- (quant_table[j] * scalefactor[row] * scalefactor[col]) * 65536);
- j++;
- }
+
+ // Note: Added for Dual-JPEG
+ void loadAdvanceQuantTableCb(std::array<long, 64> &quant_table)
+ {
+ float scalefactor[8] = {1.0f, 1.387039845f, 1.306562965f, 1.175875602f,
+ 1.0f, 0.785694958f, 0.541196100f, 0.275899379f};
+ uint8_t j, row, col;
+ std::array<uint8_t, 64> tempQT{};
+
+ // Load quantization coefficients from JPG file, scale them for DCT and
+ // reorder
+ // from zig-zag order
+ if (mapping == 1)
+ {
+ switch (advanceSelector)
+ {
+ case 0:
+ stdChrominanceQt = tbl000Y;
+ break;
+ case 1:
+ stdChrominanceQt = tbl014Y;
+ break;
+ case 2:
+ stdChrominanceQt = tbl029Y;
+ break;
+ case 3:
+ stdChrominanceQt = tbl043Y;
+ break;
+ case 4:
+ stdChrominanceQt = tbl057Y;
+ break;
+ case 5:
+ stdChrominanceQt = tbl071Y;
+ break;
+ case 6:
+ stdChrominanceQt = tbl086Y;
+ break;
+ case 7:
+ stdChrominanceQt = tbl100Y;
+ break;
+ }
+ }
+ else
+ {
+ switch (advanceSelector)
+ {
+ case 0:
+ stdChrominanceQt = tbl000Uv;
+ break;
+ case 1:
+ stdChrominanceQt = tbl014Uv;
+ break;
+ case 2:
+ stdChrominanceQt = tbl029Uv;
+ break;
+ case 3:
+ stdChrominanceQt = tbl043Uv;
+ break;
+ case 4:
+ stdChrominanceQt = tbl057Uv;
+ break;
+ case 5:
+ stdChrominanceQt = tbl071Uv;
+ break;
+ case 6:
+ stdChrominanceQt = tbl086Uv;
+ break;
+ case 7:
+ stdChrominanceQt = tbl100Uv;
+ break;
+ }
+ }
+ // Note: pass ADVANCE SCALE FACTOR to sub-function in Dual-JPEG
+ setQuantTable(stdChrominanceQt,
+ static_cast<uint8_t>(advancescalefactoruv), tempQT);
+
+ for (j = 0; j <= 63; j++)
+ {
+ quant_table[j] = tempQT[zigzag[j]];
+ }
+ j = 0;
+ for (row = 0; row <= 7; row++)
+ {
+ for (col = 0; col <= 7; col++)
+ {
+ quant_table[j] = static_cast<long>(
+ (quant_table[j] * scalefactor[row] * scalefactor[col]) *
+ 65536);
+ j++;
+ }
+ }
+ bytePos += 64;
}
- bytePos += 64;
- }
- void idctTransform(short *coef, uint8_t *data, uint8_t nBlock) {
+ void idctTransform(short *coef, uint8_t *data, uint8_t nBlock)
+ {
#define FIX_1_082392200 ((int)277) /* FIX(1.082392200) */
#define FIX_1_414213562 ((int)362) /* FIX(1.414213562) */
#define FIX_1_847759065 ((int)473) /* FIX(1.847759065) */
@@ -347,1008 +392,1156 @@ class AstJpegDecoder {
#define MULTIPLY(var, cons) ((int)((var) * (cons)) >> 8)
- int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
- int tmp10, tmp11, tmp12, tmp13;
- int z5, z10, z11, z12, z13;
- int workspace[64]; /* buffers data between passes */
-
- short *inptr = coef;
- long *quantptr;
- int *wsptr = workspace;
- unsigned char *outptr;
- unsigned char *rLimit = rlimitTable + 128;
- int ctr, dcval, dctsize = 8;
-
- quantptr = &qt[nBlock][0];
-
- // Pass 1: process columns from input (inptr), store into work array(wsptr)
-
- for (ctr = 8; ctr > 0; ctr--) {
- /* Due to quantization, we will usually find that many of the input
- * coefficients are zero, especially the AC terms. We can exploit this
- * by short-circuiting the IDCT calculation for any column in which all
- * the AC terms are zero. In that case each output is equal to the
- * DC coefficient (with scale factor as needed).
- * With typical images and quantization tables, half or more of the
- * column DCT calculations can be simplified this way.
- */
-
- if ((inptr[dctsize * 1] | inptr[dctsize * 2] | inptr[dctsize * 3] |
- inptr[dctsize * 4] | inptr[dctsize * 5] | inptr[dctsize * 6] |
- inptr[dctsize * 7]) == 0) {
- /* AC terms all zero */
- dcval = static_cast<int>((inptr[dctsize * 0] * quantptr[dctsize * 0]) >>
- 16);
-
- wsptr[dctsize * 0] = dcval;
- wsptr[dctsize * 1] = dcval;
- wsptr[dctsize * 2] = dcval;
- wsptr[dctsize * 3] = dcval;
- wsptr[dctsize * 4] = dcval;
- wsptr[dctsize * 5] = dcval;
- wsptr[dctsize * 6] = dcval;
- wsptr[dctsize * 7] = dcval;
-
- inptr++; /* advance pointers to next column */
- quantptr++;
- wsptr++;
- continue;
- }
-
- /* Even part */
-
- tmp0 = (inptr[dctsize * 0] * quantptr[dctsize * 0]) >> 16;
- tmp1 = (inptr[dctsize * 2] * quantptr[dctsize * 2]) >> 16;
- tmp2 = (inptr[dctsize * 4] * quantptr[dctsize * 4]) >> 16;
- tmp3 = (inptr[dctsize * 6] * quantptr[dctsize * 6]) >> 16;
-
- tmp10 = tmp0 + tmp2; /* phase 3 */
- tmp11 = tmp0 - tmp2;
-
- tmp13 = tmp1 + tmp3; /* phases 5-3 */
- tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */
-
- tmp0 = tmp10 + tmp13; /* phase 2 */
- tmp3 = tmp10 - tmp13;
- tmp1 = tmp11 + tmp12;
- tmp2 = tmp11 - tmp12;
-
- /* Odd part */
-
- tmp4 = (inptr[dctsize * 1] * quantptr[dctsize * 1]) >> 16;
- tmp5 = (inptr[dctsize * 3] * quantptr[dctsize * 3]) >> 16;
- tmp6 = (inptr[dctsize * 5] * quantptr[dctsize * 5]) >> 16;
- tmp7 = (inptr[dctsize * 7] * quantptr[dctsize * 7]) >> 16;
-
- z13 = tmp6 + tmp5; /* phase 6 */
- z10 = tmp6 - tmp5;
- z11 = tmp4 + tmp7;
- z12 = tmp4 - tmp7;
-
- tmp7 = z11 + z13; /* phase 5 */
- tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
-
- z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */
- tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */
- tmp12 = MULTIPLY(z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */
-
- tmp6 = tmp12 - tmp7; /* phase 2 */
- tmp5 = tmp11 - tmp6;
- tmp4 = tmp10 + tmp5;
-
- wsptr[dctsize * 0] = (tmp0 + tmp7);
- wsptr[dctsize * 7] = (tmp0 - tmp7);
- wsptr[dctsize * 1] = (tmp1 + tmp6);
- wsptr[dctsize * 6] = (tmp1 - tmp6);
- wsptr[dctsize * 2] = (tmp2 + tmp5);
- wsptr[dctsize * 5] = (tmp2 - tmp5);
- wsptr[dctsize * 4] = (tmp3 + tmp4);
- wsptr[dctsize * 3] = (tmp3 - tmp4);
-
- inptr++; /* advance pointers to next column */
- quantptr++;
- wsptr++;
- }
+ int tmp0, tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7;
+ int tmp10, tmp11, tmp12, tmp13;
+ int z5, z10, z11, z12, z13;
+ int workspace[64]; /* buffers data between passes */
+
+ short *inptr = coef;
+ long *quantptr;
+ int *wsptr = workspace;
+ unsigned char *outptr;
+ unsigned char *rLimit = rlimitTable + 128;
+ int ctr, dcval, dctsize = 8;
+
+ quantptr = &qt[nBlock][0];
+
+ // Pass 1: process columns from input (inptr), store into work
+ // array(wsptr)
+
+ for (ctr = 8; ctr > 0; ctr--)
+ {
+ /* Due to quantization, we will usually find that many of the input
+ * coefficients are zero, especially the AC terms. We can exploit
+ * this by short-circuiting the IDCT calculation for any column in
+ * which all the AC terms are zero. In that case each output is
+ * equal to the DC coefficient (with scale factor as needed). With
+ * typical images and quantization tables, half or more of the
+ * column DCT calculations can be simplified this way.
+ */
+
+ if ((inptr[dctsize * 1] | inptr[dctsize * 2] | inptr[dctsize * 3] |
+ inptr[dctsize * 4] | inptr[dctsize * 5] | inptr[dctsize * 6] |
+ inptr[dctsize * 7]) == 0)
+ {
+ /* AC terms all zero */
+ dcval = static_cast<int>(
+ (inptr[dctsize * 0] * quantptr[dctsize * 0]) >> 16);
+
+ wsptr[dctsize * 0] = dcval;
+ wsptr[dctsize * 1] = dcval;
+ wsptr[dctsize * 2] = dcval;
+ wsptr[dctsize * 3] = dcval;
+ wsptr[dctsize * 4] = dcval;
+ wsptr[dctsize * 5] = dcval;
+ wsptr[dctsize * 6] = dcval;
+ wsptr[dctsize * 7] = dcval;
+
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ continue;
+ }
-/* Pass 2: process rows from work array, store into output array. */
-/* Note that we must descale the results by a factor of 8 == 2**3, */
-/* and also undo the PASS1_BITS scaling. */
+ /* Even part */
-//#define RANGE_MASK 1023; //2 bits wider than legal samples
-#define PASS1_BITS 0
-#define IDESCALE(x, n) ((int)((x) >> (n)))
+ tmp0 = (inptr[dctsize * 0] * quantptr[dctsize * 0]) >> 16;
+ tmp1 = (inptr[dctsize * 2] * quantptr[dctsize * 2]) >> 16;
+ tmp2 = (inptr[dctsize * 4] * quantptr[dctsize * 4]) >> 16;
+ tmp3 = (inptr[dctsize * 6] * quantptr[dctsize * 6]) >> 16;
- wsptr = workspace;
- for (ctr = 0; ctr < dctsize; ctr++) {
- outptr = data + ctr * 8;
+ tmp10 = tmp0 + tmp2; /* phase 3 */
+ tmp11 = tmp0 - tmp2;
- /* Rows of zeroes can be exploited in the same way as we did with columns.
- * However, the column calculation has created many nonzero AC terms, so
- * the simplification applies less often (typically 5% to 10% of the
- * time). On machines with very fast multiplication, it's possible that
- * the test takes more time than it's worth. In that case this section
- * may be commented out.
- */
- /* Even part */
+ tmp13 = tmp1 + tmp3; /* phases 5-3 */
+ tmp12 = MULTIPLY(tmp1 - tmp3, FIX_1_414213562) - tmp13; /* 2*c4 */
- tmp10 = (wsptr[0] + wsptr[4]);
- tmp11 = (wsptr[0] - wsptr[4]);
+ tmp0 = tmp10 + tmp13; /* phase 2 */
+ tmp3 = tmp10 - tmp13;
+ tmp1 = tmp11 + tmp12;
+ tmp2 = tmp11 - tmp12;
- tmp13 = (wsptr[2] + wsptr[6]);
- tmp12 = MULTIPLY((int)wsptr[2] - (int)wsptr[6], FIX_1_414213562) - tmp13;
+ /* Odd part */
- tmp0 = tmp10 + tmp13;
- tmp3 = tmp10 - tmp13;
- tmp1 = tmp11 + tmp12;
- tmp2 = tmp11 - tmp12;
+ tmp4 = (inptr[dctsize * 1] * quantptr[dctsize * 1]) >> 16;
+ tmp5 = (inptr[dctsize * 3] * quantptr[dctsize * 3]) >> 16;
+ tmp6 = (inptr[dctsize * 5] * quantptr[dctsize * 5]) >> 16;
+ tmp7 = (inptr[dctsize * 7] * quantptr[dctsize * 7]) >> 16;
- /* Odd part */
+ z13 = tmp6 + tmp5; /* phase 6 */
+ z10 = tmp6 - tmp5;
+ z11 = tmp4 + tmp7;
+ z12 = tmp4 - tmp7;
- z13 = wsptr[5] + wsptr[3];
- z10 = wsptr[5] - wsptr[3];
- z11 = wsptr[1] + wsptr[7];
- z12 = wsptr[1] - wsptr[7];
+ tmp7 = z11 + z13; /* phase 5 */
+ tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
- tmp7 = z11 + z13; /* phase 5 */
- tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
+ z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */
+ tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */
+ tmp12 = MULTIPLY(z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */
- z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */
- tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */
- tmp12 = MULTIPLY(z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */
+ tmp6 = tmp12 - tmp7; /* phase 2 */
+ tmp5 = tmp11 - tmp6;
+ tmp4 = tmp10 + tmp5;
- tmp6 = tmp12 - tmp7; /* phase 2 */
- tmp5 = tmp11 - tmp6;
- tmp4 = tmp10 + tmp5;
+ wsptr[dctsize * 0] = (tmp0 + tmp7);
+ wsptr[dctsize * 7] = (tmp0 - tmp7);
+ wsptr[dctsize * 1] = (tmp1 + tmp6);
+ wsptr[dctsize * 6] = (tmp1 - tmp6);
+ wsptr[dctsize * 2] = (tmp2 + tmp5);
+ wsptr[dctsize * 5] = (tmp2 - tmp5);
+ wsptr[dctsize * 4] = (tmp3 + tmp4);
+ wsptr[dctsize * 3] = (tmp3 - tmp4);
- /* Final output stage: scale down by a factor of 8 and range-limit */
+ inptr++; /* advance pointers to next column */
+ quantptr++;
+ wsptr++;
+ }
- outptr[0] = rLimit[IDESCALE((tmp0 + tmp7), (PASS1_BITS + 3)) & 1023L];
- outptr[7] = rLimit[IDESCALE((tmp0 - tmp7), (PASS1_BITS + 3)) & 1023L];
- outptr[1] = rLimit[IDESCALE((tmp1 + tmp6), (PASS1_BITS + 3)) & 1023L];
- outptr[6] = rLimit[IDESCALE((tmp1 - tmp6), (PASS1_BITS + 3)) & 1023L];
- outptr[2] = rLimit[IDESCALE((tmp2 + tmp5), (PASS1_BITS + 3)) & 1023L];
- outptr[5] = rLimit[IDESCALE((tmp2 - tmp5), (PASS1_BITS + 3)) & 1023L];
- outptr[4] = rLimit[IDESCALE((tmp3 + tmp4), (PASS1_BITS + 3)) & 1023L];
- outptr[3] = rLimit[IDESCALE((tmp3 - tmp4), (PASS1_BITS + 3)) & 1023L];
+/* Pass 2: process rows from work array, store into output array. */
+/* Note that we must descale the results by a factor of 8 == 2**3, */
+/* and also undo the PASS1_BITS scaling. */
+
+//#define RANGE_MASK 1023; //2 bits wider than legal samples
+#define PASS1_BITS 0
+#define IDESCALE(x, n) ((int)((x) >> (n)))
- wsptr += dctsize; /* advance pointer to next row */
+ wsptr = workspace;
+ for (ctr = 0; ctr < dctsize; ctr++)
+ {
+ outptr = data + ctr * 8;
+
+ /* Rows of zeroes can be exploited in the same way as we did with
+ * columns. However, the column calculation has created many nonzero
+ * AC terms, so the simplification applies less often (typically 5%
+ * to 10% of the time). On machines with very fast multiplication,
+ * it's possible that the test takes more time than it's worth. In
+ * that case this section may be commented out.
+ */
+ /* Even part */
+
+ tmp10 = (wsptr[0] + wsptr[4]);
+ tmp11 = (wsptr[0] - wsptr[4]);
+
+ tmp13 = (wsptr[2] + wsptr[6]);
+ tmp12 = MULTIPLY((int)wsptr[2] - (int)wsptr[6], FIX_1_414213562) -
+ tmp13;
+
+ tmp0 = tmp10 + tmp13;
+ tmp3 = tmp10 - tmp13;
+ tmp1 = tmp11 + tmp12;
+ tmp2 = tmp11 - tmp12;
+
+ /* Odd part */
+
+ z13 = wsptr[5] + wsptr[3];
+ z10 = wsptr[5] - wsptr[3];
+ z11 = wsptr[1] + wsptr[7];
+ z12 = wsptr[1] - wsptr[7];
+
+ tmp7 = z11 + z13; /* phase 5 */
+ tmp11 = MULTIPLY(z11 - z13, FIX_1_414213562); /* 2*c4 */
+
+ z5 = MULTIPLY(z10 + z12, FIX_1_847759065); /* 2*c2 */
+ tmp10 = MULTIPLY(z12, FIX_1_082392200) - z5; /* 2*(c2-c6) */
+ tmp12 = MULTIPLY(z10, -FIX_2_613125930) + z5; /* -2*(c2+c6) */
+
+ tmp6 = tmp12 - tmp7; /* phase 2 */
+ tmp5 = tmp11 - tmp6;
+ tmp4 = tmp10 + tmp5;
+
+ /* Final output stage: scale down by a factor of 8 and range-limit
+ */
+
+ outptr[0] =
+ rLimit[IDESCALE((tmp0 + tmp7), (PASS1_BITS + 3)) & 1023L];
+ outptr[7] =
+ rLimit[IDESCALE((tmp0 - tmp7), (PASS1_BITS + 3)) & 1023L];
+ outptr[1] =
+ rLimit[IDESCALE((tmp1 + tmp6), (PASS1_BITS + 3)) & 1023L];
+ outptr[6] =
+ rLimit[IDESCALE((tmp1 - tmp6), (PASS1_BITS + 3)) & 1023L];
+ outptr[2] =
+ rLimit[IDESCALE((tmp2 + tmp5), (PASS1_BITS + 3)) & 1023L];
+ outptr[5] =
+ rLimit[IDESCALE((tmp2 - tmp5), (PASS1_BITS + 3)) & 1023L];
+ outptr[4] =
+ rLimit[IDESCALE((tmp3 + tmp4), (PASS1_BITS + 3)) & 1023L];
+ outptr[3] =
+ rLimit[IDESCALE((tmp3 - tmp4), (PASS1_BITS + 3)) & 1023L];
+
+ wsptr += dctsize; /* advance pointer to next row */
+ }
}
- }
- void yuvToRgb(
- int txb, int tyb,
- unsigned char
- *pYCbCr, // in, Y: 256 or 64 bytes; Cb: 64 bytes; Cr: 64 bytes
- struct RGB *pYUV, // in, Y: 256 or 64 bytes; Cb: 64 bytes; Cr: 64 bytes
- unsigned char
- *pBgr // out, BGR format, 16*16*3 = 768 bytes; or 8*8*3=192 bytes
- ) {
- int i, j, pos, m, n;
- unsigned char cb, cr, *py, *pcb, *pcr, *py420[4];
- int y;
- struct RGB *pByte;
- int nBlocksInMcu = 6;
- unsigned int pixelX, pixelY;
-
- pByte = reinterpret_cast<struct RGB *>(pBgr);
- if (yuvmode == YuvMode::YUV444) {
- py = pYCbCr;
- pcb = pYCbCr + 64;
- pcr = pcb + 64;
-
- pixelX = txb * 8;
- pixelY = tyb * 8;
- pos = (pixelY * width) + pixelX;
-
- for (j = 0; j < 8; j++) {
- for (i = 0; i < 8; i++) {
- m = ((j << 3) + i);
- y = py[m];
- cb = pcb[m];
- cr = pcr[m];
- n = pos + i;
- // For 2Pass. Save the YUV value
- pYUV[n].b = cb;
- pYUV[n].g = y;
- pYUV[n].r = cr;
- pByte[n].b = rlimitTable[mY[y] + mCbToB[cb]];
- pByte[n].g = rlimitTable[mY[y] + mCbToG[cb] + mCrToG[cr]];
- pByte[n].r = rlimitTable[mY[y] + mCrToR[cr]];
+ void yuvToRgb(
+ int txb, int tyb,
+ unsigned char
+ *pYCbCr, // in, Y: 256 or 64 bytes; Cb: 64 bytes; Cr: 64 bytes
+ struct RGB *pYUV, // in, Y: 256 or 64 bytes; Cb: 64 bytes; Cr: 64 bytes
+ unsigned char
+ *pBgr // out, BGR format, 16*16*3 = 768 bytes; or 8*8*3=192 bytes
+ )
+ {
+ int i, j, pos, m, n;
+ unsigned char cb, cr, *py, *pcb, *pcr, *py420[4];
+ int y;
+ struct RGB *pByte;
+ int nBlocksInMcu = 6;
+ unsigned int pixelX, pixelY;
+
+ pByte = reinterpret_cast<struct RGB *>(pBgr);
+ if (yuvmode == YuvMode::YUV444)
+ {
+ py = pYCbCr;
+ pcb = pYCbCr + 64;
+ pcr = pcb + 64;
+
+ pixelX = txb * 8;
+ pixelY = tyb * 8;
+ pos = (pixelY * width) + pixelX;
+
+ for (j = 0; j < 8; j++)
+ {
+ for (i = 0; i < 8; i++)
+ {
+ m = ((j << 3) + i);
+ y = py[m];
+ cb = pcb[m];
+ cr = pcr[m];
+ n = pos + i;
+ // For 2Pass. Save the YUV value
+ pYUV[n].b = cb;
+ pYUV[n].g = y;
+ pYUV[n].r = cr;
+ pByte[n].b = rlimitTable[mY[y] + mCbToB[cb]];
+ pByte[n].g = rlimitTable[mY[y] + mCbToG[cb] + mCrToG[cr]];
+ pByte[n].r = rlimitTable[mY[y] + mCrToR[cr]];
+ }
+ pos += width;
+ }
}
- pos += width;
- }
- } else {
- for (i = 0; i < nBlocksInMcu - 2; i++) {
- py420[i] = pYCbCr + i * 64;
- }
- pcb = pYCbCr + (nBlocksInMcu - 2) * 64;
- pcr = pcb + 64;
-
- pixelX = txb * 16;
- pixelY = tyb * 16;
- pos = (pixelY * width) + pixelX;
-
- for (j = 0; j < 16; j++) {
- for (i = 0; i < 16; i++) {
- // block number is ((j/8) * 2 + i/8)={0, 1, 2, 3}
- y = *(py420[(j >> 3) * 2 + (i >> 3)]++);
- m = ((j >> 1) << 3) + (i >> 1);
- cb = pcb[m];
- cr = pcr[m];
- n = pos + i;
- pByte[n].b = rlimitTable[mY[y] + mCbToB[cb]];
- pByte[n].g = rlimitTable[mY[y] + mCbToG[cb] + mCrToG[cr]];
- pByte[n].r = rlimitTable[mY[y] + mCrToR[cr]];
+ else
+ {
+ for (i = 0; i < nBlocksInMcu - 2; i++)
+ {
+ py420[i] = pYCbCr + i * 64;
+ }
+ pcb = pYCbCr + (nBlocksInMcu - 2) * 64;
+ pcr = pcb + 64;
+
+ pixelX = txb * 16;
+ pixelY = tyb * 16;
+ pos = (pixelY * width) + pixelX;
+
+ for (j = 0; j < 16; j++)
+ {
+ for (i = 0; i < 16; i++)
+ {
+ // block number is ((j/8) * 2 + i/8)={0, 1, 2, 3}
+ y = *(py420[(j >> 3) * 2 + (i >> 3)]++);
+ m = ((j >> 1) << 3) + (i >> 1);
+ cb = pcb[m];
+ cr = pcr[m];
+ n = pos + i;
+ pByte[n].b = rlimitTable[mY[y] + mCbToB[cb]];
+ pByte[n].g = rlimitTable[mY[y] + mCbToG[cb] + mCrToG[cr]];
+ pByte[n].r = rlimitTable[mY[y] + mCrToR[cr]];
+ }
+ pos += width;
+ }
}
- pos += width;
- }
}
- }
- void yuvToBuffer(
- int txb, int tyb,
- unsigned char
- *pYCbCr, // in, Y: 256 or 64 bytes; Cb: 64 bytes; Cr: 64 bytes
- struct RGB
- *pYUV, // out, BGR format, 16*16*3 = 768 bytes; or 8*8*3=192 bytes
- unsigned char
- *pBgr // out, BGR format, 16*16*3 = 768 bytes; or 8*8*3=192 bytes
- ) {
- int i, j, pos, m, n;
- unsigned char cb, cr, *py, *pcb, *pcr, *py420[4];
- int y;
- struct RGB *pByte;
- int nBlocksInMcu = 6;
- unsigned int pixelX, pixelY;
-
- pByte = reinterpret_cast<struct RGB *>(pBgr);
- if (yuvmode == YuvMode::YUV444) {
- py = pYCbCr;
- pcb = pYCbCr + 64;
- pcr = pcb + 64;
-
- pixelX = txb * 8;
- pixelY = tyb * 8;
- pos = (pixelY * width) + pixelX;
-
- for (j = 0; j < 8; j++) {
- for (i = 0; i < 8; i++) {
- m = ((j << 3) + i);
- n = pos + i;
- y = pYUV[n].g + (py[m] - 128);
- cb = pYUV[n].b + (pcb[m] - 128);
- cr = pYUV[n].r + (pcr[m] - 128);
- pYUV[n].b = cb;
- pYUV[n].g = y;
- pYUV[n].r = cr;
- pByte[n].b = rlimitTable[mY[y] + mCbToB[cb]];
- pByte[n].g = rlimitTable[mY[y] + mCbToG[cb] + mCrToG[cr]];
- pByte[n].r = rlimitTable[mY[y] + mCrToR[cr]];
+ void yuvToBuffer(
+ int txb, int tyb,
+ unsigned char
+ *pYCbCr, // in, Y: 256 or 64 bytes; Cb: 64 bytes; Cr: 64 bytes
+ struct RGB
+ *pYUV, // out, BGR format, 16*16*3 = 768 bytes; or 8*8*3=192 bytes
+ unsigned char
+ *pBgr // out, BGR format, 16*16*3 = 768 bytes; or 8*8*3=192 bytes
+ )
+ {
+ int i, j, pos, m, n;
+ unsigned char cb, cr, *py, *pcb, *pcr, *py420[4];
+ int y;
+ struct RGB *pByte;
+ int nBlocksInMcu = 6;
+ unsigned int pixelX, pixelY;
+
+ pByte = reinterpret_cast<struct RGB *>(pBgr);
+ if (yuvmode == YuvMode::YUV444)
+ {
+ py = pYCbCr;
+ pcb = pYCbCr + 64;
+ pcr = pcb + 64;
+
+ pixelX = txb * 8;
+ pixelY = tyb * 8;
+ pos = (pixelY * width) + pixelX;
+
+ for (j = 0; j < 8; j++)
+ {
+ for (i = 0; i < 8; i++)
+ {
+ m = ((j << 3) + i);
+ n = pos + i;
+ y = pYUV[n].g + (py[m] - 128);
+ cb = pYUV[n].b + (pcb[m] - 128);
+ cr = pYUV[n].r + (pcr[m] - 128);
+ pYUV[n].b = cb;
+ pYUV[n].g = y;
+ pYUV[n].r = cr;
+ pByte[n].b = rlimitTable[mY[y] + mCbToB[cb]];
+ pByte[n].g = rlimitTable[mY[y] + mCbToG[cb] + mCrToG[cr]];
+ pByte[n].r = rlimitTable[mY[y] + mCrToR[cr]];
+ }
+ pos += width;
+ }
}
- pos += width;
- }
- } else {
- for (i = 0; i < nBlocksInMcu - 2; i++) {
- py420[i] = pYCbCr + i * 64;
- }
- pcb = pYCbCr + (nBlocksInMcu - 2) * 64;
- pcr = pcb + 64;
-
- pixelX = txb * 16;
- pixelY = tyb * 16;
- pos = (pixelY * width) + pixelX;
-
- for (j = 0; j < 16; j++) {
- for (i = 0; i < 16; i++) {
- // block number is ((j/8) * 2 + i/8)={0, 1, 2, 3}
- y = *(py420[(j >> 3) * 2 + (i >> 3)]++);
- m = ((j >> 1) << 3) + (i >> 1);
- cb = pcb[m];
- cr = pcr[m];
- n = pos + i;
- pByte[n].b = rlimitTable[mY[y] + mCbToB[cb]];
- pByte[n].g = rlimitTable[mY[y] + mCbToG[cb] + mCrToG[cr]];
- pByte[n].r = rlimitTable[mY[y] + mCrToR[cr]];
+ else
+ {
+ for (i = 0; i < nBlocksInMcu - 2; i++)
+ {
+ py420[i] = pYCbCr + i * 64;
+ }
+ pcb = pYCbCr + (nBlocksInMcu - 2) * 64;
+ pcr = pcb + 64;
+
+ pixelX = txb * 16;
+ pixelY = tyb * 16;
+ pos = (pixelY * width) + pixelX;
+
+ for (j = 0; j < 16; j++)
+ {
+ for (i = 0; i < 16; i++)
+ {
+ // block number is ((j/8) * 2 + i/8)={0, 1, 2, 3}
+ y = *(py420[(j >> 3) * 2 + (i >> 3)]++);
+ m = ((j >> 1) << 3) + (i >> 1);
+ cb = pcb[m];
+ cr = pcr[m];
+ n = pos + i;
+ pByte[n].b = rlimitTable[mY[y] + mCbToB[cb]];
+ pByte[n].g = rlimitTable[mY[y] + mCbToG[cb] + mCrToG[cr]];
+ pByte[n].r = rlimitTable[mY[y] + mCrToR[cr]];
+ }
+ pos += width;
+ }
}
- pos += width;
- }
}
- }
- void decompress(int txb, int tyb, char *outBuf, uint8_t QT_TableSelection) {
- unsigned char *ptr;
- unsigned char byTileYuv[768] = {};
-
- memset(dctCoeff, 0, 384 * 2);
- ptr = byTileYuv;
- processHuffmanDataUnit(ydcNr, yacNr, &dcy, 0);
- idctTransform(dctCoeff, ptr, QT_TableSelection);
- ptr += 64;
-
- if (yuvmode == YuvMode::YUV420) {
- processHuffmanDataUnit(ydcNr, yacNr, &dcy, 64);
- idctTransform(dctCoeff + 64, ptr, QT_TableSelection);
- ptr += 64;
-
- processHuffmanDataUnit(ydcNr, yacNr, &dcy, 128);
- idctTransform(dctCoeff + 128, ptr, QT_TableSelection);
- ptr += 64;
-
- processHuffmanDataUnit(ydcNr, yacNr, &dcy, 192);
- idctTransform(dctCoeff + 192, ptr, QT_TableSelection);
- ptr += 64;
-
- processHuffmanDataUnit(cbDcNr, cbAcNr, &dcCb, 256);
- idctTransform(dctCoeff + 256, ptr, QT_TableSelection + 1);
- ptr += 64;
-
- processHuffmanDataUnit(crDcNr, crAcNr, &dcCr, 320);
- idctTransform(dctCoeff + 320, ptr, QT_TableSelection + 1);
- } else {
- processHuffmanDataUnit(cbDcNr, cbAcNr, &dcCb, 64);
- idctTransform(dctCoeff + 64, ptr, QT_TableSelection + 1);
- ptr += 64;
-
- processHuffmanDataUnit(crDcNr, crAcNr, &dcCr, 128);
- idctTransform(dctCoeff + 128, ptr, QT_TableSelection + 1);
- }
-
- // yuvToRgb (txb, tyb, byTileYuv, (unsigned char *)outBuf);
- // yuvBuffer for YUV record
- yuvToRgb(txb, tyb, byTileYuv, yuvBuffer.data(),
- reinterpret_cast<unsigned char *>(outBuf));
- }
-
- void decompress2Pass(int txb, int tyb, char *outBuf,
- uint8_t QT_TableSelection) {
- unsigned char *ptr;
- unsigned char byTileYuv[768];
- memset(dctCoeff, 0, 384 * 2);
-
- ptr = byTileYuv;
- processHuffmanDataUnit(ydcNr, yacNr, &dcy, 0);
- idctTransform(dctCoeff, ptr, QT_TableSelection);
- ptr += 64;
-
- processHuffmanDataUnit(cbDcNr, cbAcNr, &dcCb, 64);
- idctTransform(dctCoeff + 64, ptr, QT_TableSelection + 1);
- ptr += 64;
-
- processHuffmanDataUnit(crDcNr, crAcNr, &dcCr, 128);
- idctTransform(dctCoeff + 128, ptr, QT_TableSelection + 1);
-
- yuvToBuffer(txb, tyb, byTileYuv, yuvBuffer.data(),
- reinterpret_cast<unsigned char *>(outBuf));
- // yuvToRgb (txb, tyb, byTileYuv, (unsigned char *)outBuf);
- }
-
- void vqDecompress(int txb, int tyb, char *outBuf, uint8_t QT_TableSelection,
- struct ColorCache *VQ) {
- unsigned char *ptr, i;
- unsigned char byTileYuv[192];
- int data;
-
- ptr = byTileYuv;
- if (VQ->bitMapBits == 0) {
- for (i = 0; i < 64; i++) {
- ptr[0] = (VQ->color[VQ->index[0]] & 0xFF0000) >> 16;
- ptr[64] = (VQ->color[VQ->index[0]] & 0x00FF00) >> 8;
- ptr[128] = VQ->color[VQ->index[0]] & 0x0000FF;
- ptr += 1;
- }
- } else {
- for (i = 0; i < 64; i++) {
- data = static_cast<int>(lookKbits(VQ->bitMapBits));
- ptr[0] = (VQ->color[VQ->index[data]] & 0xFF0000) >> 16;
- ptr[64] = (VQ->color[VQ->index[data]] & 0x00FF00) >> 8;
- ptr[128] = VQ->color[VQ->index[data]] & 0x0000FF;
- ptr += 1;
- skipKbits(VQ->bitMapBits);
- }
- }
- // yuvToRgb (txb, tyb, byTileYuv, (unsigned char *)outBuf);
- yuvToRgb(txb, tyb, byTileYuv, yuvBuffer.data(),
- reinterpret_cast<unsigned char *>(outBuf));
- }
-
- void moveBlockIndex() {
- if (yuvmode == YuvMode::YUV444) {
- txb++;
- if (txb >= static_cast<int>(width / 8)) {
- tyb++;
- if (tyb >= static_cast<int>(height / 8)) {
- tyb = 0;
+ void decompress(int txb, int tyb, char *outBuf, uint8_t QT_TableSelection)
+ {
+ unsigned char *ptr;
+ unsigned char byTileYuv[768] = {};
+
+ memset(dctCoeff, 0, 384 * 2);
+ ptr = byTileYuv;
+ processHuffmanDataUnit(ydcNr, yacNr, &dcy, 0);
+ idctTransform(dctCoeff, ptr, QT_TableSelection);
+ ptr += 64;
+
+ if (yuvmode == YuvMode::YUV420)
+ {
+ processHuffmanDataUnit(ydcNr, yacNr, &dcy, 64);
+ idctTransform(dctCoeff + 64, ptr, QT_TableSelection);
+ ptr += 64;
+
+ processHuffmanDataUnit(ydcNr, yacNr, &dcy, 128);
+ idctTransform(dctCoeff + 128, ptr, QT_TableSelection);
+ ptr += 64;
+
+ processHuffmanDataUnit(ydcNr, yacNr, &dcy, 192);
+ idctTransform(dctCoeff + 192, ptr, QT_TableSelection);
+ ptr += 64;
+
+ processHuffmanDataUnit(cbDcNr, cbAcNr, &dcCb, 256);
+ idctTransform(dctCoeff + 256, ptr, QT_TableSelection + 1);
+ ptr += 64;
+
+ processHuffmanDataUnit(crDcNr, crAcNr, &dcCr, 320);
+ idctTransform(dctCoeff + 320, ptr, QT_TableSelection + 1);
}
- txb = 0;
- }
- } else {
- txb++;
- if (txb >= static_cast<int>(width / 16)) {
- tyb++;
- if (tyb >= static_cast<int>(height / 16)) {
- tyb = 0;
+ else
+ {
+ processHuffmanDataUnit(cbDcNr, cbAcNr, &dcCb, 64);
+ idctTransform(dctCoeff + 64, ptr, QT_TableSelection + 1);
+ ptr += 64;
+
+ processHuffmanDataUnit(crDcNr, crAcNr, &dcCr, 128);
+ idctTransform(dctCoeff + 128, ptr, QT_TableSelection + 1);
}
- txb = 0;
- }
+
+ // yuvToRgb (txb, tyb, byTileYuv, (unsigned char *)outBuf);
+ // yuvBuffer for YUV record
+ yuvToRgb(txb, tyb, byTileYuv, yuvBuffer.data(),
+ reinterpret_cast<unsigned char *>(outBuf));
}
- }
- void initColorTable() {
- int i, x;
- int nScale = 1L << 16; // equal to power(2,16)
- int nHalf = nScale >> 1;
+ void decompress2Pass(int txb, int tyb, char *outBuf,
+ uint8_t QT_TableSelection)
+ {
+ unsigned char *ptr;
+ unsigned char byTileYuv[768];
+ memset(dctCoeff, 0, 384 * 2);
-#define FIX(x) ((int)((x)*nScale + 0.5))
+ ptr = byTileYuv;
+ processHuffmanDataUnit(ydcNr, yacNr, &dcy, 0);
+ idctTransform(dctCoeff, ptr, QT_TableSelection);
+ ptr += 64;
- /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
- /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
- /* Cr=>r value is nearest int to 1.597656 * x */
- /* Cb=>b value is nearest int to 2.015625 * x */
- /* Cr=>g value is scaled-up -0.8125 * x */
- /* Cb=>g value is scaled-up -0.390625 * x */
- for (i = 0, x = -128; i < 256; i++, x++) {
- mCrToR[i] = (FIX(1.597656) * x + nHalf) >> 16;
- mCbToB[i] = (FIX(2.015625) * x + nHalf) >> 16;
- mCrToG[i] = (-FIX(0.8125) * x + nHalf) >> 16;
- mCbToG[i] = (-FIX(0.390625) * x + nHalf) >> 16;
- }
- for (i = 0, x = -16; i < 256; i++, x++) {
- mY[i] = (FIX(1.164) * x + nHalf) >> 16;
+ processHuffmanDataUnit(cbDcNr, cbAcNr, &dcCb, 64);
+ idctTransform(dctCoeff + 64, ptr, QT_TableSelection + 1);
+ ptr += 64;
+
+ processHuffmanDataUnit(crDcNr, crAcNr, &dcCr, 128);
+ idctTransform(dctCoeff + 128, ptr, QT_TableSelection + 1);
+
+ yuvToBuffer(txb, tyb, byTileYuv, yuvBuffer.data(),
+ reinterpret_cast<unsigned char *>(outBuf));
+ // yuvToRgb (txb, tyb, byTileYuv, (unsigned char *)outBuf);
}
- // For color Text Enchance Y Re-map. Recommend to disable in default
- /*
- for (i = 0; i < (VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate);
- i++) {
- temp = (double)i /
- VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate;
- temp1 = 1.0 / VideoEngineInfo->INFData.Gamma1Parameter;
- mY[i] =
- (BYTE)(VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate * pow (temp,
- temp1));
- if (mY[i] > 255) mY[i] = 255;
+
+ void vqDecompress(int txb, int tyb, char *outBuf, uint8_t QT_TableSelection,
+ struct ColorCache *VQ)
+ {
+ unsigned char *ptr, i;
+ unsigned char byTileYuv[192];
+ int data;
+
+ ptr = byTileYuv;
+ if (VQ->bitMapBits == 0)
+ {
+ for (i = 0; i < 64; i++)
+ {
+ ptr[0] = (VQ->color[VQ->index[0]] & 0xFF0000) >> 16;
+ ptr[64] = (VQ->color[VQ->index[0]] & 0x00FF00) >> 8;
+ ptr[128] = VQ->color[VQ->index[0]] & 0x0000FF;
+ ptr += 1;
}
- for (i = (VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate); i < 256;
- i++) {
- mY[i] =
- (BYTE)((VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate) + (256 -
- VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate) * ( pow((double)((i -
- VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate) / (256 -
- (VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate))), (1.0 /
- VideoEngineInfo->INFData.Gamma2Parameter)) ));
- if (mY[i] > 255) mY[i] = 255;
+ }
+ else
+ {
+ for (i = 0; i < 64; i++)
+ {
+ data = static_cast<int>(lookKbits(VQ->bitMapBits));
+ ptr[0] = (VQ->color[VQ->index[data]] & 0xFF0000) >> 16;
+ ptr[64] = (VQ->color[VQ->index[data]] & 0x00FF00) >> 8;
+ ptr[128] = VQ->color[VQ->index[data]] & 0x0000FF;
+ ptr += 1;
+ skipKbits(VQ->bitMapBits);
}
- */
- }
- void loadHuffmanTable(HuffmanTable *HT, const unsigned char *nrcode,
- const unsigned char *value,
- const unsigned short int *Huff_code) {
- unsigned char k, j, i;
- unsigned int code, codeIndex;
-
- for (j = 1; j <= 16; j++) {
- HT->length[j] = nrcode[j];
- }
- for (i = 0, k = 1; k <= 16; k++) {
- for (j = 0; j < HT->length[k]; j++) {
- HT->v[wordHiLo(k, j)] = value[i];
- i++;
- }
+ }
+ // yuvToRgb (txb, tyb, byTileYuv, (unsigned char *)outBuf);
+ yuvToRgb(txb, tyb, byTileYuv, yuvBuffer.data(),
+ reinterpret_cast<unsigned char *>(outBuf));
}
- code = 0;
- for (k = 1; k <= 16; k++) {
- HT->minorCode[k] = static_cast<unsigned short int>(code);
- for (j = 1; j <= HT->length[k]; j++) {
- code++;
- }
- HT->majorCode[k] = static_cast<unsigned short int>(code - 1);
- code *= 2;
- if (HT->length[k] == 0) {
- HT->minorCode[k] = 0xFFFF;
- HT->majorCode[k] = 0;
- }
+ void moveBlockIndex()
+ {
+ if (yuvmode == YuvMode::YUV444)
+ {
+ txb++;
+ if (txb >= static_cast<int>(width / 8))
+ {
+ tyb++;
+ if (tyb >= static_cast<int>(height / 8))
+ {
+ tyb = 0;
+ }
+ txb = 0;
+ }
+ }
+ else
+ {
+ txb++;
+ if (txb >= static_cast<int>(width / 16))
+ {
+ tyb++;
+ if (tyb >= static_cast<int>(height / 16))
+ {
+ tyb = 0;
+ }
+ txb = 0;
+ }
+ }
}
- HT->len[0] = 2;
- i = 2;
+ void initColorTable()
+ {
+ int i, x;
+ int nScale = 1L << 16; // equal to power(2,16)
+ int nHalf = nScale >> 1;
- for (codeIndex = 1; codeIndex < 65535; codeIndex++) {
- if (codeIndex < Huff_code[i]) {
- HT->len[codeIndex] = static_cast<unsigned char>(Huff_code[i + 1]);
- } else {
- i = i + 2;
- HT->len[codeIndex] = static_cast<unsigned char>(Huff_code[i + 1]);
- }
- }
- }
- void initJpgTable() {
- initColorTable();
- prepareRangeLimitTable();
- loadHuffmanTable(&htdc[0], stdDcLuminanceNrcodes, stdDcLuminanceValues,
- dcLuminanceHuffmancode);
- loadHuffmanTable(&htac[0], stdAcLuminanceNrcodes, stdAcLuminanceValues,
- acLuminanceHuffmancode);
- loadHuffmanTable(&htdc[1], stdDcChrominanceNrcodes, stdDcChrominanceValues,
- dcChrominanceHuffmancode);
- loadHuffmanTable(&htac[1], stdAcChrominanceNrcodes, stdAcChrominanceValues,
- acChrominanceHuffmancode);
- }
-
- void prepareRangeLimitTable()
- /* Allocate and fill in the sample_range_limit table */
- {
- int j;
- rlimitTable = reinterpret_cast<unsigned char *>(malloc(5 * 256L + 128));
- /* First segment of "simple" table: limit[x] = 0 for x < 0 */
- memset((void *)rlimitTable, 0, 256);
- rlimitTable += 256; /* allow negative subscripts of simple table */
- /* Main part of "simple" table: limit[x] = x */
- for (j = 0; j < 256; j++) {
- rlimitTable[j] = j;
- }
- /* End of simple table, rest of first half of post-IDCT table */
- for (j = 256; j < 640; j++) {
- rlimitTable[j] = 255;
+#define FIX(x) ((int)((x)*nScale + 0.5))
+
+ /* i is the actual input pixel value, in the range 0..MAXJSAMPLE */
+ /* The Cb or Cr value we are thinking of is x = i - CENTERJSAMPLE */
+ /* Cr=>r value is nearest int to 1.597656 * x */
+ /* Cb=>b value is nearest int to 2.015625 * x */
+ /* Cr=>g value is scaled-up -0.8125 * x */
+ /* Cb=>g value is scaled-up -0.390625 * x */
+ for (i = 0, x = -128; i < 256; i++, x++)
+ {
+ mCrToR[i] = (FIX(1.597656) * x + nHalf) >> 16;
+ mCbToB[i] = (FIX(2.015625) * x + nHalf) >> 16;
+ mCrToG[i] = (-FIX(0.8125) * x + nHalf) >> 16;
+ mCbToG[i] = (-FIX(0.390625) * x + nHalf) >> 16;
+ }
+ for (i = 0, x = -16; i < 256; i++, x++)
+ {
+ mY[i] = (FIX(1.164) * x + nHalf) >> 16;
+ }
+ // For color Text Enchance Y Re-map. Recommend to disable in default
+ /*
+ for (i = 0; i <
+ (VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate); i++) { temp =
+ (double)i / VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate; temp1
+ = 1.0 / VideoEngineInfo->INFData.Gamma1Parameter; mY[i] =
+ (BYTE)(VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate * pow (temp,
+ temp1));
+ if (mY[i] > 255) mY[i] = 255;
+ }
+ for (i = (VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate); i <
+ 256; i++) { mY[i] =
+ (BYTE)((VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate) + (256 -
+ VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate) * ( pow((double)((i
+ - VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate) / (256 -
+ (VideoEngineInfo->INFData.Gamma1_Gamma2_Seperate))), (1.0 /
+ VideoEngineInfo->INFData.Gamma2Parameter)) ));
+ if (mY[i] > 255) mY[i] = 255;
+ }
+ */
}
+ void loadHuffmanTable(HuffmanTable *HT, const unsigned char *nrcode,
+ const unsigned char *value,
+ const unsigned short int *Huff_code)
+ {
+ unsigned char k, j, i;
+ unsigned int code, codeIndex;
+
+ for (j = 1; j <= 16; j++)
+ {
+ HT->length[j] = nrcode[j];
+ }
+ for (i = 0, k = 1; k <= 16; k++)
+ {
+ for (j = 0; j < HT->length[k]; j++)
+ {
+ HT->v[wordHiLo(k, j)] = value[i];
+ i++;
+ }
+ }
+
+ code = 0;
+ for (k = 1; k <= 16; k++)
+ {
+ HT->minorCode[k] = static_cast<unsigned short int>(code);
+ for (j = 1; j <= HT->length[k]; j++)
+ {
+ code++;
+ }
+ HT->majorCode[k] = static_cast<unsigned short int>(code - 1);
+ code *= 2;
+ if (HT->length[k] == 0)
+ {
+ HT->minorCode[k] = 0xFFFF;
+ HT->majorCode[k] = 0;
+ }
+ }
+
+ HT->len[0] = 2;
+ i = 2;
- /* Second half of post-IDCT table */
- memset((void *)(rlimitTable + 640), 0, 384);
- for (j = 0; j < 128; j++) {
- rlimitTable[j + 1024] = j;
+ for (codeIndex = 1; codeIndex < 65535; codeIndex++)
+ {
+ if (codeIndex < Huff_code[i])
+ {
+ HT->len[codeIndex] =
+ static_cast<unsigned char>(Huff_code[i + 1]);
+ }
+ else
+ {
+ i = i + 2;
+ HT->len[codeIndex] =
+ static_cast<unsigned char>(Huff_code[i + 1]);
+ }
+ }
}
- }
-
- inline unsigned short int wordHiLo(uint8_t byte_high, uint8_t byte_low) {
- return (byte_high << 8) + byte_low;
- }
-
- // river
- void processHuffmanDataUnit(uint8_t DC_nr, uint8_t AC_nr,
- signed short int *previous_DC,
- unsigned short int position) {
- uint8_t nr = 0;
- uint8_t k;
- unsigned short int tmpHcode;
- uint8_t sizeVal, count0;
- unsigned short int *minCode;
- uint8_t *huffValues;
- uint8_t byteTemp;
-
- minCode = htdc[DC_nr].minorCode;
- // maj_code=htdc[DC_nr].majorCode;
- huffValues = htdc[DC_nr].v;
-
- // DC
- k = htdc[DC_nr].len[static_cast<unsigned short int>(codebuf >> 16)];
- // river
- // tmp_Hcode=lookKbits(k);
- tmpHcode = static_cast<unsigned short int>(codebuf >> (32 - k));
- skipKbits(k);
- sizeVal =
- huffValues[wordHiLo(k, static_cast<uint8_t>(tmpHcode - minCode[k]))];
- if (sizeVal == 0) {
- dctCoeff[position + 0] = *previous_DC;
- } else {
- dctCoeff[position + 0] = *previous_DC + getKbits(sizeVal);
- *previous_DC = dctCoeff[position + 0];
+ void initJpgTable()
+ {
+ initColorTable();
+ prepareRangeLimitTable();
+ loadHuffmanTable(&htdc[0], stdDcLuminanceNrcodes, stdDcLuminanceValues,
+ dcLuminanceHuffmancode);
+ loadHuffmanTable(&htac[0], stdAcLuminanceNrcodes, stdAcLuminanceValues,
+ acLuminanceHuffmancode);
+ loadHuffmanTable(&htdc[1], stdDcChrominanceNrcodes,
+ stdDcChrominanceValues, dcChrominanceHuffmancode);
+ loadHuffmanTable(&htac[1], stdAcChrominanceNrcodes,
+ stdAcChrominanceValues, acChrominanceHuffmancode);
}
- // Second, AC coefficient decoding
- minCode = htac[AC_nr].minorCode;
- // maj_code=htac[AC_nr].majorCode;
- huffValues = htac[AC_nr].v;
-
- nr = 1; // AC coefficient
- do {
- k = htac[AC_nr].len[static_cast<unsigned short int>(codebuf >> 16)];
- tmpHcode = static_cast<unsigned short int>(codebuf >> (32 - k));
- skipKbits(k);
-
- byteTemp =
- huffValues[wordHiLo(k, static_cast<uint8_t>(tmpHcode - minCode[k]))];
- sizeVal = byteTemp & 0xF;
- count0 = byteTemp >> 4;
- if (sizeVal == 0) {
- if (count0 != 0xF) {
- break;
+ void prepareRangeLimitTable()
+ /* Allocate and fill in the sample_range_limit table */
+ {
+ int j;
+ rlimitTable = reinterpret_cast<unsigned char *>(malloc(5 * 256L + 128));
+ /* First segment of "simple" table: limit[x] = 0 for x < 0 */
+ memset((void *)rlimitTable, 0, 256);
+ rlimitTable += 256; /* allow negative subscripts of simple table */
+ /* Main part of "simple" table: limit[x] = x */
+ for (j = 0; j < 256; j++)
+ {
+ rlimitTable[j] = j;
+ }
+ /* End of simple table, rest of first half of post-IDCT table */
+ for (j = 256; j < 640; j++)
+ {
+ rlimitTable[j] = 255;
+ }
+
+ /* Second half of post-IDCT table */
+ memset((void *)(rlimitTable + 640), 0, 384);
+ for (j = 0; j < 128; j++)
+ {
+ rlimitTable[j + 1024] = j;
}
- nr += 16;
- } else {
- nr += count0; // skip count_0 zeroes
- dctCoeff[position + dezigzag[nr++]] = getKbits(sizeVal);
- }
- } while (nr < 64);
- }
-
- unsigned short int lookKbits(uint8_t k) {
- unsigned short int revcode;
-
- revcode = static_cast<unsigned short int>(codebuf >> (32 - k));
-
- return (revcode);
- }
-
- void skipKbits(uint8_t k) {
- unsigned long readbuf;
-
- if ((newbits - k) <= 0) {
- readbuf = buffer[bufferIndex];
- bufferIndex++;
- codebuf =
- (codebuf << k) | ((newbuf | (readbuf >> (newbits))) >> (32 - k));
- newbuf = readbuf << (k - newbits);
- newbits = 32 + newbits - k;
- } else {
- codebuf = (codebuf << k) | (newbuf >> (32 - k));
- newbuf = newbuf << k;
- newbits -= k;
}
- }
- signed short int getKbits(uint8_t k) {
- signed short int signedWordvalue;
+ inline unsigned short int wordHiLo(uint8_t byte_high, uint8_t byte_low)
+ {
+ return (byte_high << 8) + byte_low;
+ }
// river
- // signed_wordvalue=lookKbits(k);
- signedWordvalue = static_cast<unsigned short int>(codebuf >> (32 - k));
- if (((1L << (k - 1)) & signedWordvalue) == 0) {
- // neg_pow2 was previously defined as the below. It seemed silly to keep
- // a table of values around for something
- // THat's relatively easy to compute, so it was replaced with the
- // appropriate math
- // signed_wordvalue = signed_wordvalue - (0xFFFF >> (16 - k));
- std::array<signed short int, 17> negPow2 = {
- 0, -1, -3, -7, -15, -31, -63, -127,
- -255, -511, -1023, -2047, -4095, -8191, -16383, -32767};
-
- signedWordvalue = signedWordvalue + negPow2[k];
- }
- skipKbits(k);
- return signedWordvalue;
- }
- int initJpgDecoding() {
- bytePos = 0;
- loadQuantTable(qt[0]);
- loadQuantTableCb(qt[1]);
- // Note: Added for Dual-JPEG
- loadAdvanceQuantTable(qt[2]);
- loadAdvanceQuantTableCb(qt[3]);
- return 1;
- }
-
- void setQuantTable(const uint8_t *basic_table, uint8_t scale_factor,
- std::array<uint8_t, 64> &newtable)
- // Set quantization table and zigzag reorder it
- {
- uint8_t i;
- long temp;
- for (i = 0; i < 64; i++) {
- temp = (static_cast<long>(basic_table[i] * 16) / scale_factor);
- /* limit the values to the valid range */
- if (temp <= 0L) {
- temp = 1L;
- }
- if (temp > 255L) {
- temp = 255L; /* limit to baseline range if requested */
- }
- newtable[zigzag[i]] = static_cast<uint8_t>(temp);
- }
- }
-
- void updatereadbuf(uint32_t *codebuf, uint32_t *newbuf, int walks,
- int *newbits, std::vector<uint32_t> &buffer) {
- unsigned long readbuf;
-
- if ((*newbits - walks) <= 0) {
- readbuf = buffer[bufferIndex];
- bufferIndex++;
- *codebuf = (*codebuf << walks) |
- ((*newbuf | (readbuf >> (*newbits))) >> (32 - walks));
- *newbuf = readbuf << (walks - *newbits);
- *newbits = 32 + *newbits - walks;
- } else {
- *codebuf = (*codebuf << walks) | (*newbuf >> (32 - walks));
- *newbuf = *newbuf << walks;
- *newbits -= walks;
- }
- }
-
- uint32_t decode(std::vector<uint32_t> &bufferVector, unsigned long width,
- unsigned long height, YuvMode yuvmode_in, int ySelector,
- int uvSelector) {
- ColorCache decodeColor;
- if (width != userWidth || height != userHeight || yuvmode_in != yuvmode ||
- ySelector != ySelector || uvSelector != uvSelector) {
- yuvmode = yuvmode_in;
- ySelector = ySelector; // 0-7
- uvSelector = uvSelector; // 0-7
- userHeight = height;
- userWidth = width;
- width = width;
- height = height;
-
- // TODO(ed) Magic number section. Document appropriately
- advanceSelector = 0; // 0-7
- mapping = 0; // 0 or 1
-
- if (yuvmode == YuvMode::YUV420) {
- if ((width % 16) != 0u) {
- width = width + 16 - (width % 16);
+ void processHuffmanDataUnit(uint8_t DC_nr, uint8_t AC_nr,
+ signed short int *previous_DC,
+ unsigned short int position)
+ {
+ uint8_t nr = 0;
+ uint8_t k;
+ unsigned short int tmpHcode;
+ uint8_t sizeVal, count0;
+ unsigned short int *minCode;
+ uint8_t *huffValues;
+ uint8_t byteTemp;
+
+ minCode = htdc[DC_nr].minorCode;
+ // maj_code=htdc[DC_nr].majorCode;
+ huffValues = htdc[DC_nr].v;
+
+ // DC
+ k = htdc[DC_nr].len[static_cast<unsigned short int>(codebuf >> 16)];
+ // river
+ // tmp_Hcode=lookKbits(k);
+ tmpHcode = static_cast<unsigned short int>(codebuf >> (32 - k));
+ skipKbits(k);
+ sizeVal = huffValues[wordHiLo(
+ k, static_cast<uint8_t>(tmpHcode - minCode[k]))];
+ if (sizeVal == 0)
+ {
+ dctCoeff[position + 0] = *previous_DC;
}
- if ((height % 16) != 0u) {
- height = height + 16 - (height % 16);
+ else
+ {
+ dctCoeff[position + 0] = *previous_DC + getKbits(sizeVal);
+ *previous_DC = dctCoeff[position + 0];
}
- } else {
- if ((width % 8) != 0u) {
- width = width + 8 - (width % 8);
+
+ // Second, AC coefficient decoding
+ minCode = htac[AC_nr].minorCode;
+ // maj_code=htac[AC_nr].majorCode;
+ huffValues = htac[AC_nr].v;
+
+ nr = 1; // AC coefficient
+ do
+ {
+ k = htac[AC_nr].len[static_cast<unsigned short int>(codebuf >> 16)];
+ tmpHcode = static_cast<unsigned short int>(codebuf >> (32 - k));
+ skipKbits(k);
+
+ byteTemp = huffValues[wordHiLo(
+ k, static_cast<uint8_t>(tmpHcode - minCode[k]))];
+ sizeVal = byteTemp & 0xF;
+ count0 = byteTemp >> 4;
+ if (sizeVal == 0)
+ {
+ if (count0 != 0xF)
+ {
+ break;
+ }
+ nr += 16;
+ }
+ else
+ {
+ nr += count0; // skip count_0 zeroes
+ dctCoeff[position + dezigzag[nr++]] = getKbits(sizeVal);
+ }
+ } while (nr < 64);
+ }
+
+ unsigned short int lookKbits(uint8_t k)
+ {
+ unsigned short int revcode;
+
+ revcode = static_cast<unsigned short int>(codebuf >> (32 - k));
+
+ return (revcode);
+ }
+
+ void skipKbits(uint8_t k)
+ {
+ unsigned long readbuf;
+
+ if ((newbits - k) <= 0)
+ {
+ readbuf = buffer[bufferIndex];
+ bufferIndex++;
+ codebuf = (codebuf << k) |
+ ((newbuf | (readbuf >> (newbits))) >> (32 - k));
+ newbuf = readbuf << (k - newbits);
+ newbits = 32 + newbits - k;
}
- if ((height % 8) != 0u) {
- height = height + 8 - (height % 8);
+ else
+ {
+ codebuf = (codebuf << k) | (newbuf >> (32 - k));
+ newbuf = newbuf << k;
+ newbits -= k;
}
- }
+ }
- initJpgDecoding();
+ signed short int getKbits(uint8_t k)
+ {
+ signed short int signedWordvalue;
+
+ // river
+ // signed_wordvalue=lookKbits(k);
+ signedWordvalue = static_cast<unsigned short int>(codebuf >> (32 - k));
+ if (((1L << (k - 1)) & signedWordvalue) == 0)
+ {
+ // neg_pow2 was previously defined as the below. It seemed silly to
+ // keep a table of values around for something THat's relatively
+ // easy to compute, so it was replaced with the appropriate math
+ // signed_wordvalue = signed_wordvalue - (0xFFFF >> (16 - k));
+ std::array<signed short int, 17> negPow2 = {
+ 0, -1, -3, -7, -15, -31, -63, -127,
+ -255, -511, -1023, -2047, -4095, -8191, -16383, -32767};
+
+ signedWordvalue = signedWordvalue + negPow2[k];
+ }
+ skipKbits(k);
+ return signedWordvalue;
}
- // TODO(ed) cleanup cruft
- buffer = bufferVector.data();
-
- codebuf = bufferVector[0];
- newbuf = bufferVector[1];
- bufferIndex = 2;
-
- txb = tyb = 0;
- newbits = 32;
- dcy = dcCb = dcCr = 0;
-
- static const uint32_t vqHeaderMask = 0x01;
- static const uint32_t vqNoUpdateHeader = 0x00;
- static const uint32_t vqUpdateHeader = 0x01;
- static const int vqNoUpdateLength = 0x03;
- static const int vqUpdateLength = 0x1B;
- static const uint32_t vqIndexMask = 0x03;
- static const uint32_t vqColorMask = 0xFFFFFF;
-
- static const int blockAsT2100StartLength = 0x04;
- static const int blockAsT2100SkipLength = 20; // S:1 H:3 X:8 Y:8
-
- do {
- auto blockHeader = static_cast<JpgBlock>((codebuf >> 28) & 0xFF);
- switch (blockHeader) {
- case JpgBlock::JPEG_NO_SKIP_CODE:
- updatereadbuf(&codebuf, &newbuf, blockAsT2100StartLength, &newbits,
- bufferVector);
- decompress(txb, tyb, reinterpret_cast<char *>(outBuffer.data()), 0);
- break;
- case JpgBlock::FRAME_END_CODE:
- return 0;
- break;
- case JpgBlock::JPEG_SKIP_CODE:
-
- txb = (codebuf & 0x0FF00000) >> 20;
- tyb = (codebuf & 0x0FF000) >> 12;
-
- updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength, &newbits,
- bufferVector);
- decompress(txb, tyb, reinterpret_cast<char *>(outBuffer.data()), 0);
- break;
- case JpgBlock::VQ_NO_SKIP_1_COLOR_CODE:
- updatereadbuf(&codebuf, &newbuf, blockAsT2100StartLength, &newbits,
- bufferVector);
- decodeColor.bitMapBits = 0;
-
- for (int i = 0; i < 1; i++) {
- decodeColor.index[i] = ((codebuf >> 29) & vqIndexMask);
- if (((codebuf >> 31) & vqHeaderMask) == vqNoUpdateHeader) {
- updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength, &newbits,
- bufferVector);
- } else {
- decodeColor.color[decodeColor.index[i]] =
- ((codebuf >> 5) & vqColorMask);
- updatereadbuf(&codebuf, &newbuf, vqUpdateLength, &newbits,
- bufferVector);
- }
- }
- vqDecompress(txb, tyb, reinterpret_cast<char *>(outBuffer.data()), 0,
- &decodeColor);
- break;
- case JpgBlock::VQ_SKIP_1_COLOR_CODE:
- txb = (codebuf & 0x0FF00000) >> 20;
- tyb = (codebuf & 0x0FF000) >> 12;
-
- updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength, &newbits,
- bufferVector);
- decodeColor.bitMapBits = 0;
-
- for (int i = 0; i < 1; i++) {
- decodeColor.index[i] = ((codebuf >> 29) & vqIndexMask);
- if (((codebuf >> 31) & vqHeaderMask) == vqNoUpdateHeader) {
- updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength, &newbits,
- bufferVector);
- } else {
- decodeColor.color[decodeColor.index[i]] =
- ((codebuf >> 5) & vqColorMask);
- updatereadbuf(&codebuf, &newbuf, vqUpdateLength, &newbits,
- bufferVector);
- }
- }
- vqDecompress(txb, tyb, reinterpret_cast<char *>(outBuffer.data()), 0,
- &decodeColor);
- break;
-
- case JpgBlock::VQ_NO_SKIP_2_COLOR_CODE:
- updatereadbuf(&codebuf, &newbuf, blockAsT2100StartLength, &newbits,
- bufferVector);
- decodeColor.bitMapBits = 1;
-
- for (int i = 0; i < 2; i++) {
- decodeColor.index[i] = ((codebuf >> 29) & vqIndexMask);
- if (((codebuf >> 31) & vqHeaderMask) == vqNoUpdateHeader) {
- updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength, &newbits,
- bufferVector);
- } else {
- decodeColor.color[decodeColor.index[i]] =
- ((codebuf >> 5) & vqColorMask);
- updatereadbuf(&codebuf, &newbuf, vqUpdateLength, &newbits,
- bufferVector);
- }
- }
- vqDecompress(txb, tyb, reinterpret_cast<char *>(outBuffer.data()), 0,
- &decodeColor);
- break;
- case JpgBlock::VQ_SKIP_2_COLOR_CODE:
- txb = (codebuf & 0x0FF00000) >> 20;
- tyb = (codebuf & 0x0FF000) >> 12;
-
- updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength, &newbits,
- bufferVector);
- decodeColor.bitMapBits = 1;
-
- for (int i = 0; i < 2; i++) {
- decodeColor.index[i] = ((codebuf >> 29) & vqIndexMask);
- if (((codebuf >> 31) & vqHeaderMask) == vqNoUpdateHeader) {
- updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength, &newbits,
- bufferVector);
- } else {
- decodeColor.color[decodeColor.index[i]] =
- ((codebuf >> 5) & vqColorMask);
- updatereadbuf(&codebuf, &newbuf, vqUpdateLength, &newbits,
- bufferVector);
- }
- }
- vqDecompress(txb, tyb, reinterpret_cast<char *>(outBuffer.data()), 0,
- &decodeColor);
-
- break;
- case JpgBlock::VQ_NO_SKIP_4_COLOR_CODE:
- updatereadbuf(&codebuf, &newbuf, blockAsT2100StartLength, &newbits,
- bufferVector);
- decodeColor.bitMapBits = 2;
-
- for (unsigned char &i : decodeColor.index) {
- i = ((codebuf >> 29) & vqIndexMask);
- if (((codebuf >> 31) & vqHeaderMask) == vqNoUpdateHeader) {
- updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength, &newbits,
- bufferVector);
- } else {
- decodeColor.color[i] = ((codebuf >> 5) & vqColorMask);
- updatereadbuf(&codebuf, &newbuf, vqUpdateLength, &newbits,
- bufferVector);
+ int initJpgDecoding()
+ {
+ bytePos = 0;
+ loadQuantTable(qt[0]);
+ loadQuantTableCb(qt[1]);
+ // Note: Added for Dual-JPEG
+ loadAdvanceQuantTable(qt[2]);
+ loadAdvanceQuantTableCb(qt[3]);
+ return 1;
+ }
+
+ void setQuantTable(const uint8_t *basic_table, uint8_t scale_factor,
+ std::array<uint8_t, 64> &newtable)
+ // Set quantization table and zigzag reorder it
+ {
+ uint8_t i;
+ long temp;
+ for (i = 0; i < 64; i++)
+ {
+ temp = (static_cast<long>(basic_table[i] * 16) / scale_factor);
+ /* limit the values to the valid range */
+ if (temp <= 0L)
+ {
+ temp = 1L;
}
- }
- vqDecompress(txb, tyb, reinterpret_cast<char *>(outBuffer.data()), 0,
- &decodeColor);
-
- break;
-
- case JpgBlock::VQ_SKIP_4_COLOR_CODE:
- txb = (codebuf & 0x0FF00000) >> 20;
- tyb = (codebuf & 0x0FF000) >> 12;
-
- updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength, &newbits,
- bufferVector);
- decodeColor.bitMapBits = 2;
-
- for (unsigned char &i : decodeColor.index) {
- i = ((codebuf >> 29) & vqIndexMask);
- if (((codebuf >> 31) & vqHeaderMask) == vqNoUpdateHeader) {
- updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength, &newbits,
- bufferVector);
- } else {
- decodeColor.color[i] = ((codebuf >> 5) & vqColorMask);
- updatereadbuf(&codebuf, &newbuf, vqUpdateLength, &newbits,
- bufferVector);
+ if (temp > 255L)
+ {
+ temp = 255L; /* limit to baseline range if requested */
}
- }
- vqDecompress(txb, tyb, reinterpret_cast<char *>(outBuffer.data()), 0,
- &decodeColor);
+ newtable[zigzag[i]] = static_cast<uint8_t>(temp);
+ }
+ }
- break;
- case JpgBlock::JPEG_SKIP_PASS2_CODE:
- txb = (codebuf & 0x0FF00000) >> 20;
- tyb = (codebuf & 0x0FF000) >> 12;
+ void updatereadbuf(uint32_t *codebuf, uint32_t *newbuf, int walks,
+ int *newbits, std::vector<uint32_t> &buffer)
+ {
+ unsigned long readbuf;
+
+ if ((*newbits - walks) <= 0)
+ {
+ readbuf = buffer[bufferIndex];
+ bufferIndex++;
+ *codebuf = (*codebuf << walks) |
+ ((*newbuf | (readbuf >> (*newbits))) >> (32 - walks));
+ *newbuf = readbuf << (walks - *newbits);
+ *newbits = 32 + *newbits - walks;
+ }
+ else
+ {
+ *codebuf = (*codebuf << walks) | (*newbuf >> (32 - walks));
+ *newbuf = *newbuf << walks;
+ *newbits -= walks;
+ }
+ }
- updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength, &newbits,
- bufferVector);
- decompress2Pass(txb, tyb, reinterpret_cast<char *>(outBuffer.data()),
- 2);
+ uint32_t decode(std::vector<uint32_t> &bufferVector, unsigned long width,
+ unsigned long height, YuvMode yuvmode_in, int ySelector,
+ int uvSelector)
+ {
+ ColorCache decodeColor;
+ if (width != userWidth || height != userHeight ||
+ yuvmode_in != yuvmode || ySelector != ySelector ||
+ uvSelector != uvSelector)
+ {
+ yuvmode = yuvmode_in;
+ ySelector = ySelector; // 0-7
+ uvSelector = uvSelector; // 0-7
+ userHeight = height;
+ userWidth = width;
+ width = width;
+ height = height;
+
+ // TODO(ed) Magic number section. Document appropriately
+ advanceSelector = 0; // 0-7
+ mapping = 0; // 0 or 1
+
+ if (yuvmode == YuvMode::YUV420)
+ {
+ if ((width % 16) != 0u)
+ {
+ width = width + 16 - (width % 16);
+ }
+ if ((height % 16) != 0u)
+ {
+ height = height + 16 - (height % 16);
+ }
+ }
+ else
+ {
+ if ((width % 8) != 0u)
+ {
+ width = width + 8 - (width % 8);
+ }
+ if ((height % 8) != 0u)
+ {
+ height = height + 8 - (height % 8);
+ }
+ }
- break;
- default:
- // TODO(ed) propogate errors upstream
- return -1;
- break;
- }
- moveBlockIndex();
+ initJpgDecoding();
+ }
+ // TODO(ed) cleanup cruft
+ buffer = bufferVector.data();
+
+ codebuf = bufferVector[0];
+ newbuf = bufferVector[1];
+ bufferIndex = 2;
+
+ txb = tyb = 0;
+ newbits = 32;
+ dcy = dcCb = dcCr = 0;
+
+ static const uint32_t vqHeaderMask = 0x01;
+ static const uint32_t vqNoUpdateHeader = 0x00;
+ static const uint32_t vqUpdateHeader = 0x01;
+ static const int vqNoUpdateLength = 0x03;
+ static const int vqUpdateLength = 0x1B;
+ static const uint32_t vqIndexMask = 0x03;
+ static const uint32_t vqColorMask = 0xFFFFFF;
+
+ static const int blockAsT2100StartLength = 0x04;
+ static const int blockAsT2100SkipLength = 20; // S:1 H:3 X:8 Y:8
+
+ do
+ {
+ auto blockHeader = static_cast<JpgBlock>((codebuf >> 28) & 0xFF);
+ switch (blockHeader)
+ {
+ case JpgBlock::JPEG_NO_SKIP_CODE:
+ updatereadbuf(&codebuf, &newbuf, blockAsT2100StartLength,
+ &newbits, bufferVector);
+ decompress(txb, tyb,
+ reinterpret_cast<char *>(outBuffer.data()), 0);
+ break;
+ case JpgBlock::FRAME_END_CODE:
+ return 0;
+ break;
+ case JpgBlock::JPEG_SKIP_CODE:
+
+ txb = (codebuf & 0x0FF00000) >> 20;
+ tyb = (codebuf & 0x0FF000) >> 12;
+
+ updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength,
+ &newbits, bufferVector);
+ decompress(txb, tyb,
+ reinterpret_cast<char *>(outBuffer.data()), 0);
+ break;
+ case JpgBlock::VQ_NO_SKIP_1_COLOR_CODE:
+ updatereadbuf(&codebuf, &newbuf, blockAsT2100StartLength,
+ &newbits, bufferVector);
+ decodeColor.bitMapBits = 0;
+
+ for (int i = 0; i < 1; i++)
+ {
+ decodeColor.index[i] = ((codebuf >> 29) & vqIndexMask);
+ if (((codebuf >> 31) & vqHeaderMask) ==
+ vqNoUpdateHeader)
+ {
+ updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength,
+ &newbits, bufferVector);
+ }
+ else
+ {
+ decodeColor.color[decodeColor.index[i]] =
+ ((codebuf >> 5) & vqColorMask);
+ updatereadbuf(&codebuf, &newbuf, vqUpdateLength,
+ &newbits, bufferVector);
+ }
+ }
+ vqDecompress(txb, tyb,
+ reinterpret_cast<char *>(outBuffer.data()), 0,
+ &decodeColor);
+ break;
+ case JpgBlock::VQ_SKIP_1_COLOR_CODE:
+ txb = (codebuf & 0x0FF00000) >> 20;
+ tyb = (codebuf & 0x0FF000) >> 12;
+
+ updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength,
+ &newbits, bufferVector);
+ decodeColor.bitMapBits = 0;
+
+ for (int i = 0; i < 1; i++)
+ {
+ decodeColor.index[i] = ((codebuf >> 29) & vqIndexMask);
+ if (((codebuf >> 31) & vqHeaderMask) ==
+ vqNoUpdateHeader)
+ {
+ updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength,
+ &newbits, bufferVector);
+ }
+ else
+ {
+ decodeColor.color[decodeColor.index[i]] =
+ ((codebuf >> 5) & vqColorMask);
+ updatereadbuf(&codebuf, &newbuf, vqUpdateLength,
+ &newbits, bufferVector);
+ }
+ }
+ vqDecompress(txb, tyb,
+ reinterpret_cast<char *>(outBuffer.data()), 0,
+ &decodeColor);
+ break;
+
+ case JpgBlock::VQ_NO_SKIP_2_COLOR_CODE:
+ updatereadbuf(&codebuf, &newbuf, blockAsT2100StartLength,
+ &newbits, bufferVector);
+ decodeColor.bitMapBits = 1;
+
+ for (int i = 0; i < 2; i++)
+ {
+ decodeColor.index[i] = ((codebuf >> 29) & vqIndexMask);
+ if (((codebuf >> 31) & vqHeaderMask) ==
+ vqNoUpdateHeader)
+ {
+ updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength,
+ &newbits, bufferVector);
+ }
+ else
+ {
+ decodeColor.color[decodeColor.index[i]] =
+ ((codebuf >> 5) & vqColorMask);
+ updatereadbuf(&codebuf, &newbuf, vqUpdateLength,
+ &newbits, bufferVector);
+ }
+ }
+ vqDecompress(txb, tyb,
+ reinterpret_cast<char *>(outBuffer.data()), 0,
+ &decodeColor);
+ break;
+ case JpgBlock::VQ_SKIP_2_COLOR_CODE:
+ txb = (codebuf & 0x0FF00000) >> 20;
+ tyb = (codebuf & 0x0FF000) >> 12;
+
+ updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength,
+ &newbits, bufferVector);
+ decodeColor.bitMapBits = 1;
+
+ for (int i = 0; i < 2; i++)
+ {
+ decodeColor.index[i] = ((codebuf >> 29) & vqIndexMask);
+ if (((codebuf >> 31) & vqHeaderMask) ==
+ vqNoUpdateHeader)
+ {
+ updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength,
+ &newbits, bufferVector);
+ }
+ else
+ {
+ decodeColor.color[decodeColor.index[i]] =
+ ((codebuf >> 5) & vqColorMask);
+ updatereadbuf(&codebuf, &newbuf, vqUpdateLength,
+ &newbits, bufferVector);
+ }
+ }
+ vqDecompress(txb, tyb,
+ reinterpret_cast<char *>(outBuffer.data()), 0,
+ &decodeColor);
+
+ break;
+ case JpgBlock::VQ_NO_SKIP_4_COLOR_CODE:
+ updatereadbuf(&codebuf, &newbuf, blockAsT2100StartLength,
+ &newbits, bufferVector);
+ decodeColor.bitMapBits = 2;
+
+ for (unsigned char &i : decodeColor.index)
+ {
+ i = ((codebuf >> 29) & vqIndexMask);
+ if (((codebuf >> 31) & vqHeaderMask) ==
+ vqNoUpdateHeader)
+ {
+ updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength,
+ &newbits, bufferVector);
+ }
+ else
+ {
+ decodeColor.color[i] =
+ ((codebuf >> 5) & vqColorMask);
+ updatereadbuf(&codebuf, &newbuf, vqUpdateLength,
+ &newbits, bufferVector);
+ }
+ }
+ vqDecompress(txb, tyb,
+ reinterpret_cast<char *>(outBuffer.data()), 0,
+ &decodeColor);
+
+ break;
+
+ case JpgBlock::VQ_SKIP_4_COLOR_CODE:
+ txb = (codebuf & 0x0FF00000) >> 20;
+ tyb = (codebuf & 0x0FF000) >> 12;
+
+ updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength,
+ &newbits, bufferVector);
+ decodeColor.bitMapBits = 2;
+
+ for (unsigned char &i : decodeColor.index)
+ {
+ i = ((codebuf >> 29) & vqIndexMask);
+ if (((codebuf >> 31) & vqHeaderMask) ==
+ vqNoUpdateHeader)
+ {
+ updatereadbuf(&codebuf, &newbuf, vqNoUpdateLength,
+ &newbits, bufferVector);
+ }
+ else
+ {
+ decodeColor.color[i] =
+ ((codebuf >> 5) & vqColorMask);
+ updatereadbuf(&codebuf, &newbuf, vqUpdateLength,
+ &newbits, bufferVector);
+ }
+ }
+ vqDecompress(txb, tyb,
+ reinterpret_cast<char *>(outBuffer.data()), 0,
+ &decodeColor);
+
+ break;
+ case JpgBlock::JPEG_SKIP_PASS2_CODE:
+ txb = (codebuf & 0x0FF00000) >> 20;
+ tyb = (codebuf & 0x0FF000) >> 12;
+
+ updatereadbuf(&codebuf, &newbuf, blockAsT2100SkipLength,
+ &newbits, bufferVector);
+ decompress2Pass(txb, tyb,
+ reinterpret_cast<char *>(outBuffer.data()),
+ 2);
+
+ break;
+ default:
+ // TODO(ed) propogate errors upstream
+ return -1;
+ break;
+ }
+ moveBlockIndex();
- } while (bufferIndex <= bufferVector.size());
+ } while (bufferIndex <= bufferVector.size());
- return -1;
- }
+ return -1;
+ }
#ifdef cimg_version
- void dump_to_bitmap_file() {
- cimg_library::CImg<unsigned char> image(width, height, 1, 3);
- for (int y = 0; y < width; y++) {
- for (int x = 0; x < height; x++) {
- auto pixel = outBuffer[x + (y * width)];
- image(x, y, 0) = pixel.r;
- image(x, y, 1) = pixel.g;
- image(x, y, 2) = pixel.b;
- }
+ void dump_to_bitmap_file()
+ {
+ cimg_library::CImg<unsigned char> image(width, height, 1, 3);
+ for (int y = 0; y < width; y++)
+ {
+ for (int x = 0; x < height; x++)
+ {
+ auto pixel = outBuffer[x + (y * width)];
+ image(x, y, 0) = pixel.r;
+ image(x, y, 1) = pixel.g;
+ image(x, y, 2) = pixel.b;
+ }
+ }
+ image.save("/tmp/file2.bmp");
}
- image.save("/tmp/file2.bmp");
- }
#endif
- private:
- YuvMode yuvmode{};
- // width and height are the modes your display used
- unsigned long width{};
- unsigned long height{};
- unsigned long userWidth{};
- unsigned long userHeight{};
- unsigned char ySelector{};
- int scalefactor;
- int scalefactoruv;
- int advancescalefactor;
- int advancescalefactoruv;
- int mapping{};
- unsigned char uvSelector{};
- unsigned char advanceSelector{};
- int bytePos{}; // current byte position
-
- // quantization tables, no more than 4 quantization tables
- std::array<std::array<long, 64>, 4> qt{};
-
- // DC huffman tables , no more than 4 (0..3)
- std::array<HuffmanTable, 4> htdc{};
- // AC huffman tables (0..3)
- std::array<HuffmanTable, 4> htac{};
- std::array<int, 256> mCrToR{};
- std::array<int, 256> mCbToB{};
- std::array<int, 256> mCrToG{};
- std::array<int, 256> mCbToG{};
- std::array<int, 256> mY{};
- unsigned long bufferIndex{};
- uint32_t codebuf{}, newbuf{}, readbuf{};
- const unsigned char *stdLuminanceQt{};
- const uint8_t *stdChrominanceQt{};
-
- signed short int dcy{}, dcCb{}, dcCr{}; // Coeficientii DC pentru Y,Cb,Cr
- signed short int dctCoeff[384]{};
- // std::vector<signed short int> dctCoeff; // Current DCT_coefficients
- // quantization table number for Y, Cb, Cr
- uint8_t yqNr = 0, cbQNr = 1, crQNr = 1;
- // DC Huffman table number for Y,Cb, Cr
- uint8_t ydcNr = 0, cbDcNr = 1, crDcNr = 1;
- // AC Huffman table number for Y,Cb, Cr
- uint8_t yacNr = 0, cbAcNr = 1, crAcNr = 1;
- int txb = 0;
- int tyb = 0;
- int newbits{};
- uint8_t *rlimitTable{};
- std::vector<RGB> yuvBuffer;
- // TODO(ed) this shouldn't exist. It is cruft that needs cleaning up
- uint32_t *buffer{};
-
- public:
- std::vector<RGB> outBuffer;
+ private:
+ YuvMode yuvmode{};
+ // width and height are the modes your display used
+ unsigned long width{};
+ unsigned long height{};
+ unsigned long userWidth{};
+ unsigned long userHeight{};
+ unsigned char ySelector{};
+ int scalefactor;
+ int scalefactoruv;
+ int advancescalefactor;
+ int advancescalefactoruv;
+ int mapping{};
+ unsigned char uvSelector{};
+ unsigned char advanceSelector{};
+ int bytePos{}; // current byte position
+
+ // quantization tables, no more than 4 quantization tables
+ std::array<std::array<long, 64>, 4> qt{};
+
+ // DC huffman tables , no more than 4 (0..3)
+ std::array<HuffmanTable, 4> htdc{};
+ // AC huffman tables (0..3)
+ std::array<HuffmanTable, 4> htac{};
+ std::array<int, 256> mCrToR{};
+ std::array<int, 256> mCbToB{};
+ std::array<int, 256> mCrToG{};
+ std::array<int, 256> mCbToG{};
+ std::array<int, 256> mY{};
+ unsigned long bufferIndex{};
+ uint32_t codebuf{}, newbuf{}, readbuf{};
+ const unsigned char *stdLuminanceQt{};
+ const uint8_t *stdChrominanceQt{};
+
+ signed short int dcy{}, dcCb{}, dcCr{}; // Coeficientii DC pentru Y,Cb,Cr
+ signed short int dctCoeff[384]{};
+ // std::vector<signed short int> dctCoeff; // Current DCT_coefficients
+ // quantization table number for Y, Cb, Cr
+ uint8_t yqNr = 0, cbQNr = 1, crQNr = 1;
+ // DC Huffman table number for Y,Cb, Cr
+ uint8_t ydcNr = 0, cbDcNr = 1, crDcNr = 1;
+ // AC Huffman table number for Y,Cb, Cr
+ uint8_t yacNr = 0, cbAcNr = 1, crAcNr = 1;
+ int txb = 0;
+ int tyb = 0;
+ int newbits{};
+ uint8_t *rlimitTable{};
+ std::vector<RGB> yuvBuffer;
+ // TODO(ed) this shouldn't exist. It is cruft that needs cleaning up
+ uint32_t *buffer{};
+
+ public:
+ std::vector<RGB> outBuffer;
};
-} // namespace ast_video \ No newline at end of file
+} // namespace ast_video \ No newline at end of file
diff --git a/include/ast_video_puller.hpp b/include/ast_video_puller.hpp
index c2ccea27c3..520fc68e18 100644
--- a/include/ast_video_puller.hpp
+++ b/include/ast_video_puller.hpp
@@ -1,186 +1,212 @@
#pragma once
#include <ast_video_types.hpp>
+#include <boost/asio.hpp>
#include <cassert>
#include <iostream>
#include <mutex>
#include <vector>
-#include <boost/asio.hpp>
-namespace ast_video {
+namespace ast_video
+{
//
// Cursor struct is used in User Mode
//
-struct AstCurAttributionTag {
- unsigned int posX;
- unsigned int posY;
- unsigned int curWidth;
- unsigned int curHeight;
- unsigned int curType; // 0:mono 1:color 2:disappear cursor
- unsigned int curChangeFlag;
+struct AstCurAttributionTag
+{
+ unsigned int posX;
+ unsigned int posY;
+ unsigned int curWidth;
+ unsigned int curHeight;
+ unsigned int curType; // 0:mono 1:color 2:disappear cursor
+ unsigned int curChangeFlag;
};
//
// For storing Cursor Information
//
-struct AstCursorTag {
- AstCurAttributionTag attr;
- // unsigned char icon[MAX_CUR_OFFSETX*MAX_CUR_OFFSETY*2];
- unsigned char *icon; //[64*64*2];
+struct AstCursorTag
+{
+ AstCurAttributionTag attr;
+ // unsigned char icon[MAX_CUR_OFFSETX*MAX_CUR_OFFSETY*2];
+ unsigned char *icon; //[64*64*2];
};
//
// For select image format, i.e. 422 JPG420, 444 JPG444, lumin/chrom table, 0
// ~ 11, low to high
//
-struct FeaturesTag {
- short jpgFmt; // 422:JPG420, 444:JPG444
- short luminTbl;
- short chromTbl;
- short toleranceNoise;
- int w;
- int h;
- unsigned char *buf;
+struct FeaturesTag
+{
+ short jpgFmt; // 422:JPG420, 444:JPG444
+ short luminTbl;
+ short chromTbl;
+ short toleranceNoise;
+ int w;
+ int h;
+ unsigned char *buf;
};
//
// For configure video engine control registers
//
-struct ImageInfo {
- short doImageRefresh; // Action 0:motion 1:fullframe 2:quick cursor
- char qcValid; // quick cursor enable/disable
- unsigned int len;
- int crypttype;
- char cryptkey[16];
- union {
- FeaturesTag features;
- AstCursorTag cursorInfo;
- } parameter;
+struct ImageInfo
+{
+ short doImageRefresh; // Action 0:motion 1:fullframe 2:quick cursor
+ char qcValid; // quick cursor enable/disable
+ unsigned int len;
+ int crypttype;
+ char cryptkey[16];
+ union
+ {
+ FeaturesTag features;
+ AstCursorTag cursorInfo;
+ } parameter;
};
-class SimpleVideoPuller {
- public:
- SimpleVideoPuller() : imageInfo(){};
-
- void initialize() {
- std::cout << "Opening /dev/video\n";
- videoFd = open("/dev/video", O_RDWR);
- if (videoFd == 0) {
- std::cout << "Failed to open /dev/video\n";
- throw std::runtime_error("Failed to open /dev/video");
- }
- std::cout << "Opened successfully\n";
- }
-
- RawVideoBuffer readVideo() {
- assert(videoFd != 0);
- RawVideoBuffer raw;
-
- imageInfo.doImageRefresh = 1; // full frame refresh
- imageInfo.qcValid = 0; // quick cursor disabled
- imageInfo.parameter.features.buf =
- reinterpret_cast<unsigned char *>(raw.buffer.data());
- imageInfo.crypttype = -1;
- std::cout << "Writing\n";
-
- int status;
- /*
- status = write(videoFd, reinterpret_cast<char*>(&imageInfo),
- sizeof(imageInfo));
- if (status != sizeof(imageInfo)) {
- std::cout << "Write failed. Return: " << status << "\n";
- perror("perror output:");
- }
-
- std::cout << "Write done\n";
- */
- std::cout << "Reading\n";
- status =
- read(videoFd, reinterpret_cast<char *>(&imageInfo), sizeof(imageInfo));
- std::cout << "Done reading\n";
-
- if (status != 0) {
- std::cerr << "Read failed with status " << status << "\n";
+class SimpleVideoPuller
+{
+ public:
+ SimpleVideoPuller() : imageInfo(){};
+
+ void initialize()
+ {
+ std::cout << "Opening /dev/video\n";
+ videoFd = open("/dev/video", O_RDWR);
+ if (videoFd == 0)
+ {
+ std::cout << "Failed to open /dev/video\n";
+ throw std::runtime_error("Failed to open /dev/video");
+ }
+ std::cout << "Opened successfully\n";
}
- raw.buffer.resize(imageInfo.len);
-
- raw.height = imageInfo.parameter.features.h;
- raw.width = imageInfo.parameter.features.w;
- if (imageInfo.parameter.features.jpgFmt == 422) {
- raw.mode = YuvMode::YUV420;
- } else {
- raw.mode = YuvMode::YUV444;
+ RawVideoBuffer readVideo()
+ {
+ assert(videoFd != 0);
+ RawVideoBuffer raw;
+
+ imageInfo.doImageRefresh = 1; // full frame refresh
+ imageInfo.qcValid = 0; // quick cursor disabled
+ imageInfo.parameter.features.buf =
+ reinterpret_cast<unsigned char *>(raw.buffer.data());
+ imageInfo.crypttype = -1;
+ std::cout << "Writing\n";
+
+ int status;
+ /*
+ status = write(videoFd, reinterpret_cast<char*>(&imageInfo),
+ sizeof(imageInfo));
+ if (status != sizeof(imageInfo)) {
+ std::cout << "Write failed. Return: " << status << "\n";
+ perror("perror output:");
+ }
+
+ std::cout << "Write done\n";
+ */
+ std::cout << "Reading\n";
+ status = read(videoFd, reinterpret_cast<char *>(&imageInfo),
+ sizeof(imageInfo));
+ std::cout << "Done reading\n";
+
+ if (status != 0)
+ {
+ std::cerr << "Read failed with status " << status << "\n";
+ }
+
+ raw.buffer.resize(imageInfo.len);
+
+ raw.height = imageInfo.parameter.features.h;
+ raw.width = imageInfo.parameter.features.w;
+ if (imageInfo.parameter.features.jpgFmt == 422)
+ {
+ raw.mode = YuvMode::YUV420;
+ }
+ else
+ {
+ raw.mode = YuvMode::YUV444;
+ }
+ return raw;
}
- return raw;
- }
- private:
- int videoFd{};
- ImageInfo imageInfo;
+ private:
+ int videoFd{};
+ ImageInfo imageInfo;
};
#if defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
-class AsyncVideoPuller {
- public:
- using video_callback = std::function<void(RawVideoBuffer &)>;
-
- explicit AsyncVideoPuller(boost::asio::io_service &ioService)
- : imageInfo(), devVideo(ioService, open("/dev/video", O_RDWR)) {
- videobuf = std::make_shared<RawVideoBuffer>();
-
- imageInfo.doImageRefresh = 1; // full frame refresh
- imageInfo.qcValid = 0; // quick cursor disabled
- imageInfo.parameter.features.buf =
- reinterpret_cast<unsigned char *>(videobuf->buffer.data());
- imageInfo.crypttype = -1;
- };
-
- void registerCallback(video_callback &callback) {
- std::lock_guard<std::mutex> lock(callbackMutex);
- callbacks.push_back(callback);
- startRead();
- }
-
- void startRead() {
- auto mutableBuffer = boost::asio::buffer(&imageInfo, sizeof(imageInfo));
- boost::asio::async_read(devVideo, mutableBuffer,
- [this](const boost::system::error_code &ec,
- std::size_t bytes_transferred) {
- if (ec) {
- std::cerr << "Read failed with status " << ec
- << "\n";
- } else {
- this->readDone();
- }
- });
- }
-
- void readDone() {
- std::cout << "Done reading\n";
- videobuf->buffer.resize(imageInfo.len);
-
- videobuf->height = imageInfo.parameter.features.h;
- videobuf->width = imageInfo.parameter.features.w;
- if (imageInfo.parameter.features.jpgFmt == 422) {
- videobuf->mode = YuvMode::YUV420;
- } else {
- videobuf->mode = YuvMode::YUV444;
+class AsyncVideoPuller
+{
+ public:
+ using video_callback = std::function<void(RawVideoBuffer &)>;
+
+ explicit AsyncVideoPuller(boost::asio::io_service &ioService) :
+ imageInfo(), devVideo(ioService, open("/dev/video", O_RDWR))
+ {
+ videobuf = std::make_shared<RawVideoBuffer>();
+
+ imageInfo.doImageRefresh = 1; // full frame refresh
+ imageInfo.qcValid = 0; // quick cursor disabled
+ imageInfo.parameter.features.buf =
+ reinterpret_cast<unsigned char *>(videobuf->buffer.data());
+ imageInfo.crypttype = -1;
+ };
+
+ void registerCallback(video_callback &callback)
+ {
+ std::lock_guard<std::mutex> lock(callbackMutex);
+ callbacks.push_back(callback);
+ startRead();
+ }
+
+ void startRead()
+ {
+ auto mutableBuffer = boost::asio::buffer(&imageInfo, sizeof(imageInfo));
+ boost::asio::async_read(devVideo, mutableBuffer,
+ [this](const boost::system::error_code &ec,
+ std::size_t bytes_transferred) {
+ if (ec)
+ {
+ std::cerr << "Read failed with status "
+ << ec << "\n";
+ }
+ else
+ {
+ this->readDone();
+ }
+ });
}
- std::lock_guard<std::mutex> lock(callbackMutex);
- for (auto &callback : callbacks) {
- // TODO(ed) call callbacks async and double buffer frames
- callback(*videobuf);
+
+ void readDone()
+ {
+ std::cout << "Done reading\n";
+ videobuf->buffer.resize(imageInfo.len);
+
+ videobuf->height = imageInfo.parameter.features.h;
+ videobuf->width = imageInfo.parameter.features.w;
+ if (imageInfo.parameter.features.jpgFmt == 422)
+ {
+ videobuf->mode = YuvMode::YUV420;
+ }
+ else
+ {
+ videobuf->mode = YuvMode::YUV444;
+ }
+ std::lock_guard<std::mutex> lock(callbackMutex);
+ for (auto &callback : callbacks)
+ {
+ // TODO(ed) call callbacks async and double buffer frames
+ callback(*videobuf);
+ }
}
- }
-
- private:
- std::shared_ptr<RawVideoBuffer> videobuf;
- boost::asio::posix::stream_descriptor devVideo;
- ImageInfo imageInfo;
- std::mutex callbackMutex;
- std::vector<video_callback> callbacks;
+
+ private:
+ std::shared_ptr<RawVideoBuffer> videobuf;
+ boost::asio::posix::stream_descriptor devVideo;
+ ImageInfo imageInfo;
+ std::mutex callbackMutex;
+ std::vector<video_callback> callbacks;
};
-#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
-} // namespace ast_video
+#endif // defined(BOOST_ASIO_HAS_POSIX_STREAM_DESCRIPTOR)
+} // namespace ast_video
diff --git a/include/ast_video_types.hpp b/include/ast_video_types.hpp
index f9801460e6..aeef1d8499 100644
--- a/include/ast_video_types.hpp
+++ b/include/ast_video_types.hpp
@@ -2,18 +2,24 @@
#include <cstdint>
#include <vector>
-namespace ast_video {
-enum class YuvMode { YUV444 = 0, YUV420 = 1 };
+namespace ast_video
+{
+enum class YuvMode
+{
+ YUV444 = 0,
+ YUV420 = 1
+};
-class RawVideoBuffer {
- public:
- RawVideoBuffer() : buffer(1024 * 1024 * 10, 0){};
- unsigned long height{};
- unsigned long width{};
- int ySelector{};
- int uvSelector{};
- YuvMode mode;
- // TODO(ed) determine a more appropriate buffer size
- std::vector<uint32_t> buffer;
+class RawVideoBuffer
+{
+ public:
+ RawVideoBuffer() : buffer(1024 * 1024 * 10, 0){};
+ unsigned long height{};
+ unsigned long width{};
+ int ySelector{};
+ int uvSelector{};
+ YuvMode mode;
+ // TODO(ed) determine a more appropriate buffer size
+ std::vector<uint32_t> buffer;
};
-} // namespace ast_video \ No newline at end of file
+} // namespace ast_video \ No newline at end of file
diff --git a/include/dbus_monitor.hpp b/include/dbus_monitor.hpp
index e8b1a327b1..5dcd5ca362 100644
--- a/include/dbus_monitor.hpp
+++ b/include/dbus_monitor.hpp
@@ -1,26 +1,33 @@
#pragma once
-#include <dbus_singleton.hpp>
-#include <sdbusplus/bus/match.hpp>
#include <crow/app.h>
#include <crow/websocket.h>
+
#include <boost/container/flat_map.hpp>
#include <boost/container/flat_set.hpp>
+#include <dbus_singleton.hpp>
+#include <sdbusplus/bus/match.hpp>
-namespace nlohmann {
+namespace nlohmann
+{
template <typename... Args>
-struct adl_serializer<sdbusplus::message::variant<Args...>> {
- static void to_json(json& j, const sdbusplus::message::variant<Args...>& v) {
- mapbox::util::apply_visitor([&](auto&& val) { j = val; }, v);
- }
+struct adl_serializer<sdbusplus::message::variant<Args...>>
+{
+ static void to_json(json& j, const sdbusplus::message::variant<Args...>& v)
+ {
+ mapbox::util::apply_visitor([&](auto&& val) { j = val; }, v);
+ }
};
-} // namespace nlohmann
+} // namespace nlohmann
-namespace crow {
-namespace dbus_monitor {
+namespace crow
+{
+namespace dbus_monitor
+{
-struct DbusWebsocketSession {
- std::vector<std::unique_ptr<sdbusplus::bus::match::match>> matches;
- boost::container::flat_set<std::string> interfaces;
+struct DbusWebsocketSession
+{
+ std::vector<std::unique_ptr<sdbusplus::bus::match::match>> matches;
+ boost::container::flat_set<std::string> interfaces;
};
static boost::container::flat_map<crow::websocket::Connection*,
@@ -28,165 +35,198 @@ static boost::container::flat_map<crow::websocket::Connection*,
sessions;
inline int onPropertyUpdate(sd_bus_message* m, void* userdata,
- sd_bus_error* ret_error) {
- if (ret_error == nullptr || sd_bus_error_is_set(ret_error)) {
- BMCWEB_LOG_ERROR << "Got sdbus error on match";
- return 0;
- }
- crow::websocket::Connection* connection =
- static_cast<crow::websocket::Connection*>(userdata);
- auto thisSession = sessions.find(connection);
- if (thisSession == sessions.end()) {
- BMCWEB_LOG_ERROR << "Couldn't find dbus connection " << connection;
- return 0;
- }
- sdbusplus::message::message message(m);
- using VariantType =
- sdbusplus::message::variant<std::string, bool, int64_t, uint64_t, double>;
- nlohmann::json j{{"event", message.get_member()},
- {"path", message.get_path()}};
- if (strcmp(message.get_member(), "PropertiesChanged") == 0) {
- std::string interface_name;
- boost::container::flat_map<std::string, VariantType> values;
- message.read(interface_name, values);
- j["properties"] = values;
- j["interface"] = std::move(interface_name);
-
- } else if (strcmp(message.get_member(), "InterfacesAdded") == 0) {
- std::string object_name;
- boost::container::flat_map<
- std::string, boost::container::flat_map<std::string, VariantType>>
- values;
- message.read(object_name, values);
- for (const std::pair<std::string,
- boost::container::flat_map<std::string, VariantType>>&
- paths : values) {
- auto it = thisSession->second.interfaces.find(paths.first);
- if (it != thisSession->second.interfaces.end()) {
- j["interfaces"][paths.first] = paths.second;
- }
+ sd_bus_error* ret_error)
+{
+ if (ret_error == nullptr || sd_bus_error_is_set(ret_error))
+ {
+ BMCWEB_LOG_ERROR << "Got sdbus error on match";
+ return 0;
+ }
+ crow::websocket::Connection* connection =
+ static_cast<crow::websocket::Connection*>(userdata);
+ auto thisSession = sessions.find(connection);
+ if (thisSession == sessions.end())
+ {
+ BMCWEB_LOG_ERROR << "Couldn't find dbus connection " << connection;
+ return 0;
+ }
+ sdbusplus::message::message message(m);
+ using VariantType = sdbusplus::message::variant<std::string, bool, int64_t,
+ uint64_t, double>;
+ nlohmann::json j{{"event", message.get_member()},
+ {"path", message.get_path()}};
+ if (strcmp(message.get_member(), "PropertiesChanged") == 0)
+ {
+ std::string interface_name;
+ boost::container::flat_map<std::string, VariantType> values;
+ message.read(interface_name, values);
+ j["properties"] = values;
+ j["interface"] = std::move(interface_name);
+ }
+ else if (strcmp(message.get_member(), "InterfacesAdded") == 0)
+ {
+ std::string object_name;
+ boost::container::flat_map<
+ std::string, boost::container::flat_map<std::string, VariantType>>
+ values;
+ message.read(object_name, values);
+ for (const std::pair<
+ std::string,
+ boost::container::flat_map<std::string, VariantType>>& paths :
+ values)
+ {
+ auto it = thisSession->second.interfaces.find(paths.first);
+ if (it != thisSession->second.interfaces.end())
+ {
+ j["interfaces"][paths.first] = paths.second;
+ }
+ }
+ }
+ else
+ {
+ BMCWEB_LOG_CRITICAL << "message " << message.get_member()
+ << " was unexpected";
+ return 0;
}
- } else {
- BMCWEB_LOG_CRITICAL << "message " << message.get_member()
- << " was unexpected";
- return 0;
- }
- connection->sendText(j.dump());
- return 0;
+ connection->sendText(j.dump());
+ return 0;
};
-template <typename... Middlewares>
-void requestRoutes(Crow<Middlewares...>& app) {
- BMCWEB_ROUTE(app, "/subscribe")
- .websocket()
- .onopen([&](crow::websocket::Connection& conn) {
- BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
- sessions[&conn] = DbusWebsocketSession();
- })
- .onclose([&](crow::websocket::Connection& conn,
- const std::string& reason) { sessions.erase(&conn); })
- .onmessage([&](crow::websocket::Connection& conn, const std::string& data,
- bool is_binary) {
- DbusWebsocketSession& thisSession = sessions[&conn];
- BMCWEB_LOG_DEBUG << "Connection " << &conn << " recevied " << data;
- nlohmann::json j = nlohmann::json::parse(data, nullptr, false);
- if (j.is_discarded()) {
- BMCWEB_LOG_ERROR << "Unable to parse json data for monitor";
- conn.close("Unable to parse json request");
- return;
- }
- nlohmann::json::iterator interfaces = j.find("interfaces");
- if (interfaces != j.end()) {
- thisSession.interfaces.reserve(interfaces->size());
- for (auto& interface : *interfaces) {
- const std::string* str = interface.get_ptr<const std::string*>();
- if (str != nullptr) {
- thisSession.interfaces.insert(*str);
+template <typename... Middlewares> void requestRoutes(Crow<Middlewares...>& app)
+{
+ BMCWEB_ROUTE(app, "/subscribe")
+ .websocket()
+ .onopen([&](crow::websocket::Connection& conn) {
+ BMCWEB_LOG_DEBUG << "Connection " << &conn << " opened";
+ sessions[&conn] = DbusWebsocketSession();
+ })
+ .onclose([&](crow::websocket::Connection& conn,
+ const std::string& reason) { sessions.erase(&conn); })
+ .onmessage([&](crow::websocket::Connection& conn,
+ const std::string& data, bool is_binary) {
+ DbusWebsocketSession& thisSession = sessions[&conn];
+ BMCWEB_LOG_DEBUG << "Connection " << &conn << " recevied " << data;
+ nlohmann::json j = nlohmann::json::parse(data, nullptr, false);
+ if (j.is_discarded())
+ {
+ BMCWEB_LOG_ERROR << "Unable to parse json data for monitor";
+ conn.close("Unable to parse json request");
+ return;
+ }
+ nlohmann::json::iterator interfaces = j.find("interfaces");
+ if (interfaces != j.end())
+ {
+ thisSession.interfaces.reserve(interfaces->size());
+ for (auto& interface : *interfaces)
+ {
+ const std::string* str =
+ interface.get_ptr<const std::string*>();
+ if (str != nullptr)
+ {
+ thisSession.interfaces.insert(*str);
+ }
+ }
}
- }
- }
- nlohmann::json::iterator paths = j.find("paths");
- if (paths != j.end()) {
- int interfaceCount = thisSession.interfaces.size();
- if (interfaceCount == 0) {
- interfaceCount = 1;
- }
- // Reserve our matches upfront. For each path there is 1 for
- // interfacesAdded, and InterfaceCount number for PropertiesChanged
- thisSession.matches.reserve(thisSession.matches.size() +
- paths->size() * (1 + interfaceCount));
- }
- std::string object_manager_match_string;
- std::string properties_match_string;
- std::string object_manager_interfaces_match_string;
- // These regexes derived on the rules here:
- // https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names
- std::regex validPath("^/([A-Za-z0-9_]+/?)*$");
- std::regex validInterface(
- "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*)+$");
+ nlohmann::json::iterator paths = j.find("paths");
+ if (paths != j.end())
+ {
+ int interfaceCount = thisSession.interfaces.size();
+ if (interfaceCount == 0)
+ {
+ interfaceCount = 1;
+ }
+ // Reserve our matches upfront. For each path there is 1 for
+ // interfacesAdded, and InterfaceCount number for
+ // PropertiesChanged
+ thisSession.matches.reserve(thisSession.matches.size() +
+ paths->size() *
+ (1 + interfaceCount));
+ }
+ std::string object_manager_match_string;
+ std::string properties_match_string;
+ std::string object_manager_interfaces_match_string;
+ // These regexes derived on the rules here:
+ // https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names
+ std::regex validPath("^/([A-Za-z0-9_]+/?)*$");
+ std::regex validInterface(
+ "^[A-Za-z_][A-Za-z0-9_]*(\\.[A-Za-z_][A-Za-z0-9_]*)+$");
- for (const auto& thisPath : *paths) {
- const std::string* thisPathString =
- thisPath.get_ptr<const std::string*>();
- if (thisPathString == nullptr) {
- BMCWEB_LOG_ERROR << "subscribe path isn't a string?";
- conn.close();
- return;
- }
- if (!std::regex_match(*thisPathString, validPath)) {
- BMCWEB_LOG_ERROR << "Invalid path name " << *thisPathString;
- conn.close();
- return;
- }
- properties_match_string =
- ("type='signal',"
- "interface='org.freedesktop.DBus.Properties',"
- "path_namespace='" +
- *thisPathString +
- "',"
- "member='PropertiesChanged'");
- // If interfaces weren't specified, add a single match for all
- // interfaces
- if (thisSession.interfaces.size() == 0) {
- BMCWEB_LOG_DEBUG << "Creating match " << properties_match_string;
+ for (const auto& thisPath : *paths)
+ {
+ const std::string* thisPathString =
+ thisPath.get_ptr<const std::string*>();
+ if (thisPathString == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "subscribe path isn't a string?";
+ conn.close();
+ return;
+ }
+ if (!std::regex_match(*thisPathString, validPath))
+ {
+ BMCWEB_LOG_ERROR << "Invalid path name " << *thisPathString;
+ conn.close();
+ return;
+ }
+ properties_match_string =
+ ("type='signal',"
+ "interface='org.freedesktop.DBus.Properties',"
+ "path_namespace='" +
+ *thisPathString +
+ "',"
+ "member='PropertiesChanged'");
+ // If interfaces weren't specified, add a single match for all
+ // interfaces
+ if (thisSession.interfaces.size() == 0)
+ {
+ BMCWEB_LOG_DEBUG << "Creating match "
+ << properties_match_string;
- thisSession.matches.emplace_back(
- std::make_unique<sdbusplus::bus::match::match>(
- *crow::connections::systemBus, properties_match_string,
- onPropertyUpdate, &conn));
- } else {
- // If interfaces were specified, add a match for each interface
- for (const std::string& interface : thisSession.interfaces) {
- if (!std::regex_match(interface, validInterface)) {
- BMCWEB_LOG_ERROR << "Invalid interface name " << interface;
- conn.close();
- return;
- }
- std::string ifaceMatchString =
- properties_match_string + ",arg0='" + interface + "'";
- BMCWEB_LOG_DEBUG << "Creating match " << ifaceMatchString;
- thisSession.matches.emplace_back(
- std::make_unique<sdbusplus::bus::match::match>(
- *crow::connections::systemBus, ifaceMatchString,
- onPropertyUpdate, &conn));
+ thisSession.matches.emplace_back(
+ std::make_unique<sdbusplus::bus::match::match>(
+ *crow::connections::systemBus,
+ properties_match_string, onPropertyUpdate, &conn));
+ }
+ else
+ {
+ // If interfaces were specified, add a match for each
+ // interface
+ for (const std::string& interface : thisSession.interfaces)
+ {
+ if (!std::regex_match(interface, validInterface))
+ {
+ BMCWEB_LOG_ERROR << "Invalid interface name "
+ << interface;
+ conn.close();
+ return;
+ }
+ std::string ifaceMatchString = properties_match_string +
+ ",arg0='" + interface +
+ "'";
+ BMCWEB_LOG_DEBUG << "Creating match "
+ << ifaceMatchString;
+ thisSession.matches.emplace_back(
+ std::make_unique<sdbusplus::bus::match::match>(
+ *crow::connections::systemBus, ifaceMatchString,
+ onPropertyUpdate, &conn));
+ }
+ }
+ object_manager_match_string =
+ ("type='signal',"
+ "interface='org.freedesktop.DBus.ObjectManager',"
+ "path_namespace='" +
+ *thisPathString +
+ "',"
+ "member='InterfacesAdded'");
+ BMCWEB_LOG_DEBUG << "Creating match "
+ << object_manager_match_string;
+ thisSession.matches.emplace_back(
+ std::make_unique<sdbusplus::bus::match::match>(
+ *crow::connections::systemBus,
+ object_manager_match_string, onPropertyUpdate, &conn));
}
- }
- object_manager_match_string =
- ("type='signal',"
- "interface='org.freedesktop.DBus.ObjectManager',"
- "path_namespace='" +
- *thisPathString +
- "',"
- "member='InterfacesAdded'");
- BMCWEB_LOG_DEBUG << "Creating match " << object_manager_match_string;
- thisSession.matches.emplace_back(
- std::make_unique<sdbusplus::bus::match::match>(
- *crow::connections::systemBus, object_manager_match_string,
- onPropertyUpdate, &conn));
- }
- });
+ });
}
-} // namespace dbus_monitor
-} // namespace crow
+} // namespace dbus_monitor
+} // namespace crow
diff --git a/include/dbus_singleton.hpp b/include/dbus_singleton.hpp
index a4a16bb2d1..2438152b3f 100644
--- a/include/dbus_singleton.hpp
+++ b/include/dbus_singleton.hpp
@@ -1,21 +1,28 @@
#pragma once
-#include <sdbusplus/asio/connection.hpp>
#include <iostream>
+#include <sdbusplus/asio/connection.hpp>
-namespace mapbox {
+namespace mapbox
+{
template <typename T, typename... Types>
-const T* getPtr(const mapbox::util::variant<Types...>& v) {
- if (v.template is<std::remove_const_t<T>>()) {
- return &v.template get_unchecked<std::remove_const_t<T>>();
- } else {
- return nullptr;
- }
+const T* getPtr(const mapbox::util::variant<Types...>& v)
+{
+ if (v.template is<std::remove_const_t<T>>())
+ {
+ return &v.template get_unchecked<std::remove_const_t<T>>();
+ }
+ else
+ {
+ return nullptr;
+ }
}
-} // namespace mapbox
+} // namespace mapbox
-namespace crow {
-namespace connections {
+namespace crow
+{
+namespace connections
+{
static std::shared_ptr<sdbusplus::asio::connection> systemBus;
-} // namespace connections
-} // namespace crow
+} // namespace connections
+} // namespace crow
diff --git a/include/gzip_helper.hpp b/include/gzip_helper.hpp
index e14fc1b50b..be13809236 100644
--- a/include/gzip_helper.hpp
+++ b/include/gzip_helper.hpp
@@ -1,56 +1,65 @@
#pragma once
#include <zlib.h>
+
#include <cstring>
#include <string>
inline bool gzipInflate(const std::string& compressedBytes,
- std::string& uncompressedBytes) {
- if (compressedBytes.empty()) {
- uncompressedBytes = compressedBytes;
- return true;
- }
-
- uncompressedBytes.clear();
+ std::string& uncompressedBytes)
+{
+ if (compressedBytes.empty())
+ {
+ uncompressedBytes = compressedBytes;
+ return true;
+ }
- unsigned half_length = compressedBytes.size() / 2;
+ uncompressedBytes.clear();
- z_stream strm{};
+ unsigned half_length = compressedBytes.size() / 2;
- // The following line is nolint because we're declaring away constness.
- // It's not clear why the input buffers on zlib aren't const, so this is a
- // bit of a cheat for the moment
- strm.next_in = (Bytef*)compressedBytes.data(); // NOLINT
- strm.avail_in = compressedBytes.size();
- strm.total_out = 0;
- strm.zalloc = Z_NULL;
- strm.zfree = Z_NULL;
+ z_stream strm{};
- bool done = false;
+ // The following line is nolint because we're declaring away constness.
+ // It's not clear why the input buffers on zlib aren't const, so this is a
+ // bit of a cheat for the moment
+ strm.next_in = (Bytef*)compressedBytes.data(); // NOLINT
+ strm.avail_in = compressedBytes.size();
+ strm.total_out = 0;
+ strm.zalloc = Z_NULL;
+ strm.zfree = Z_NULL;
- if (inflateInit2(&strm, (16 + MAX_WBITS)) != Z_OK) {
- return false;
- }
+ bool done = false;
- while (!done) {
- // If our output buffer is too small
- if (strm.total_out >= uncompressedBytes.size()) {
- uncompressedBytes.resize(uncompressedBytes.size() + half_length);
+ if (inflateInit2(&strm, (16 + MAX_WBITS)) != Z_OK)
+ {
+ return false;
}
- strm.next_out =
- (Bytef*)(uncompressedBytes.data() + strm.total_out); // NOLINT
- strm.avail_out =
- ((uLong)uncompressedBytes.size() - strm.total_out); // NOLINT
-
- // Inflate another chunk.
- int err = inflate(&strm, Z_SYNC_FLUSH);
- if (err == Z_STREAM_END) {
- done = true;
- } else if (err != Z_OK) {
- break;
+ while (!done)
+ {
+ // If our output buffer is too small
+ if (strm.total_out >= uncompressedBytes.size())
+ {
+ uncompressedBytes.resize(uncompressedBytes.size() + half_length);
+ }
+
+ strm.next_out =
+ (Bytef*)(uncompressedBytes.data() + strm.total_out); // NOLINT
+ strm.avail_out =
+ ((uLong)uncompressedBytes.size() - strm.total_out); // NOLINT
+
+ // Inflate another chunk.
+ int err = inflate(&strm, Z_SYNC_FLUSH);
+ if (err == Z_STREAM_END)
+ {
+ done = true;
+ }
+ else if (err != Z_OK)
+ {
+ break;
+ }
}
- }
- return inflateEnd(&strm) == Z_OK;
+ return inflateEnd(&strm) == Z_OK;
} \ No newline at end of file
diff --git a/include/http_utility.hpp b/include/http_utility.hpp
index f2d317206a..e13dfc0878 100644
--- a/include/http_utility.hpp
+++ b/include/http_utility.hpp
@@ -1,21 +1,27 @@
#pragma once
#include <boost/algorithm/string.hpp>
-namespace http_helpers {
-inline bool requestPrefersHtml(const crow::Request& req) {
- boost::string_view header = req.getHeaderValue("accept");
- std::vector<std::string> encodings;
- // chrome currently sends 6 accepts headers, firefox sends 4.
- encodings.reserve(6);
- boost::split(encodings, header, boost::is_any_of(", "),
- boost::token_compress_on);
- for (const std::string& encoding : encodings) {
- if (encoding == "text/html") {
- return true;
- } else if (encoding == "application/json") {
- return false;
+namespace http_helpers
+{
+inline bool requestPrefersHtml(const crow::Request& req)
+{
+ boost::string_view header = req.getHeaderValue("accept");
+ std::vector<std::string> encodings;
+ // chrome currently sends 6 accepts headers, firefox sends 4.
+ encodings.reserve(6);
+ boost::split(encodings, header, boost::is_any_of(", "),
+ boost::token_compress_on);
+ for (const std::string& encoding : encodings)
+ {
+ if (encoding == "text/html")
+ {
+ return true;
+ }
+ else if (encoding == "application/json")
+ {
+ return false;
+ }
}
- }
- return false;
+ return false;
}
-} // namespace http_helpers \ No newline at end of file
+} // namespace http_helpers \ No newline at end of file
diff --git a/include/image_upload.hpp b/include/image_upload.hpp
index df5c1ae491..2b84db8a33 100644
--- a/include/image_upload.hpp
+++ b/include/image_upload.hpp
@@ -1,103 +1,113 @@
#pragma once
-#include <dbus_singleton.hpp>
-#include <cstdio>
-#include <fstream>
-#include <memory>
#include <crow/app.h>
+
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
+#include <cstdio>
+#include <dbus_singleton.hpp>
+#include <fstream>
+#include <memory>
-namespace crow {
-namespace image_upload {
+namespace crow
+{
+namespace image_upload
+{
std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher;
inline void uploadImageHandler(const crow::Request& req, crow::Response& res,
- const std::string& filename) {
- // Only allow one FW update at a time
- if (fwUpdateMatcher != nullptr) {
- res.addHeader("Retry-After", "30");
- res.result(boost::beast::http::status::service_unavailable);
- res.end();
- return;
- }
- // Make this const static so it survives outside this method
- static boost::asio::deadline_timer timeout(*req.ioService,
- boost::posix_time::seconds(5));
-
- timeout.expires_from_now(boost::posix_time::seconds(5));
-
- timeout.async_wait([&res](const boost::system::error_code& ec) {
- fwUpdateMatcher = nullptr;
- if (ec == asio::error::operation_aborted) {
- // expected, we were canceled before the timer completed.
- return;
- }
- BMCWEB_LOG_ERROR << "Timed out waiting for log event";
-
- if (ec) {
- BMCWEB_LOG_ERROR << "Async_wait failed " << ec;
- return;
+ const std::string& filename)
+{
+ // Only allow one FW update at a time
+ if (fwUpdateMatcher != nullptr)
+ {
+ res.addHeader("Retry-After", "30");
+ res.result(boost::beast::http::status::service_unavailable);
+ res.end();
+ return;
}
+ // Make this const static so it survives outside this method
+ static boost::asio::deadline_timer timeout(*req.ioService,
+ boost::posix_time::seconds(5));
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
- });
+ timeout.expires_from_now(boost::posix_time::seconds(5));
- std::function<void(sdbusplus::message::message&)> callback =
- [&res](sdbusplus::message::message& m) {
- BMCWEB_LOG_DEBUG << "Match fired";
- boost::system::error_code ec;
- timeout.cancel(ec);
- if (ec) {
- BMCWEB_LOG_ERROR << "error canceling timer " << ec;
+ timeout.async_wait([&res](const boost::system::error_code& ec) {
+ fwUpdateMatcher = nullptr;
+ if (ec == asio::error::operation_aborted)
+ {
+ // expected, we were canceled before the timer completed.
+ return;
}
- std::string versionInfo;
- m.read(versionInfo); // Read in the object path that was just created
+ BMCWEB_LOG_ERROR << "Timed out waiting for log event";
- std::size_t index = versionInfo.rfind('/');
- if (index != std::string::npos) {
- versionInfo.erase(0, index);
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "Async_wait failed " << ec;
+ return;
}
- res.jsonValue = {{"data", std::move(versionInfo)},
- {"message", "200 OK"},
- {"status", "ok"}};
- BMCWEB_LOG_DEBUG << "ending response";
+
+ res.result(boost::beast::http::status::internal_server_error);
res.end();
- fwUpdateMatcher = nullptr;
- };
- fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
- *crow::connections::systemBus,
- "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
- "member='InterfacesAdded',path='/xyz/openbmc_project/logging'",
- callback);
+ });
+
+ std::function<void(sdbusplus::message::message&)> callback =
+ [&res](sdbusplus::message::message& m) {
+ BMCWEB_LOG_DEBUG << "Match fired";
+ boost::system::error_code ec;
+ timeout.cancel(ec);
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "error canceling timer " << ec;
+ }
+ std::string versionInfo;
+ m.read(
+ versionInfo); // Read in the object path that was just created
+
+ std::size_t index = versionInfo.rfind('/');
+ if (index != std::string::npos)
+ {
+ versionInfo.erase(0, index);
+ }
+ res.jsonValue = {{"data", std::move(versionInfo)},
+ {"message", "200 OK"},
+ {"status", "ok"}};
+ BMCWEB_LOG_DEBUG << "ending response";
+ res.end();
+ fwUpdateMatcher = nullptr;
+ };
+ fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
+ *crow::connections::systemBus,
+ "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
+ "member='InterfacesAdded',path='/xyz/openbmc_project/logging'",
+ callback);
- std::string filepath(
- "/tmp/images/" +
- boost::uuids::to_string(boost::uuids::random_generator()()));
- BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
- std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
- std::ofstream::trunc);
- out << req.body;
- out.close();
+ std::string filepath(
+ "/tmp/images/" +
+ boost::uuids::to_string(boost::uuids::random_generator()()));
+ BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
+ std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
+ std::ofstream::trunc);
+ out << req.body;
+ out.close();
}
-template <typename... Middlewares>
-void requestRoutes(Crow<Middlewares...>& app) {
- BMCWEB_ROUTE(app, "/upload/image/<str>")
- .methods("POST"_method,
- "PUT"_method)([](const crow::Request& req, crow::Response& res,
- const std::string& filename) {
- uploadImageHandler(req, res, filename);
- });
+template <typename... Middlewares> void requestRoutes(Crow<Middlewares...>& app)
+{
+ BMCWEB_ROUTE(app, "/upload/image/<str>")
+ .methods("POST"_method,
+ "PUT"_method)([](const crow::Request& req, crow::Response& res,
+ const std::string& filename) {
+ uploadImageHandler(req, res, filename);
+ });
- BMCWEB_ROUTE(app, "/upload/image")
- .methods("POST"_method,
- "PUT"_method)([](const crow::Request& req, crow::Response& res) {
- uploadImageHandler(req, res, "");
- });
+ BMCWEB_ROUTE(app, "/upload/image")
+ .methods("POST"_method, "PUT"_method)(
+ [](const crow::Request& req, crow::Response& res) {
+ uploadImageHandler(req, res, "");
+ });
}
-} // namespace image_upload
-} // namespace crow
+} // namespace image_upload
+} // namespace crow
diff --git a/include/openbmc_dbus_rest.hpp b/include/openbmc_dbus_rest.hpp
index 3e6443d29e..4f6c233ff7 100644
--- a/include/openbmc_dbus_rest.hpp
+++ b/include/openbmc_dbus_rest.hpp
@@ -1,64 +1,78 @@
#include <crow/app.h>
-
#include <tinyxml2.h>
+
+#include <boost/algorithm/string.hpp>
+#include <boost/container/flat_set.hpp>
#include <dbus_singleton.hpp>
#include <experimental/filesystem>
#include <fstream>
-#include <boost/algorithm/string.hpp>
-#include <boost/container/flat_set.hpp>
-namespace crow {
-namespace openbmc_mapper {
+namespace crow
+{
+namespace openbmc_mapper
+{
void introspectObjects(crow::Response &res, std::string process_name,
std::string path,
- std::shared_ptr<nlohmann::json> transaction) {
- crow::connections::systemBus->async_method_call(
- [
- &res, transaction, processName{std::move(process_name)},
- objectPath{std::move(path)}
- ](const boost::system::error_code ec, const std::string &introspect_xml) {
- if (ec) {
- BMCWEB_LOG_ERROR << "Introspect call failed with error: "
- << ec.message() << " on process: " << processName
- << " path: " << objectPath << "\n";
-
- } else {
- transaction->push_back({{"path", objectPath}});
-
- tinyxml2::XMLDocument doc;
-
- doc.Parse(introspect_xml.c_str());
- tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
- if (pRoot == nullptr) {
- BMCWEB_LOG_ERROR << "XML document failed to parse " << processName
- << " " << objectPath << "\n";
-
- } else {
- tinyxml2::XMLElement *node = pRoot->FirstChildElement("node");
- while (node != nullptr) {
- std::string childPath = node->Attribute("name");
- std::string newpath;
- if (objectPath != "/") {
- newpath += objectPath;
- }
- newpath += "/" + childPath;
- // introspect the subobjects as well
- introspectObjects(res, processName, newpath, transaction);
-
- node = node->NextSiblingElement("node");
+ std::shared_ptr<nlohmann::json> transaction)
+{
+ crow::connections::systemBus->async_method_call(
+ [&res, transaction, processName{std::move(process_name)},
+ objectPath{std::move(path)}](const boost::system::error_code ec,
+ const std::string &introspect_xml) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR
+ << "Introspect call failed with error: " << ec.message()
+ << " on process: " << processName << " path: " << objectPath
+ << "\n";
}
- }
- }
- // if we're the last outstanding caller, finish the request
- if (transaction.use_count() == 1) {
- res.jsonValue = {{"status", "ok"},
- {"bus_name", processName},
- {"objects", std::move(*transaction)}};
- res.end();
- }
- },
- process_name, path, "org.freedesktop.DBus.Introspectable", "Introspect");
+ else
+ {
+ transaction->push_back({{"path", objectPath}});
+
+ tinyxml2::XMLDocument doc;
+
+ doc.Parse(introspect_xml.c_str());
+ tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
+ if (pRoot == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "XML document failed to parse "
+ << processName << " " << objectPath
+ << "\n";
+ }
+ else
+ {
+ tinyxml2::XMLElement *node =
+ pRoot->FirstChildElement("node");
+ while (node != nullptr)
+ {
+ std::string childPath = node->Attribute("name");
+ std::string newpath;
+ if (objectPath != "/")
+ {
+ newpath += objectPath;
+ }
+ newpath += "/" + childPath;
+ // introspect the subobjects as well
+ introspectObjects(res, processName, newpath,
+ transaction);
+
+ node = node->NextSiblingElement("node");
+ }
+ }
+ }
+ // if we're the last outstanding caller, finish the request
+ if (transaction.use_count() == 1)
+ {
+ res.jsonValue = {{"status", "ok"},
+ {"bus_name", processName},
+ {"objects", std::move(*transaction)}};
+ res.end();
+ }
+ },
+ process_name, path, "org.freedesktop.DBus.Introspectable",
+ "Introspect");
}
// A smattering of common types to unpack. TODO(ed) this should really iterate
@@ -74,46 +88,60 @@ using ManagedObjectType = std::vector<std::pair<
std::string,
boost::container::flat_map<std::string, DbusRestVariantType>>>>;
-void getManagedObjectsForEnumerate(
- const std::string &object_name, const std::string &connection_name,
- crow::Response &res, std::shared_ptr<nlohmann::json> transaction) {
- crow::connections::systemBus->async_method_call(
- [&res, transaction](const boost::system::error_code ec,
- const ManagedObjectType &objects) {
- if (ec) {
- BMCWEB_LOG_ERROR << ec;
- } else {
- nlohmann::json &dataJson = *transaction;
-
- for (auto &objectPath : objects) {
- BMCWEB_LOG_DEBUG
- << "Reading object "
- << static_cast<const std::string &>(objectPath.first);
- nlohmann::json &objectJson =
- dataJson[static_cast<const std::string &>(objectPath.first)];
- if (objectJson.is_null()) {
- objectJson = nlohmann::json::object();
+void getManagedObjectsForEnumerate(const std::string &object_name,
+ const std::string &connection_name,
+ crow::Response &res,
+ std::shared_ptr<nlohmann::json> transaction)
+{
+ crow::connections::systemBus->async_method_call(
+ [&res, transaction](const boost::system::error_code ec,
+ const ManagedObjectType &objects) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << ec;
}
- for (const auto &interface : objectPath.second) {
- for (const auto &property : interface.second) {
- nlohmann::json &propertyJson = objectJson[property.first];
- mapbox::util::apply_visitor(
- [&propertyJson](auto &&val) { propertyJson = val; },
- property.second);
- }
+ else
+ {
+ nlohmann::json &dataJson = *transaction;
+
+ for (auto &objectPath : objects)
+ {
+ BMCWEB_LOG_DEBUG
+ << "Reading object "
+ << static_cast<const std::string &>(objectPath.first);
+ nlohmann::json &objectJson =
+ dataJson[static_cast<const std::string &>(
+ objectPath.first)];
+ if (objectJson.is_null())
+ {
+ objectJson = nlohmann::json::object();
+ }
+ for (const auto &interface : objectPath.second)
+ {
+ for (const auto &property : interface.second)
+ {
+ nlohmann::json &propertyJson =
+ objectJson[property.first];
+ mapbox::util::apply_visitor(
+ [&propertyJson](auto &&val) {
+ propertyJson = val;
+ },
+ property.second);
+ }
+ }
+ }
}
- }
- }
- if (transaction.use_count() == 1) {
- res.jsonValue = {{"message", "200 OK"},
- {"status", "ok"},
- {"data", std::move(*transaction)}};
- res.end();
- }
- },
- connection_name, object_name, "org.freedesktop.DBus.ObjectManager",
- "GetManagedObjects");
+ if (transaction.use_count() == 1)
+ {
+ res.jsonValue = {{"message", "200 OK"},
+ {"status", "ok"},
+ {"data", std::move(*transaction)}};
+ res.end();
+ }
+ },
+ connection_name, object_name, "org.freedesktop.DBus.ObjectManager",
+ "GetManagedObjects");
}
using GetSubTreeType = std::vector<
@@ -121,1025 +149,1320 @@ using GetSubTreeType = std::vector<
std::vector<std::pair<std::string, std::vector<std::string>>>>>;
// Structure for storing data on an in progress action
-struct InProgressActionData {
- InProgressActionData(crow::Response &res) : res(res){};
- ~InProgressActionData() {
- if (res.result() == boost::beast::http::status::internal_server_error) {
- // Reset the json object to clear out any data that made it in before the
- // error happened
- // todo(ed) handle error condition with proper code
- res.jsonValue = nlohmann::json::object();
+struct InProgressActionData
+{
+ InProgressActionData(crow::Response &res) : res(res){};
+ ~InProgressActionData()
+ {
+ if (res.result() == boost::beast::http::status::internal_server_error)
+ {
+ // Reset the json object to clear out any data that made it in
+ // before the error happened todo(ed) handle error condition with
+ // proper code
+ res.jsonValue = nlohmann::json::object();
+ }
+ res.end();
+ }
+
+ void setErrorStatus()
+ {
+ res.result(boost::beast::http::status::internal_server_error);
}
- res.end();
- }
-
- void setErrorStatus() {
- res.result(boost::beast::http::status::internal_server_error);
- }
- crow::Response &res;
- std::string path;
- std::string methodName;
- nlohmann::json arguments;
+ crow::Response &res;
+ std::string path;
+ std::string methodName;
+ nlohmann::json arguments;
};
-std::vector<std::string> dbusArgSplit(const std::string &string) {
- std::vector<std::string> ret;
- if (string.empty()) {
- return ret;
- }
- ret.push_back("");
- int containerDepth = 0;
-
- for (std::string::const_iterator character = string.begin();
- character != string.end(); character++) {
- ret.back() += *character;
- switch (*character) {
- case ('a'):
- break;
- case ('('):
- case ('{'):
- containerDepth++;
- break;
- case ('}'):
- case (')'):
- containerDepth--;
- if (containerDepth == 0) {
- if (character + 1 != string.end()) {
- ret.push_back("");
- }
- }
- break;
- default:
- if (containerDepth == 0) {
- if (character + 1 != string.end()) {
- ret.push_back("");
- }
+std::vector<std::string> dbusArgSplit(const std::string &string)
+{
+ std::vector<std::string> ret;
+ if (string.empty())
+ {
+ return ret;
+ }
+ ret.push_back("");
+ int containerDepth = 0;
+
+ for (std::string::const_iterator character = string.begin();
+ character != string.end(); character++)
+ {
+ ret.back() += *character;
+ switch (*character)
+ {
+ case ('a'):
+ break;
+ case ('('):
+ case ('{'):
+ containerDepth++;
+ break;
+ case ('}'):
+ case (')'):
+ containerDepth--;
+ if (containerDepth == 0)
+ {
+ if (character + 1 != string.end())
+ {
+ ret.push_back("");
+ }
+ }
+ break;
+ default:
+ if (containerDepth == 0)
+ {
+ if (character + 1 != string.end())
+ {
+ ret.push_back("");
+ }
+ }
+ break;
}
- break;
}
- }
}
int convertJsonToDbus(sd_bus_message *m, const std::string &arg_type,
- const nlohmann::json &input_json) {
- int r = 0;
- BMCWEB_LOG_DEBUG << "Converting " << input_json.dump()
- << " to type: " << arg_type;
- const std::vector<std::string> argTypes = dbusArgSplit(arg_type);
-
- // Assume a single object for now.
- const nlohmann::json *j = &input_json;
- nlohmann::json::const_iterator jIt = input_json.begin();
-
- for (const std::string &arg_code : argTypes) {
- // If we are decoding multiple objects, grab the pointer to the iterator,
- // and increment it for the next loop
- if (argTypes.size() > 1) {
- if (jIt == input_json.end()) {
- return -2;
- }
- j = &*jIt;
- jIt++;
- }
- const int64_t *int_value = j->get_ptr<const int64_t *>();
- const uint64_t *uint_value = j->get_ptr<const uint64_t *>();
- const std::string *string_value = j->get_ptr<const std::string *>();
- const double *double_value = j->get_ptr<const double *>();
- const bool *b = j->get_ptr<const bool *>();
- int64_t v = 0;
- double d = 0.0;
-
- // Do some basic type conversions that make sense. uint can be converted to
- // int. int and uint can be converted to double
- if (uint_value != nullptr && int_value == nullptr) {
- v = static_cast<int64_t>(*uint_value);
- int_value = &v;
- }
- if (uint_value != nullptr && double_value == nullptr) {
- d = static_cast<double>(*uint_value);
- double_value = &d;
- }
- if (int_value != nullptr && double_value == nullptr) {
- d = static_cast<double>(*int_value);
- double_value = &d;
- }
+ const nlohmann::json &input_json)
+{
+ int r = 0;
+ BMCWEB_LOG_DEBUG << "Converting " << input_json.dump()
+ << " to type: " << arg_type;
+ const std::vector<std::string> argTypes = dbusArgSplit(arg_type);
+
+ // Assume a single object for now.
+ const nlohmann::json *j = &input_json;
+ nlohmann::json::const_iterator jIt = input_json.begin();
+
+ for (const std::string &arg_code : argTypes)
+ {
+ // If we are decoding multiple objects, grab the pointer to the
+ // iterator, and increment it for the next loop
+ if (argTypes.size() > 1)
+ {
+ if (jIt == input_json.end())
+ {
+ return -2;
+ }
+ j = &*jIt;
+ jIt++;
+ }
+ const int64_t *int_value = j->get_ptr<const int64_t *>();
+ const uint64_t *uint_value = j->get_ptr<const uint64_t *>();
+ const std::string *string_value = j->get_ptr<const std::string *>();
+ const double *double_value = j->get_ptr<const double *>();
+ const bool *b = j->get_ptr<const bool *>();
+ int64_t v = 0;
+ double d = 0.0;
+
+ // Do some basic type conversions that make sense. uint can be
+ // converted to int. int and uint can be converted to double
+ if (uint_value != nullptr && int_value == nullptr)
+ {
+ v = static_cast<int64_t>(*uint_value);
+ int_value = &v;
+ }
+ if (uint_value != nullptr && double_value == nullptr)
+ {
+ d = static_cast<double>(*uint_value);
+ double_value = &d;
+ }
+ if (int_value != nullptr && double_value == nullptr)
+ {
+ d = static_cast<double>(*int_value);
+ double_value = &d;
+ }
- if (arg_code == "s") {
- if (string_value == nullptr) {
- return -1;
- }
- r = sd_bus_message_append_basic(m, arg_code[0],
- (void *)string_value->c_str());
- if (r < 0) {
- return r;
- }
- } else if (arg_code == "i") {
- if (int_value == nullptr) {
- return -1;
- }
- int32_t i = static_cast<int32_t>(*int_value);
- r = sd_bus_message_append_basic(m, arg_code[0], &i);
- if (r < 0) {
- return r;
- }
- } else if (arg_code == "b") {
- // lots of ways bool could be represented here. Try them all
- int bool_int = false;
- if (int_value != nullptr) {
- bool_int = *int_value > 0 ? 1 : 0;
- } else if (b != nullptr) {
- bool_int = b ? 1 : 0;
- } else if (string_value != nullptr) {
- bool_int = boost::istarts_with(*string_value, "t") ? 1 : 0;
- } else {
- return -1;
- }
- r = sd_bus_message_append_basic(m, arg_code[0], &bool_int);
- if (r < 0) {
- return r;
- }
- } else if (arg_code == "n") {
- if (int_value == nullptr) {
- return -1;
- }
- int16_t n = static_cast<int16_t>(*int_value);
- r = sd_bus_message_append_basic(m, arg_code[0], &n);
- if (r < 0) {
- return r;
- }
- } else if (arg_code == "x") {
- if (int_value == nullptr) {
- return -1;
- }
- r = sd_bus_message_append_basic(m, arg_code[0], int_value);
- if (r < 0) {
- return r;
- }
- } else if (arg_code == "y") {
- if (uint_value == nullptr) {
- return -1;
- }
- uint8_t y = static_cast<uint8_t>(*uint_value);
- r = sd_bus_message_append_basic(m, arg_code[0], &y);
- } else if (arg_code == "q") {
- if (uint_value == nullptr) {
- return -1;
- }
- uint16_t q = static_cast<uint16_t>(*uint_value);
- r = sd_bus_message_append_basic(m, arg_code[0], &q);
- } else if (arg_code == "u") {
- if (uint_value == nullptr) {
- return -1;
- }
- uint32_t u = static_cast<uint32_t>(*uint_value);
- r = sd_bus_message_append_basic(m, arg_code[0], &u);
- } else if (arg_code == "t") {
- if (uint_value == nullptr) {
- return -1;
- }
- r = sd_bus_message_append_basic(m, arg_code[0], uint_value);
- } else if (arg_code == "d") {
- sd_bus_message_append_basic(m, arg_code[0], double_value);
- } else if (boost::starts_with(arg_code, "a")) {
- std::string contained_type = arg_code.substr(1);
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
- contained_type.c_str());
- if (r < 0) {
- return r;
- }
-
- for (nlohmann::json::const_iterator it = j->begin(); it != j->end();
- ++it) {
- r = convertJsonToDbus(m, contained_type, *it);
- if (r < 0) {
- return r;
+ if (arg_code == "s")
+ {
+ if (string_value == nullptr)
+ {
+ return -1;
+ }
+ r = sd_bus_message_append_basic(m, arg_code[0],
+ (void *)string_value->c_str());
+ if (r < 0)
+ {
+ return r;
+ }
}
+ else if (arg_code == "i")
+ {
+ if (int_value == nullptr)
+ {
+ return -1;
+ }
+ int32_t i = static_cast<int32_t>(*int_value);
+ r = sd_bus_message_append_basic(m, arg_code[0], &i);
+ if (r < 0)
+ {
+ return r;
+ }
+ }
+ else if (arg_code == "b")
+ {
+ // lots of ways bool could be represented here. Try them all
+ int bool_int = false;
+ if (int_value != nullptr)
+ {
+ bool_int = *int_value > 0 ? 1 : 0;
+ }
+ else if (b != nullptr)
+ {
+ bool_int = b ? 1 : 0;
+ }
+ else if (string_value != nullptr)
+ {
+ bool_int = boost::istarts_with(*string_value, "t") ? 1 : 0;
+ }
+ else
+ {
+ return -1;
+ }
+ r = sd_bus_message_append_basic(m, arg_code[0], &bool_int);
+ if (r < 0)
+ {
+ return r;
+ }
+ }
+ else if (arg_code == "n")
+ {
+ if (int_value == nullptr)
+ {
+ return -1;
+ }
+ int16_t n = static_cast<int16_t>(*int_value);
+ r = sd_bus_message_append_basic(m, arg_code[0], &n);
+ if (r < 0)
+ {
+ return r;
+ }
+ }
+ else if (arg_code == "x")
+ {
+ if (int_value == nullptr)
+ {
+ return -1;
+ }
+ r = sd_bus_message_append_basic(m, arg_code[0], int_value);
+ if (r < 0)
+ {
+ return r;
+ }
+ }
+ else if (arg_code == "y")
+ {
+ if (uint_value == nullptr)
+ {
+ return -1;
+ }
+ uint8_t y = static_cast<uint8_t>(*uint_value);
+ r = sd_bus_message_append_basic(m, arg_code[0], &y);
+ }
+ else if (arg_code == "q")
+ {
+ if (uint_value == nullptr)
+ {
+ return -1;
+ }
+ uint16_t q = static_cast<uint16_t>(*uint_value);
+ r = sd_bus_message_append_basic(m, arg_code[0], &q);
+ }
+ else if (arg_code == "u")
+ {
+ if (uint_value == nullptr)
+ {
+ return -1;
+ }
+ uint32_t u = static_cast<uint32_t>(*uint_value);
+ r = sd_bus_message_append_basic(m, arg_code[0], &u);
+ }
+ else if (arg_code == "t")
+ {
+ if (uint_value == nullptr)
+ {
+ return -1;
+ }
+ r = sd_bus_message_append_basic(m, arg_code[0], uint_value);
+ }
+ else if (arg_code == "d")
+ {
+ sd_bus_message_append_basic(m, arg_code[0], double_value);
+ }
+ else if (boost::starts_with(arg_code, "a"))
+ {
+ std::string contained_type = arg_code.substr(1);
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_ARRAY,
+ contained_type.c_str());
+ if (r < 0)
+ {
+ return r;
+ }
+
+ for (nlohmann::json::const_iterator it = j->begin(); it != j->end();
+ ++it)
+ {
+ r = convertJsonToDbus(m, contained_type, *it);
+ if (r < 0)
+ {
+ return r;
+ }
- it++;
- }
- sd_bus_message_close_container(m);
- } else if (boost::starts_with(arg_code, "v")) {
- std::string contained_type = arg_code.substr(1);
- BMCWEB_LOG_DEBUG << "variant type: " << arg_code
- << " appending variant of type: " << contained_type;
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
- contained_type.c_str());
- if (r < 0) {
- return r;
- }
-
- r = convertJsonToDbus(m, contained_type, input_json);
- if (r < 0) {
- return r;
- }
-
- r = sd_bus_message_close_container(m);
- if (r < 0) {
- return r;
- }
- } else if (boost::starts_with(arg_code, "(") &&
- boost::ends_with(arg_code, ")")) {
- std::string contained_type = arg_code.substr(1, arg_code.size() - 1);
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
- contained_type.c_str());
- nlohmann::json::const_iterator it = j->begin();
- for (const std::string &arg_code : dbusArgSplit(arg_type)) {
- if (it == j->end()) {
- return -1;
+ it++;
+ }
+ sd_bus_message_close_container(m);
}
- r = convertJsonToDbus(m, arg_code, *it);
- if (r < 0) {
- return r;
+ else if (boost::starts_with(arg_code, "v"))
+ {
+ std::string contained_type = arg_code.substr(1);
+ BMCWEB_LOG_DEBUG
+ << "variant type: " << arg_code
+ << " appending variant of type: " << contained_type;
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_VARIANT,
+ contained_type.c_str());
+ if (r < 0)
+ {
+ return r;
+ }
+
+ r = convertJsonToDbus(m, contained_type, input_json);
+ if (r < 0)
+ {
+ return r;
+ }
+
+ r = sd_bus_message_close_container(m);
+ if (r < 0)
+ {
+ return r;
+ }
}
- it++;
- }
- r = sd_bus_message_close_container(m);
- } else if (boost::starts_with(arg_code, "{") &&
- boost::ends_with(arg_code, "}")) {
- std::string contained_type = arg_code.substr(1, arg_code.size() - 1);
- r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
- contained_type.c_str());
- std::vector<std::string> codes = dbusArgSplit(contained_type);
- if (codes.size() != 2) {
- return -1;
- }
- const std::string &key_type = codes[0];
- const std::string &value_type = codes[1];
- for (auto it : j->items()) {
- r = convertJsonToDbus(m, key_type, it.key());
- if (r < 0) {
- return r;
+ else if (boost::starts_with(arg_code, "(") &&
+ boost::ends_with(arg_code, ")"))
+ {
+ std::string contained_type =
+ arg_code.substr(1, arg_code.size() - 1);
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT,
+ contained_type.c_str());
+ nlohmann::json::const_iterator it = j->begin();
+ for (const std::string &arg_code : dbusArgSplit(arg_type))
+ {
+ if (it == j->end())
+ {
+ return -1;
+ }
+ r = convertJsonToDbus(m, arg_code, *it);
+ if (r < 0)
+ {
+ return r;
+ }
+ it++;
+ }
+ r = sd_bus_message_close_container(m);
}
+ else if (boost::starts_with(arg_code, "{") &&
+ boost::ends_with(arg_code, "}"))
+ {
+ std::string contained_type =
+ arg_code.substr(1, arg_code.size() - 1);
+ r = sd_bus_message_open_container(m, SD_BUS_TYPE_DICT_ENTRY,
+ contained_type.c_str());
+ std::vector<std::string> codes = dbusArgSplit(contained_type);
+ if (codes.size() != 2)
+ {
+ return -1;
+ }
+ const std::string &key_type = codes[0];
+ const std::string &value_type = codes[1];
+ for (auto it : j->items())
+ {
+ r = convertJsonToDbus(m, key_type, it.key());
+ if (r < 0)
+ {
+ return r;
+ }
- r = convertJsonToDbus(m, value_type, it.value());
- if (r < 0) {
- return r;
+ r = convertJsonToDbus(m, value_type, it.value());
+ if (r < 0)
+ {
+ return r;
+ }
+ }
+ r = sd_bus_message_close_container(m);
+ }
+ else
+ {
+ return -2;
+ }
+ if (r < 0)
+ {
+ return r;
}
- }
- r = sd_bus_message_close_container(m);
- } else {
- return -2;
- }
- if (r < 0) {
- return r;
- }
- if (argTypes.size() > 1) {
- jIt++;
+ if (argTypes.size() > 1)
+ {
+ jIt++;
+ }
}
- }
}
void findActionOnInterface(std::shared_ptr<InProgressActionData> transaction,
- const std::string &connectionName) {
- BMCWEB_LOG_DEBUG << "findActionOnInterface for connection " << connectionName;
- crow::connections::systemBus->async_method_call(
- [
- transaction, connectionName{std::string(connectionName)}
- ](const boost::system::error_code ec, const std::string &introspect_xml) {
- BMCWEB_LOG_DEBUG << "got xml:\n " << introspect_xml;
- if (ec) {
- BMCWEB_LOG_ERROR << "Introspect call failed with error: "
- << ec.message() << " on process: " << connectionName
- << "\n";
- } else {
- tinyxml2::XMLDocument doc;
-
- doc.Parse(introspect_xml.c_str());
- tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
- if (pRoot == nullptr) {
- BMCWEB_LOG_ERROR << "XML document failed to parse "
- << connectionName << "\n";
-
- } else {
- tinyxml2::XMLElement *interface_node =
- pRoot->FirstChildElement("interface");
- while (interface_node != nullptr) {
- std::string this_interface_name =
- interface_node->Attribute("name");
- tinyxml2::XMLElement *method_node =
- interface_node->FirstChildElement("method");
- while (method_node != nullptr) {
- std::string this_methodName = method_node->Attribute("name");
- BMCWEB_LOG_DEBUG << "Found method: " << this_methodName;
- if (this_methodName == transaction->methodName) {
- sdbusplus::message::message m =
- crow::connections::systemBus->new_method_call(
- connectionName.c_str(), transaction->path.c_str(),
- this_interface_name.c_str(),
- transaction->methodName.c_str());
-
- tinyxml2::XMLElement *argument_node =
- method_node->FirstChildElement("arg");
-
- nlohmann::json::const_iterator arg_it =
- transaction->arguments.begin();
-
- while (argument_node != nullptr) {
- std::string arg_direction =
- argument_node->Attribute("direction");
- if (arg_direction == "in") {
- std::string arg_type = argument_node->Attribute("type");
- if (arg_it == transaction->arguments.end()) {
- transaction->setErrorStatus();
- return;
- }
- if (convertJsonToDbus(m.get(), arg_type, *arg_it) < 0) {
- transaction->setErrorStatus();
- return;
- }
-
- arg_it++;
- }
- argument_node = method_node->NextSiblingElement("arg");
- }
- crow::connections::systemBus->async_send(
- m, [transaction](boost::system::error_code ec,
- sdbusplus::message::message &m) {
- if (ec) {
- transaction->setErrorStatus();
- return;
+ const std::string &connectionName)
+{
+ BMCWEB_LOG_DEBUG << "findActionOnInterface for connection "
+ << connectionName;
+ crow::connections::systemBus->async_method_call(
+ [transaction, connectionName{std::string(connectionName)}](
+ const boost::system::error_code ec,
+ const std::string &introspect_xml) {
+ BMCWEB_LOG_DEBUG << "got xml:\n " << introspect_xml;
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR
+ << "Introspect call failed with error: " << ec.message()
+ << " on process: " << connectionName << "\n";
+ }
+ else
+ {
+ tinyxml2::XMLDocument doc;
+
+ doc.Parse(introspect_xml.c_str());
+ tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
+ if (pRoot == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "XML document failed to parse "
+ << connectionName << "\n";
+ }
+ else
+ {
+ tinyxml2::XMLElement *interface_node =
+ pRoot->FirstChildElement("interface");
+ while (interface_node != nullptr)
+ {
+ std::string this_interface_name =
+ interface_node->Attribute("name");
+ tinyxml2::XMLElement *method_node =
+ interface_node->FirstChildElement("method");
+ while (method_node != nullptr)
+ {
+ std::string this_methodName =
+ method_node->Attribute("name");
+ BMCWEB_LOG_DEBUG << "Found method: "
+ << this_methodName;
+ if (this_methodName == transaction->methodName)
+ {
+ sdbusplus::message::message m =
+ crow::connections::systemBus
+ ->new_method_call(
+ connectionName.c_str(),
+ transaction->path.c_str(),
+ this_interface_name.c_str(),
+ transaction->methodName.c_str());
+
+ tinyxml2::XMLElement *argument_node =
+ method_node->FirstChildElement("arg");
+
+ nlohmann::json::const_iterator arg_it =
+ transaction->arguments.begin();
+
+ while (argument_node != nullptr)
+ {
+ std::string arg_direction =
+ argument_node->Attribute("direction");
+ if (arg_direction == "in")
+ {
+ std::string arg_type =
+ argument_node->Attribute("type");
+ if (arg_it ==
+ transaction->arguments.end())
+ {
+ transaction->setErrorStatus();
+ return;
+ }
+ if (convertJsonToDbus(m.get(), arg_type,
+ *arg_it) < 0)
+ {
+ transaction->setErrorStatus();
+ return;
+ }
+
+ arg_it++;
+ }
+ argument_node =
+ method_node->NextSiblingElement("arg");
+ }
+ crow::connections::systemBus->async_send(
+ m, [transaction](
+ boost::system::error_code ec,
+ sdbusplus::message::message &m) {
+ if (ec)
+ {
+ transaction->setErrorStatus();
+ return;
+ }
+ transaction->res.jsonValue = {
+ {"status", "ok"},
+ {"message", "200 OK"},
+ {"data", nullptr}};
+ });
+ break;
+ }
+ method_node =
+ method_node->NextSiblingElement("method");
}
- transaction->res.jsonValue = {{"status", "ok"},
- {"message", "200 OK"},
- {"data", nullptr}};
- });
- break;
+ interface_node =
+ interface_node->NextSiblingElement("interface");
+ }
}
- method_node = method_node->NextSiblingElement("method");
- }
- interface_node = interface_node->NextSiblingElement("interface");
}
- }
- }
- },
- connectionName, transaction->path, "org.freedesktop.DBus.Introspectable",
- "Introspect");
+ },
+ connectionName, transaction->path,
+ "org.freedesktop.DBus.Introspectable", "Introspect");
}
void handle_action(const crow::Request &req, crow::Response &res,
- const std::string &objectPath,
- const std::string &methodName) {
- nlohmann::json requestDbusData =
- nlohmann::json::parse(req.body, nullptr, false);
-
- if (requestDbusData.is_discarded()) {
- res.result(boost::beast::http::status::bad_request);
- res.end();
- return;
- }
- if (!requestDbusData.is_array()) {
- res.result(boost::beast::http::status::bad_request);
- res.end();
- return;
- }
- auto transaction = std::make_shared<InProgressActionData>(res);
-
- transaction->path = objectPath;
- transaction->methodName = methodName;
- transaction->arguments = std::move(requestDbusData);
- crow::connections::systemBus->async_method_call(
- [transaction](
- const boost::system::error_code ec,
- const std::vector<std::pair<std::string, std::vector<std::string>>>
- &interface_names) {
- if (ec || interface_names.size() <= 0) {
- transaction->setErrorStatus();
- return;
- }
+ const std::string &objectPath, const std::string &methodName)
+{
+ nlohmann::json requestDbusData =
+ nlohmann::json::parse(req.body, nullptr, false);
+
+ if (requestDbusData.is_discarded())
+ {
+ res.result(boost::beast::http::status::bad_request);
+ res.end();
+ return;
+ }
+ if (!requestDbusData.is_array())
+ {
+ res.result(boost::beast::http::status::bad_request);
+ res.end();
+ return;
+ }
+ auto transaction = std::make_shared<InProgressActionData>(res);
+
+ transaction->path = objectPath;
+ transaction->methodName = methodName;
+ transaction->arguments = std::move(requestDbusData);
+ crow::connections::systemBus->async_method_call(
+ [transaction](
+ const boost::system::error_code ec,
+ const std::vector<std::pair<std::string, std::vector<std::string>>>
+ &interface_names) {
+ if (ec || interface_names.size() <= 0)
+ {
+ transaction->setErrorStatus();
+ return;
+ }
- BMCWEB_LOG_DEBUG << "GetObject returned objects "
- << interface_names.size();
+ BMCWEB_LOG_DEBUG << "GetObject returned objects "
+ << interface_names.size();
- for (const std::pair<std::string, std::vector<std::string>> &object :
- interface_names) {
- findActionOnInterface(transaction, object.first);
- }
- },
- "xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper",
- "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
- std::array<std::string, 0>());
+ for (const std::pair<std::string, std::vector<std::string>>
+ &object : interface_names)
+ {
+ findActionOnInterface(transaction, object.first);
+ }
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetObject", objectPath,
+ std::array<std::string, 0>());
}
-void handle_list(crow::Response &res, const std::string &objectPath) {
- crow::connections::systemBus->async_method_call(
- [&res](const boost::system::error_code ec,
- std::vector<std::string> &objectPaths) {
- if (ec) {
- res.result(boost::beast::http::status::internal_server_error);
- } else {
- res.jsonValue = {{"status", "ok"},
- {"message", "200 OK"},
- {"data", std::move(objectPaths)}};
- }
- res.end();
- },
- "xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper",
- "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
- static_cast<int32_t>(99), std::array<std::string, 0>());
+void handle_list(crow::Response &res, const std::string &objectPath)
+{
+ crow::connections::systemBus->async_method_call(
+ [&res](const boost::system::error_code ec,
+ std::vector<std::string> &objectPaths) {
+ if (ec)
+ {
+ res.result(boost::beast::http::status::internal_server_error);
+ }
+ else
+ {
+ res.jsonValue = {{"status", "ok"},
+ {"message", "200 OK"},
+ {"data", std::move(objectPaths)}};
+ }
+ res.end();
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths", objectPath,
+ static_cast<int32_t>(99), std::array<std::string, 0>());
}
-void handle_enumerate(crow::Response &res, const std::string &objectPath) {
- crow::connections::systemBus->async_method_call(
- [&res, objectPath{std::string(objectPath)} ](
- const boost::system::error_code ec,
- const GetSubTreeType &object_names) {
- if (ec) {
- res.jsonValue = {{"message", "200 OK"},
- {"status", "ok"},
- {"data", nlohmann::json::object()}};
-
- res.end();
- return;
- }
+void handle_enumerate(crow::Response &res, const std::string &objectPath)
+{
+ crow::connections::systemBus->async_method_call(
+ [&res, objectPath{std::string(objectPath)}](
+ const boost::system::error_code ec,
+ const GetSubTreeType &object_names) {
+ if (ec)
+ {
+ res.jsonValue = {{"message", "200 OK"},
+ {"status", "ok"},
+ {"data", nlohmann::json::object()}};
- boost::container::flat_set<std::string> connections;
+ res.end();
+ return;
+ }
- for (const auto &object : object_names) {
- for (const auto &Connection : object.second) {
- connections.insert(Connection.first);
- }
- }
+ boost::container::flat_set<std::string> connections;
- if (connections.size() <= 0) {
- res.result(boost::beast::http::status::not_found);
- res.end();
- return;
- }
- auto transaction =
- std::make_shared<nlohmann::json>(nlohmann::json::object());
- for (const std::string &Connection : connections) {
- getManagedObjectsForEnumerate(objectPath, Connection, res,
- transaction);
- }
- },
- "xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper",
- "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath, (int32_t)0,
- std::array<std::string, 0>());
+ for (const auto &object : object_names)
+ {
+ for (const auto &Connection : object.second)
+ {
+ connections.insert(Connection.first);
+ }
+ }
+
+ if (connections.size() <= 0)
+ {
+ res.result(boost::beast::http::status::not_found);
+ res.end();
+ return;
+ }
+ auto transaction =
+ std::make_shared<nlohmann::json>(nlohmann::json::object());
+ for (const std::string &Connection : connections)
+ {
+ getManagedObjectsForEnumerate(objectPath, Connection, res,
+ transaction);
+ }
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree", objectPath,
+ (int32_t)0, std::array<std::string, 0>());
}
void handle_get(crow::Response &res, std::string &objectPath,
- std::string &destProperty) {
- BMCWEB_LOG_DEBUG << "handle_get: " << objectPath << " prop:" << destProperty;
- std::shared_ptr<std::string> property_name =
- std::make_shared<std::string>(std::move(destProperty));
-
- std::shared_ptr<std::string> path =
- std::make_shared<std::string>(std::move(objectPath));
-
- using GetObjectType =
- std::vector<std::pair<std::string, std::vector<std::string>>>;
- crow::connections::systemBus->async_method_call(
- [&res, path, property_name](const boost::system::error_code ec,
- const GetObjectType &object_names) {
- if (ec || object_names.size() <= 0) {
- res.result(boost::beast::http::status::not_found);
- res.end();
- return;
- }
- std::shared_ptr<nlohmann::json> response =
- std::make_shared<nlohmann::json>(nlohmann::json::object());
- // The mapper should never give us an empty interface names list, but
- // check anyway
- for (const std::pair<std::string, std::vector<std::string>> connection :
- object_names) {
- const std::vector<std::string> &interfaceNames = connection.second;
-
- if (interfaceNames.size() <= 0) {
- res.result(boost::beast::http::status::not_found);
- res.end();
- return;
- }
-
- for (const std::string &interface : interfaceNames) {
- crow::connections::systemBus->async_method_call(
- [&res, response, property_name](
- const boost::system::error_code ec,
- const std::vector<std::pair<
- std::string, DbusRestVariantType>> &properties) {
- if (ec) {
- BMCWEB_LOG_ERROR << "Bad dbus request error: " << ec;
- } else {
- for (const std::pair<std::string, DbusRestVariantType>
- &property : properties) {
- // if property name is empty, or matches our search query,
- // add it to the response json
-
- if (property_name->empty()) {
- mapbox::util::apply_visitor(
- [&response, &property](auto &&val) {
- (*response)[property.first] = val;
- },
- property.second);
- } else if (property.first == *property_name) {
- mapbox::util::apply_visitor(
- [&response](auto &&val) { (*response) = val; },
- property.second);
- }
- }
- }
- if (response.use_count() == 1) {
- res.jsonValue = {{"status", "ok"},
- {"message", "200 OK"},
- {"data", *response}};
-
+ std::string &destProperty)
+{
+ BMCWEB_LOG_DEBUG << "handle_get: " << objectPath
+ << " prop:" << destProperty;
+ std::shared_ptr<std::string> property_name =
+ std::make_shared<std::string>(std::move(destProperty));
+
+ std::shared_ptr<std::string> path =
+ std::make_shared<std::string>(std::move(objectPath));
+
+ using GetObjectType =
+ std::vector<std::pair<std::string, std::vector<std::string>>>;
+ crow::connections::systemBus->async_method_call(
+ [&res, path, property_name](const boost::system::error_code ec,
+ const GetObjectType &object_names) {
+ if (ec || object_names.size() <= 0)
+ {
+ res.result(boost::beast::http::status::not_found);
+ res.end();
+ return;
+ }
+ std::shared_ptr<nlohmann::json> response =
+ std::make_shared<nlohmann::json>(nlohmann::json::object());
+ // The mapper should never give us an empty interface names list,
+ // but check anyway
+ for (const std::pair<std::string, std::vector<std::string>>
+ connection : object_names)
+ {
+ const std::vector<std::string> &interfaceNames =
+ connection.second;
+
+ if (interfaceNames.size() <= 0)
+ {
+ res.result(boost::beast::http::status::not_found);
res.end();
- }
- },
- connection.first, *path, "org.freedesktop.DBus.Properties",
- "GetAll", interface);
- }
- }
- },
- "xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper",
- "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
- std::array<std::string, 0>());
+ return;
+ }
+
+ for (const std::string &interface : interfaceNames)
+ {
+ crow::connections::systemBus->async_method_call(
+ [&res, response, property_name](
+ const boost::system::error_code ec,
+ const std::vector<
+ std::pair<std::string, DbusRestVariantType>>
+ &properties) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "Bad dbus request error: "
+ << ec;
+ }
+ else
+ {
+ for (const std::pair<std::string,
+ DbusRestVariantType>
+ &property : properties)
+ {
+ // if property name is empty, or matches our
+ // search query, add it to the response json
+
+ if (property_name->empty())
+ {
+ mapbox::util::apply_visitor(
+ [&response, &property](auto &&val) {
+ (*response)[property.first] =
+ val;
+ },
+ property.second);
+ }
+ else if (property.first == *property_name)
+ {
+ mapbox::util::apply_visitor(
+ [&response](auto &&val) {
+ (*response) = val;
+ },
+ property.second);
+ }
+ }
+ }
+ if (response.use_count() == 1)
+ {
+ res.jsonValue = {{"status", "ok"},
+ {"message", "200 OK"},
+ {"data", *response}};
+
+ res.end();
+ }
+ },
+ connection.first, *path,
+ "org.freedesktop.DBus.Properties", "GetAll", interface);
+ }
+ }
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetObject", *path,
+ std::array<std::string, 0>());
}
-struct AsyncPutRequest {
- AsyncPutRequest(crow::Response &res) : res(res) {
- res.jsonValue = {
- {"status", "ok"}, {"message", "200 OK"}, {"data", nullptr}};
- }
- ~AsyncPutRequest() {
- if (res.result() == boost::beast::http::status::internal_server_error) {
- // Reset the json object to clear out any data that made it in before the
- // error happened
- // todo(ed) handle error condition with proper code
- res.jsonValue = nlohmann::json::object();
+struct AsyncPutRequest
+{
+ AsyncPutRequest(crow::Response &res) : res(res)
+ {
+ res.jsonValue = {
+ {"status", "ok"}, {"message", "200 OK"}, {"data", nullptr}};
}
+ ~AsyncPutRequest()
+ {
+ if (res.result() == boost::beast::http::status::internal_server_error)
+ {
+ // Reset the json object to clear out any data that made it in
+ // before the error happened todo(ed) handle error condition with
+ // proper code
+ res.jsonValue = nlohmann::json::object();
+ }
- if (res.jsonValue.empty()) {
- res.result(boost::beast::http::status::forbidden);
- res.jsonValue = {
- {"status", "error"},
- {"message", "403 Forbidden"},
- {"data",
- {{"message",
- "The specified property cannot be created: " + propertyName}}}};
- }
+ if (res.jsonValue.empty())
+ {
+ res.result(boost::beast::http::status::forbidden);
+ res.jsonValue = {
+ {"status", "error"},
+ {"message", "403 Forbidden"},
+ {"data",
+ {{"message", "The specified property cannot be created: " +
+ propertyName}}}};
+ }
- res.end();
- }
+ res.end();
+ }
- void setErrorStatus() {
- res.result(boost::beast::http::status::internal_server_error);
- }
+ void setErrorStatus()
+ {
+ res.result(boost::beast::http::status::internal_server_error);
+ }
- crow::Response &res;
- std::string objectPath;
- std::string propertyName;
- nlohmann::json propertyValue;
+ crow::Response &res;
+ std::string objectPath;
+ std::string propertyName;
+ nlohmann::json propertyValue;
};
void handlePut(const crow::Request &req, crow::Response &res,
- const std::string &objectPath, const std::string &destProperty) {
- nlohmann::json requestDbusData =
- nlohmann::json::parse(req.body, nullptr, false);
-
- if (requestDbusData.is_discarded()) {
- res.result(boost::beast::http::status::bad_request);
- res.end();
- return;
- }
-
- nlohmann::json::const_iterator propertyIt = requestDbusData.find("data");
- if (propertyIt == requestDbusData.end()) {
- res.result(boost::beast::http::status::bad_request);
- res.end();
- return;
- }
- const nlohmann::json &propertySetValue = *propertyIt;
- auto transaction = std::make_shared<AsyncPutRequest>(res);
- transaction->objectPath = objectPath;
- transaction->propertyName = destProperty;
- transaction->propertyValue = propertySetValue;
-
- using GetObjectType =
- std::vector<std::pair<std::string, std::vector<std::string>>>;
-
- crow::connections::systemBus->async_method_call(
- [transaction](const boost::system::error_code ec,
- const GetObjectType &object_names) {
- if (!ec && object_names.size() <= 0) {
- transaction->res.result(boost::beast::http::status::not_found);
- return;
- }
+ const std::string &objectPath, const std::string &destProperty)
+{
+ nlohmann::json requestDbusData =
+ nlohmann::json::parse(req.body, nullptr, false);
+
+ if (requestDbusData.is_discarded())
+ {
+ res.result(boost::beast::http::status::bad_request);
+ res.end();
+ return;
+ }
- for (const std::pair<std::string, std::vector<std::string>> connection :
- object_names) {
- const std::string &connectionName = connection.first;
-
- crow::connections::systemBus->async_method_call(
- [ connectionName{std::string(connectionName)}, transaction ](
- const boost::system::error_code ec,
- const std::string &introspectXml) {
- if (ec) {
- BMCWEB_LOG_ERROR
- << "Introspect call failed with error: " << ec.message()
- << " on process: " << connectionName;
- transaction->setErrorStatus();
- return;
- }
- tinyxml2::XMLDocument doc;
+ nlohmann::json::const_iterator propertyIt = requestDbusData.find("data");
+ if (propertyIt == requestDbusData.end())
+ {
+ res.result(boost::beast::http::status::bad_request);
+ res.end();
+ return;
+ }
+ const nlohmann::json &propertySetValue = *propertyIt;
+ auto transaction = std::make_shared<AsyncPutRequest>(res);
+ transaction->objectPath = objectPath;
+ transaction->propertyName = destProperty;
+ transaction->propertyValue = propertySetValue;
+
+ using GetObjectType =
+ std::vector<std::pair<std::string, std::vector<std::string>>>;
+
+ crow::connections::systemBus->async_method_call(
+ [transaction](const boost::system::error_code ec,
+ const GetObjectType &object_names) {
+ if (!ec && object_names.size() <= 0)
+ {
+ transaction->res.result(boost::beast::http::status::not_found);
+ return;
+ }
- doc.Parse(introspectXml.c_str());
- tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
- if (pRoot == nullptr) {
- BMCWEB_LOG_ERROR << "XML document failed to parse: "
- << introspectXml;
- transaction->setErrorStatus();
- return;
- }
- tinyxml2::XMLElement *ifaceNode =
- pRoot->FirstChildElement("interface");
- while (ifaceNode != nullptr) {
- const char *interfaceName = ifaceNode->Attribute("name");
- BMCWEB_LOG_DEBUG << "found interface " << interfaceName;
- tinyxml2::XMLElement *propNode =
- ifaceNode->FirstChildElement("property");
- while (propNode != nullptr) {
- const char *propertyName = propNode->Attribute("name");
- BMCWEB_LOG_DEBUG << "Found property " << propertyName;
- if (propertyName == transaction->propertyName) {
- const char *argType = propNode->Attribute("type");
- if (argType != nullptr) {
- sdbusplus::message::message m =
- crow::connections::systemBus->new_method_call(
- connectionName.c_str(),
- transaction->objectPath.c_str(),
- "org.freedesktop.DBus.Properties", "Set");
- m.append(interfaceName, transaction->propertyName);
- int r = sd_bus_message_open_container(
- m.get(), SD_BUS_TYPE_VARIANT, argType);
- if (r < 0) {
- transaction->setErrorStatus();
- return;
+ for (const std::pair<std::string, std::vector<std::string>>
+ connection : object_names)
+ {
+ const std::string &connectionName = connection.first;
+
+ crow::connections::systemBus->async_method_call(
+ [connectionName{std::string(connectionName)},
+ transaction](const boost::system::error_code ec,
+ const std::string &introspectXml) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR
+ << "Introspect call failed with error: "
+ << ec.message()
+ << " on process: " << connectionName;
+ transaction->setErrorStatus();
+ return;
}
- r = convertJsonToDbus(m.get(), argType,
- transaction->propertyValue);
- if (r < 0) {
- transaction->setErrorStatus();
- return;
+ tinyxml2::XMLDocument doc;
+
+ doc.Parse(introspectXml.c_str());
+ tinyxml2::XMLNode *pRoot =
+ doc.FirstChildElement("node");
+ if (pRoot == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "XML document failed to parse: "
+ << introspectXml;
+ transaction->setErrorStatus();
+ return;
}
- r = sd_bus_message_close_container(m.get());
- if (r < 0) {
- transaction->setErrorStatus();
- return;
+ tinyxml2::XMLElement *ifaceNode =
+ pRoot->FirstChildElement("interface");
+ while (ifaceNode != nullptr)
+ {
+ const char *interfaceName =
+ ifaceNode->Attribute("name");
+ BMCWEB_LOG_DEBUG << "found interface "
+ << interfaceName;
+ tinyxml2::XMLElement *propNode =
+ ifaceNode->FirstChildElement("property");
+ while (propNode != nullptr)
+ {
+ const char *propertyName =
+ propNode->Attribute("name");
+ BMCWEB_LOG_DEBUG << "Found property "
+ << propertyName;
+ if (propertyName == transaction->propertyName)
+ {
+ const char *argType =
+ propNode->Attribute("type");
+ if (argType != nullptr)
+ {
+ sdbusplus::message::message m =
+ crow::connections::systemBus
+ ->new_method_call(
+ connectionName.c_str(),
+ transaction->objectPath
+ .c_str(),
+ "org.freedesktop.DBus."
+ "Properties",
+ "Set");
+ m.append(interfaceName,
+ transaction->propertyName);
+ int r = sd_bus_message_open_container(
+ m.get(), SD_BUS_TYPE_VARIANT,
+ argType);
+ if (r < 0)
+ {
+ transaction->setErrorStatus();
+ return;
+ }
+ r = convertJsonToDbus(
+ m.get(), argType,
+ transaction->propertyValue);
+ if (r < 0)
+ {
+ transaction->setErrorStatus();
+ return;
+ }
+ r = sd_bus_message_close_container(
+ m.get());
+ if (r < 0)
+ {
+ transaction->setErrorStatus();
+ return;
+ }
+
+ crow::connections::systemBus
+ ->async_send(
+ m,
+ [transaction](
+ boost::system::error_code
+ ec,
+ sdbusplus::message::message
+ &m) {
+ BMCWEB_LOG_DEBUG << "sent";
+ if (ec)
+ {
+ transaction->res
+ .jsonValue
+ ["status"] =
+ "error";
+ transaction->res
+ .jsonValue
+ ["message"] =
+ ec.message();
+ }
+ });
+ }
+ }
+ propNode =
+ propNode->NextSiblingElement("property");
+ }
+ ifaceNode =
+ ifaceNode->NextSiblingElement("interface");
}
-
- crow::connections::systemBus->async_send(
- m, [transaction](boost::system::error_code ec,
- sdbusplus::message::message &m) {
- BMCWEB_LOG_DEBUG << "sent";
- if (ec) {
- transaction->res.jsonValue["status"] = "error";
- transaction->res.jsonValue["message"] =
- ec.message();
- }
- });
- }
- }
- propNode = propNode->NextSiblingElement("property");
- }
- ifaceNode = ifaceNode->NextSiblingElement("interface");
- }
- },
- connectionName, transaction->objectPath,
- "org.freedesktop.DBus.Introspectable", "Introspect");
- }
- },
- "xyz.openbmc_project.ObjectMapper", "/xyz/openbmc_project/object_mapper",
- "xyz.openbmc_project.ObjectMapper", "GetObject", transaction->objectPath,
- std::array<std::string, 0>());
+ },
+ connectionName, transaction->objectPath,
+ "org.freedesktop.DBus.Introspectable", "Introspect");
+ }
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetObject",
+ transaction->objectPath, std::array<std::string, 0>());
}
-template <typename... Middlewares>
-void requestRoutes(Crow<Middlewares...> &app) {
- BMCWEB_ROUTE(app, "/bus/")
- .methods("GET"_method)([](const crow::Request &req, crow::Response &res) {
- res.jsonValue = {{"busses", {{{"name", "system"}}}}, {"status", "ok"}};
- });
-
- BMCWEB_ROUTE(app, "/bus/system/")
- .methods("GET"_method)([](const crow::Request &req, crow::Response &res) {
-
- auto myCallback = [&res](const boost::system::error_code ec,
- std::vector<std::string> &names) {
- if (ec) {
- BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
- res.result(boost::beast::http::status::internal_server_error);
- } else {
- std::sort(names.begin(), names.end());
- nlohmann::json j{{"status", "ok"}};
- auto &objectsSub = j["objects"];
- for (auto &name : names) {
- objectsSub.push_back({{"name", name}});
+template <typename... Middlewares> void requestRoutes(Crow<Middlewares...> &app)
+{
+ BMCWEB_ROUTE(app, "/bus/")
+ .methods("GET"_method)(
+ [](const crow::Request &req, crow::Response &res) {
+ res.jsonValue = {{"busses", {{{"name", "system"}}}},
+ {"status", "ok"}};
+ });
+
+ BMCWEB_ROUTE(app, "/bus/system/")
+ .methods("GET"_method)(
+ [](const crow::Request &req, crow::Response &res) {
+ auto myCallback = [&res](const boost::system::error_code ec,
+ std::vector<std::string> &names) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "Dbus call failed with code " << ec;
+ res.result(
+ boost::beast::http::status::internal_server_error);
+ }
+ else
+ {
+ std::sort(names.begin(), names.end());
+ nlohmann::json j{{"status", "ok"}};
+ auto &objectsSub = j["objects"];
+ for (auto &name : names)
+ {
+ objectsSub.push_back({{"name", name}});
+ }
+ res.jsonValue = std::move(j);
+ }
+ res.end();
+ };
+ crow::connections::systemBus->async_method_call(
+ std::move(myCallback), "org.freedesktop.DBus", "/",
+ "org.freedesktop.DBus", "ListNames");
+ });
+
+ BMCWEB_ROUTE(app, "/list/")
+ .methods("GET"_method)(
+ [](const crow::Request &req, crow::Response &res) {
+ handle_list(res, "/");
+ });
+
+ BMCWEB_ROUTE(app, "/xyz/<path>")
+ .methods("GET"_method, "PUT"_method,
+ "POST"_method)([](const crow::Request &req,
+ crow::Response &res,
+ const std::string &path) {
+ std::string objectPath = "/xyz/" + path;
+
+ // Trim any trailing "/" at the end
+ if (boost::ends_with(objectPath, "/"))
+ {
+ objectPath.pop_back();
}
- res.jsonValue = std::move(j);
- }
- res.end();
- };
- crow::connections::systemBus->async_method_call(
- std::move(myCallback), "org.freedesktop.DBus", "/",
- "org.freedesktop.DBus", "ListNames");
- });
-
- BMCWEB_ROUTE(app, "/list/")
- .methods("GET"_method)([](const crow::Request &req, crow::Response &res) {
- handle_list(res, "/");
- });
-
- BMCWEB_ROUTE(app, "/xyz/<path>")
- .methods("GET"_method, "PUT"_method,
- "POST"_method)([](const crow::Request &req, crow::Response &res,
- const std::string &path) {
- std::string objectPath = "/xyz/" + path;
-
- // Trim any trailing "/" at the end
- if (boost::ends_with(objectPath, "/")) {
- objectPath.pop_back();
- }
-
- // If accessing a single attribute, fill in and update objectPath,
- // otherwise leave destProperty blank
- std::string destProperty = "";
- const char *attrSeperator = "/attr/";
- size_t attrPosition = path.find(attrSeperator);
- if (attrPosition != path.npos) {
- objectPath = "/xyz/" + path.substr(0, attrPosition);
- destProperty =
- path.substr(attrPosition + strlen(attrSeperator), path.length());
- }
-
- if (req.method() == "POST"_method) {
- constexpr const char *action_seperator = "/action/";
- size_t action_position = path.find(action_seperator);
- if (action_position != path.npos) {
- objectPath = "/xyz/" + path.substr(0, action_position);
- std::string post_property = path.substr(
- (action_position + strlen(action_seperator)), path.length());
- handle_action(req, res, objectPath, post_property);
- return;
- }
- } else if (req.method() == "GET"_method) {
- if (boost::ends_with(objectPath, "/enumerate")) {
- objectPath.erase(objectPath.end() - 10, objectPath.end());
- handle_enumerate(res, objectPath);
- } else if (boost::ends_with(objectPath, "/list")) {
- objectPath.erase(objectPath.end() - 5, objectPath.end());
- handle_list(res, objectPath);
- } else {
- handle_get(res, objectPath, destProperty);
- }
- return;
- } else if (req.method() == "PUT"_method) {
- handlePut(req, res, objectPath, destProperty);
- return;
- }
- res.result(boost::beast::http::status::method_not_allowed);
- res.end();
- });
-
- BMCWEB_ROUTE(app, "/bus/system/<str>/")
- .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
- const std::string &Connection) {
- std::shared_ptr<nlohmann::json> transaction;
- introspectObjects(res, Connection, "/", transaction);
- });
-
- BMCWEB_ROUTE(app, "/download/dump/<str>/")
- .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
- const std::string &dumpId) {
- std::regex validFilename("^[\\w\\- ]+(\\.?[\\w\\- ]+)$");
- if (!std::regex_match(dumpId, validFilename)) {
- res.result(boost::beast::http::status::not_found);
- res.end();
- return;
- }
- std::experimental::filesystem::path loc(
- "/var/lib/phosphor-debug-collector/dumps");
+ // If accessing a single attribute, fill in and update objectPath,
+ // otherwise leave destProperty blank
+ std::string destProperty = "";
+ const char *attrSeperator = "/attr/";
+ size_t attrPosition = path.find(attrSeperator);
+ if (attrPosition != path.npos)
+ {
+ objectPath = "/xyz/" + path.substr(0, attrPosition);
+ destProperty = path.substr(attrPosition + strlen(attrSeperator),
+ path.length());
+ }
- loc += dumpId;
+ if (req.method() == "POST"_method)
+ {
+ constexpr const char *action_seperator = "/action/";
+ size_t action_position = path.find(action_seperator);
+ if (action_position != path.npos)
+ {
+ objectPath = "/xyz/" + path.substr(0, action_position);
+ std::string post_property = path.substr(
+ (action_position + strlen(action_seperator)),
+ path.length());
+ handle_action(req, res, objectPath, post_property);
+ return;
+ }
+ }
+ else if (req.method() == "GET"_method)
+ {
+ if (boost::ends_with(objectPath, "/enumerate"))
+ {
+ objectPath.erase(objectPath.end() - 10, objectPath.end());
+ handle_enumerate(res, objectPath);
+ }
+ else if (boost::ends_with(objectPath, "/list"))
+ {
+ objectPath.erase(objectPath.end() - 5, objectPath.end());
+ handle_list(res, objectPath);
+ }
+ else
+ {
+ handle_get(res, objectPath, destProperty);
+ }
+ return;
+ }
+ else if (req.method() == "PUT"_method)
+ {
+ handlePut(req, res, objectPath, destProperty);
+ return;
+ }
- if (!std::experimental::filesystem::exists(loc) ||
- !std::experimental::filesystem::is_directory(loc)) {
- res.result(boost::beast::http::status::not_found);
- res.end();
- return;
- }
- std::experimental::filesystem::directory_iterator files(loc);
- for (auto &file : files) {
- std::ifstream readFile(file.path());
- if (readFile.good()) {
- continue;
- }
- res.addHeader("Content-Type", "application/octet-stream");
- res.body() = {std::istreambuf_iterator<char>(readFile),
- std::istreambuf_iterator<char>()};
- res.end();
- }
- res.result(boost::beast::http::status::not_found);
- res.end();
- return;
- });
-
- BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
- .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
- const std::string &processName,
- const std::string &requestedPath) {
- std::vector<std::string> strs;
- boost::split(strs, requestedPath, boost::is_any_of("/"));
- std::string objectPath;
- std::string interfaceName;
- std::string methodName;
- auto it = strs.begin();
- if (it == strs.end()) {
- objectPath = "/";
- }
- while (it != strs.end()) {
- // Check if segment contains ".". If it does, it must be an
- // interface
- if (it->find(".") != std::string::npos) {
- break;
- // THis check is neccesary as the trailing slash gets parsed as
- // part of our <path> specifier above, which causes the normal
- // trailing backslash redirector to fail.
- } else if (!it->empty()) {
- objectPath += "/" + *it;
- }
- it++;
- }
- if (it != strs.end()) {
- interfaceName = *it;
- it++;
-
- // after interface, we might have a method name
- if (it != strs.end()) {
- methodName = *it;
- it++;
- }
- }
- if (it != strs.end()) {
- // if there is more levels past the method name, something went
- // wrong, return not found
- res.result(boost::beast::http::status::not_found);
- res.end();
- return;
- }
- if (interfaceName.empty()) {
- crow::connections::systemBus->async_method_call(
- [&, processName, objectPath](const boost::system::error_code ec,
- const std::string &introspect_xml) {
- if (ec) {
- BMCWEB_LOG_ERROR
- << "Introspect call failed with error: " << ec.message()
- << " on process: " << processName
- << " path: " << objectPath << "\n";
-
- } else {
- tinyxml2::XMLDocument doc;
-
- doc.Parse(introspect_xml.c_str());
- tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
- if (pRoot == nullptr) {
- BMCWEB_LOG_ERROR << "XML document failed to parse "
- << processName << " " << objectPath
- << "\n";
- res.jsonValue = {{"status", "XML parse error"}};
- res.result(
- boost::beast::http::status::internal_server_error);
- } else {
- nlohmann::json interfacesArray = nlohmann::json::array();
- tinyxml2::XMLElement *interface =
- pRoot->FirstChildElement("interface");
+ res.result(boost::beast::http::status::method_not_allowed);
+ res.end();
+ });
+
+ BMCWEB_ROUTE(app, "/bus/system/<str>/")
+ .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
+ const std::string &Connection) {
+ std::shared_ptr<nlohmann::json> transaction;
+ introspectObjects(res, Connection, "/", transaction);
+ });
+
+ BMCWEB_ROUTE(app, "/download/dump/<str>/")
+ .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
+ const std::string &dumpId) {
+ std::regex validFilename("^[\\w\\- ]+(\\.?[\\w\\- ]+)$");
+ if (!std::regex_match(dumpId, validFilename))
+ {
+ res.result(boost::beast::http::status::not_found);
+ res.end();
+ return;
+ }
+ std::experimental::filesystem::path loc(
+ "/var/lib/phosphor-debug-collector/dumps");
- while (interface != nullptr) {
- std::string ifaceName = interface->Attribute("name");
- interfacesArray.push_back({{"name", ifaceName}});
+ loc += dumpId;
- interface = interface->NextSiblingElement("interface");
- }
- res.jsonValue = {{"status", "ok"},
- {"bus_name", processName},
- {"interfaces", interfacesArray},
- {"objectPath", objectPath}};
- }
+ if (!std::experimental::filesystem::exists(loc) ||
+ !std::experimental::filesystem::is_directory(loc))
+ {
+ res.result(boost::beast::http::status::not_found);
+ res.end();
+ return;
+ }
+ std::experimental::filesystem::directory_iterator files(loc);
+ for (auto &file : files)
+ {
+ std::ifstream readFile(file.path());
+ if (readFile.good())
+ {
+ continue;
}
+ res.addHeader("Content-Type", "application/octet-stream");
+ res.body() = {std::istreambuf_iterator<char>(readFile),
+ std::istreambuf_iterator<char>()};
res.end();
- },
- processName, objectPath, "org.freedesktop.DBus.Introspectable",
- "Introspect");
- } else {
- crow::connections::systemBus->async_method_call(
- [
- &, processName, objectPath,
- interface_name{std::move(interfaceName)}
- ](const boost::system::error_code ec,
- const std::string &introspect_xml) {
- if (ec) {
- BMCWEB_LOG_ERROR
- << "Introspect call failed with error: " << ec.message()
- << " on process: " << processName
- << " path: " << objectPath << "\n";
-
- } else {
- tinyxml2::XMLDocument doc;
-
- doc.Parse(introspect_xml.c_str());
- tinyxml2::XMLNode *pRoot = doc.FirstChildElement("node");
- if (pRoot == nullptr) {
- BMCWEB_LOG_ERROR << "XML document failed to parse "
- << processName << " " << objectPath
- << "\n";
- res.result(
- boost::beast::http::status::internal_server_error);
-
- } else {
- tinyxml2::XMLElement *node =
- pRoot->FirstChildElement("node");
-
- // if we know we're the only call, build the json directly
- nlohmann::json methodsArray = nlohmann::json::array();
- nlohmann::json signalsArray = nlohmann::json::array();
- tinyxml2::XMLElement *interface =
- pRoot->FirstChildElement("interface");
-
- while (interface != nullptr) {
- std::string ifaceName = interface->Attribute("name");
-
- if (ifaceName == interfaceName) {
- tinyxml2::XMLElement *methods =
- interface->FirstChildElement("method");
- while (methods != nullptr) {
- nlohmann::json argsArray = nlohmann::json::array();
- tinyxml2::XMLElement *arg =
- methods->FirstChildElement("arg");
- while (arg != nullptr) {
- argsArray.push_back(
- {{"name", arg->Attribute("name")},
- {"type", arg->Attribute("type")},
- {"direction", arg->Attribute("direction")}});
- arg = arg->NextSiblingElement("arg");
- }
- methodsArray.push_back(
- {{"name", methods->Attribute("name")},
- {"uri", "/bus/system/" + processName +
- objectPath + "/" + interfaceName +
- "/" + methods->Attribute("name")},
- {"args", argsArray}});
- methods = methods->NextSiblingElement("method");
- }
- tinyxml2::XMLElement *signals =
- interface->FirstChildElement("signal");
- while (signals != nullptr) {
- nlohmann::json argsArray = nlohmann::json::array();
-
- tinyxml2::XMLElement *arg =
- signals->FirstChildElement("arg");
- while (arg != nullptr) {
- std::string name = arg->Attribute("name");
- std::string type = arg->Attribute("type");
- argsArray.push_back({
- {"name", name},
- {"type", type},
- });
- arg = arg->NextSiblingElement("arg");
- }
- signalsArray.push_back(
- {{"name", signals->Attribute("name")},
- {"args", argsArray}});
- signals = signals->NextSiblingElement("signal");
- }
-
- res.jsonValue = {
- {"status", "ok"},
- {"bus_name", processName},
- {"interface", interfaceName},
- {"methods", methodsArray},
- {"objectPath", objectPath},
- {"properties", nlohmann::json::object()},
- {"signals", signalsArray}};
-
- break;
- }
-
- interface = interface->NextSiblingElement("interface");
- }
- if (interface == nullptr) {
- // if we got to the end of the list and never found a
- // match, throw 404
- res.result(boost::beast::http::status::not_found);
- }
- }
+ }
+ res.result(boost::beast::http::status::not_found);
+ res.end();
+ return;
+ });
+
+ BMCWEB_ROUTE(app, "/bus/system/<str>/<path>")
+ .methods("GET"_method)([](const crow::Request &req, crow::Response &res,
+ const std::string &processName,
+ const std::string &requestedPath) {
+ std::vector<std::string> strs;
+ boost::split(strs, requestedPath, boost::is_any_of("/"));
+ std::string objectPath;
+ std::string interfaceName;
+ std::string methodName;
+ auto it = strs.begin();
+ if (it == strs.end())
+ {
+ objectPath = "/";
+ }
+ while (it != strs.end())
+ {
+ // Check if segment contains ".". If it does, it must be an
+ // interface
+ if (it->find(".") != std::string::npos)
+ {
+ break;
+ // THis check is neccesary as the trailing slash gets parsed
+ // as part of our <path> specifier above, which causes the
+ // normal trailing backslash redirector to fail.
+ }
+ else if (!it->empty())
+ {
+ objectPath += "/" + *it;
}
+ it++;
+ }
+ if (it != strs.end())
+ {
+ interfaceName = *it;
+ it++;
+
+ // after interface, we might have a method name
+ if (it != strs.end())
+ {
+ methodName = *it;
+ it++;
+ }
+ }
+ if (it != strs.end())
+ {
+ // if there is more levels past the method name, something went
+ // wrong, return not found
+ res.result(boost::beast::http::status::not_found);
res.end();
- },
- processName, objectPath, "org.freedesktop.DBus.Introspectable",
- "Introspect");
- }
- });
+ return;
+ }
+ if (interfaceName.empty())
+ {
+ crow::connections::systemBus->async_method_call(
+ [&, processName,
+ objectPath](const boost::system::error_code ec,
+ const std::string &introspect_xml) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR
+ << "Introspect call failed with error: "
+ << ec.message()
+ << " on process: " << processName
+ << " path: " << objectPath << "\n";
+ }
+ else
+ {
+ tinyxml2::XMLDocument doc;
+
+ doc.Parse(introspect_xml.c_str());
+ tinyxml2::XMLNode *pRoot =
+ doc.FirstChildElement("node");
+ if (pRoot == nullptr)
+ {
+ BMCWEB_LOG_ERROR
+ << "XML document failed to parse "
+ << processName << " " << objectPath << "\n";
+ res.jsonValue = {{"status", "XML parse error"}};
+ res.result(boost::beast::http::status::
+ internal_server_error);
+ }
+ else
+ {
+ nlohmann::json interfacesArray =
+ nlohmann::json::array();
+ tinyxml2::XMLElement *interface =
+ pRoot->FirstChildElement("interface");
+
+ while (interface != nullptr)
+ {
+ std::string ifaceName =
+ interface->Attribute("name");
+ interfacesArray.push_back(
+ {{"name", ifaceName}});
+
+ interface = interface->NextSiblingElement(
+ "interface");
+ }
+ res.jsonValue = {
+ {"status", "ok"},
+ {"bus_name", processName},
+ {"interfaces", interfacesArray},
+ {"objectPath", objectPath}};
+ }
+ }
+ res.end();
+ },
+ processName, objectPath,
+ "org.freedesktop.DBus.Introspectable", "Introspect");
+ }
+ else
+ {
+ crow::connections::systemBus->async_method_call(
+ [&, processName, objectPath,
+ interface_name{std::move(interfaceName)}](
+ const boost::system::error_code ec,
+ const std::string &introspect_xml) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR
+ << "Introspect call failed with error: "
+ << ec.message()
+ << " on process: " << processName
+ << " path: " << objectPath << "\n";
+ }
+ else
+ {
+ tinyxml2::XMLDocument doc;
+
+ doc.Parse(introspect_xml.c_str());
+ tinyxml2::XMLNode *pRoot =
+ doc.FirstChildElement("node");
+ if (pRoot == nullptr)
+ {
+ BMCWEB_LOG_ERROR
+ << "XML document failed to parse "
+ << processName << " " << objectPath << "\n";
+ res.result(boost::beast::http::status::
+ internal_server_error);
+ }
+ else
+ {
+ tinyxml2::XMLElement *node =
+ pRoot->FirstChildElement("node");
+
+ // if we know we're the only call, build the
+ // json directly
+ nlohmann::json methodsArray =
+ nlohmann::json::array();
+ nlohmann::json signalsArray =
+ nlohmann::json::array();
+ tinyxml2::XMLElement *interface =
+ pRoot->FirstChildElement("interface");
+
+ while (interface != nullptr)
+ {
+ std::string ifaceName =
+ interface->Attribute("name");
+
+ if (ifaceName == interfaceName)
+ {
+ tinyxml2::XMLElement *methods =
+ interface->FirstChildElement(
+ "method");
+ while (methods != nullptr)
+ {
+ nlohmann::json argsArray =
+ nlohmann::json::array();
+ tinyxml2::XMLElement *arg =
+ methods->FirstChildElement(
+ "arg");
+ while (arg != nullptr)
+ {
+ argsArray.push_back(
+ {{"name",
+ arg->Attribute("name")},
+ {"type",
+ arg->Attribute("type")},
+ {"direction",
+ arg->Attribute(
+ "direction")}});
+ arg = arg->NextSiblingElement(
+ "arg");
+ }
+ methodsArray.push_back(
+ {{"name",
+ methods->Attribute("name")},
+ {"uri",
+ "/bus/system/" + processName +
+ objectPath + "/" +
+ interfaceName + "/" +
+ methods->Attribute(
+ "name")},
+ {"args", argsArray}});
+ methods =
+ methods->NextSiblingElement(
+ "method");
+ }
+ tinyxml2::XMLElement *signals =
+ interface->FirstChildElement(
+ "signal");
+ while (signals != nullptr)
+ {
+ nlohmann::json argsArray =
+ nlohmann::json::array();
+
+ tinyxml2::XMLElement *arg =
+ signals->FirstChildElement(
+ "arg");
+ while (arg != nullptr)
+ {
+ std::string name =
+ arg->Attribute("name");
+ std::string type =
+ arg->Attribute("type");
+ argsArray.push_back({
+ {"name", name},
+ {"type", type},
+ });
+ arg = arg->NextSiblingElement(
+ "arg");
+ }
+ signalsArray.push_back(
+ {{"name",
+ signals->Attribute("name")},
+ {"args", argsArray}});
+ signals =
+ signals->NextSiblingElement(
+ "signal");
+ }
+
+ res.jsonValue = {
+ {"status", "ok"},
+ {"bus_name", processName},
+ {"interface", interfaceName},
+ {"methods", methodsArray},
+ {"objectPath", objectPath},
+ {"properties",
+ nlohmann::json::object()},
+ {"signals", signalsArray}};
+
+ break;
+ }
+
+ interface = interface->NextSiblingElement(
+ "interface");
+ }
+ if (interface == nullptr)
+ {
+ // if we got to the end of the list and
+ // never found a match, throw 404
+ res.result(
+ boost::beast::http::status::not_found);
+ }
+ }
+ }
+ res.end();
+ },
+ processName, objectPath,
+ "org.freedesktop.DBus.Introspectable", "Introspect");
+ }
+ });
}
-} // namespace openbmc_mapper
-} // namespace crow
+} // namespace openbmc_mapper
+} // namespace crow
diff --git a/include/pam_authenticate.hpp b/include/pam_authenticate.hpp
index 65e47402f7..f51f9aaddb 100644
--- a/include/pam_authenticate.hpp
+++ b/include/pam_authenticate.hpp
@@ -1,72 +1,84 @@
#pragma once
#include <security/pam_appl.h>
+
+#include <boost/utility/string_view.hpp>
#include <cstring>
#include <memory>
-#include <boost/utility/string_view.hpp>
// function used to get user input
inline int pamFunctionConversation(int numMsg, const struct pam_message** msg,
- struct pam_response** resp,
- void* appdataPtr) {
- if (appdataPtr == nullptr) {
- return PAM_AUTH_ERR;
- }
- auto* pass = reinterpret_cast<char*>(
- malloc(std::strlen(reinterpret_cast<char*>(appdataPtr)) + 1));
- std::strcpy(pass, reinterpret_cast<char*>(appdataPtr));
+ struct pam_response** resp, void* appdataPtr)
+{
+ if (appdataPtr == nullptr)
+ {
+ return PAM_AUTH_ERR;
+ }
+ auto* pass = reinterpret_cast<char*>(
+ malloc(std::strlen(reinterpret_cast<char*>(appdataPtr)) + 1));
+ std::strcpy(pass, reinterpret_cast<char*>(appdataPtr));
- *resp = reinterpret_cast<pam_response*>(
- calloc(numMsg, sizeof(struct pam_response)));
+ *resp = reinterpret_cast<pam_response*>(
+ calloc(numMsg, sizeof(struct pam_response)));
- for (int i = 0; i < numMsg; ++i) {
- /* Ignore all PAM messages except prompting for hidden input */
- if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF) {
- continue;
- }
+ for (int i = 0; i < numMsg; ++i)
+ {
+ /* Ignore all PAM messages except prompting for hidden input */
+ if (msg[i]->msg_style != PAM_PROMPT_ECHO_OFF)
+ {
+ continue;
+ }
- /* Assume PAM is only prompting for the password as hidden input */
- resp[i]->resp = pass;
- }
+ /* Assume PAM is only prompting for the password as hidden input */
+ resp[i]->resp = pass;
+ }
- return PAM_SUCCESS;
+ return PAM_SUCCESS;
}
inline bool pamAuthenticateUser(const boost::string_view username,
- const boost::string_view password) {
- std::string userStr(username);
- std::string passStr(password);
- const struct pam_conv localConversation = {
- pamFunctionConversation, const_cast<char*>(passStr.c_str())};
- pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start
+ const boost::string_view password)
+{
+ std::string userStr(username);
+ std::string passStr(password);
+ const struct pam_conv localConversation = {
+ pamFunctionConversation, const_cast<char*>(passStr.c_str())};
+ pam_handle_t* localAuthHandle = NULL; // this gets set by pam_start
- if (pam_start("webserver", userStr.c_str(), &localConversation,
- &localAuthHandle) != PAM_SUCCESS) {
- return false;
- }
- int retval =
- pam_authenticate(localAuthHandle, PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
+ if (pam_start("webserver", userStr.c_str(), &localConversation,
+ &localAuthHandle) != PAM_SUCCESS)
+ {
+ return false;
+ }
+ int retval = pam_authenticate(localAuthHandle,
+ PAM_SILENT | PAM_DISALLOW_NULL_AUTHTOK);
- if (retval != PAM_SUCCESS) {
- if (retval == PAM_AUTH_ERR) {
- // printf("Authentication failure.\n");
- } else {
- // printf("pam_authenticate returned %d\n", retval);
+ if (retval != PAM_SUCCESS)
+ {
+ if (retval == PAM_AUTH_ERR)
+ {
+ // printf("Authentication failure.\n");
+ }
+ else
+ {
+ // printf("pam_authenticate returned %d\n", retval);
+ }
+ pam_end(localAuthHandle, PAM_SUCCESS);
+ return false;
}
- pam_end(localAuthHandle, PAM_SUCCESS);
- return false;
- }
- /* check that the account is healthy */
- if (pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK) !=
- PAM_SUCCESS) {
- pam_end(localAuthHandle, PAM_SUCCESS);
- return false;
- }
+ /* check that the account is healthy */
+ if (pam_acct_mgmt(localAuthHandle, PAM_DISALLOW_NULL_AUTHTOK) !=
+ PAM_SUCCESS)
+ {
+ pam_end(localAuthHandle, PAM_SUCCESS);
+ return false;
+ }
- if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS) {
- return false;
- }
+ if (pam_end(localAuthHandle, PAM_SUCCESS) != PAM_SUCCESS)
+ {
+ return false;
+ }
- return true;
+ return true;
}
diff --git a/include/persistent_data_middleware.hpp b/include/persistent_data_middleware.hpp
index 706f6f423a..b384f02304 100644
--- a/include/persistent_data_middleware.hpp
+++ b/include/persistent_data_middleware.hpp
@@ -1,121 +1,165 @@
#pragma once
-#include <nlohmann/json.hpp>
-#include <pam_authenticate.hpp>
-#include <sessions.hpp>
-#include <webassets.hpp>
-#include <random>
#include <crow/app.h>
#include <crow/http_request.h>
#include <crow/http_response.h>
+
#include <boost/container/flat_map.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
+#include <nlohmann/json.hpp>
+#include <pam_authenticate.hpp>
+#include <random>
+#include <sessions.hpp>
+#include <webassets.hpp>
-namespace crow {
-
-namespace persistent_data {
+namespace crow
+{
-class Middleware {
- // todo(ed) should read this from a fixed location somewhere, not CWD
- static constexpr const char* filename = "bmcweb_persistent_data.json";
- int jsonRevision = 1;
+namespace persistent_data
+{
- public:
- struct Context {};
+class Middleware
+{
+ // todo(ed) should read this from a fixed location somewhere, not CWD
+ static constexpr const char* filename = "bmcweb_persistent_data.json";
+ int jsonRevision = 1;
- Middleware() { readData(); }
+ public:
+ struct Context
+ {
+ };
- ~Middleware() {
- if (persistent_data::SessionStore::getInstance().needsWrite()) {
- writeData();
+ Middleware()
+ {
+ readData();
}
- }
-
- void beforeHandle(crow::Request& req, Response& res, Context& ctx) {}
-
- void afterHandle(Request& req, Response& res, Context& ctx) {}
-
- // TODO(ed) this should really use protobuf, or some other serialization
- // library, but adding another dependency is somewhat outside the scope of
- // this application for the moment
- void readData() {
- std::ifstream persistentFile(filename);
- int fileRevision = 0;
- if (persistentFile.is_open()) {
- // call with exceptions disabled
- auto data = nlohmann::json::parse(persistentFile, nullptr, false);
- if (data.is_discarded()) {
- BMCWEB_LOG_ERROR << "Error parsing persistent data in json file.";
- } else {
- for (const auto& item : data.items()) {
- if (item.key() == "revision") {
- fileRevision = 0;
-
- const uint64_t* uintPtr = item.value().get_ptr<const uint64_t*>();
- if (uintPtr == nullptr) {
- BMCWEB_LOG_ERROR << "Failed to read revision flag";
- } else {
- fileRevision = *uintPtr;
- }
- } else if (item.key() == "system_uuid") {
- const std::string* jSystemUuid =
- item.value().get_ptr<const std::string*>();
- if (jSystemUuid != nullptr) {
- systemUuid = *jSystemUuid;
- }
- } else if (item.key() == "sessions") {
- for (const auto& elem : item.value()) {
- std::shared_ptr<UserSession> newSession =
- UserSession::fromJson(elem);
- if (newSession == nullptr) {
- BMCWEB_LOG_ERROR
- << "Problem reading session from persistent store";
- continue;
- }
-
- BMCWEB_LOG_DEBUG << "Restored session: " << newSession->csrfToken
- << " " << newSession->uniqueId << " "
- << newSession->sessionToken;
- SessionStore::getInstance().authTokens.emplace(
- newSession->sessionToken, newSession);
- }
- } else {
- // Do nothing in the case of extra fields. We may have cases where
- // fields are added in the future, and we want to at least attempt
- // to gracefully support downgrades in that case, even if we don't
- // officially support it
- }
+ ~Middleware()
+ {
+ if (persistent_data::SessionStore::getInstance().needsWrite())
+ {
+ writeData();
}
- }
}
- bool needWrite = false;
- if (systemUuid.empty()) {
- systemUuid = boost::uuids::to_string(boost::uuids::random_generator()());
- needWrite = true;
+ void beforeHandle(crow::Request& req, Response& res, Context& ctx)
+ {
}
- if (fileRevision < jsonRevision) {
- needWrite = true;
+
+ void afterHandle(Request& req, Response& res, Context& ctx)
+ {
}
- // write revision changes or system uuid changes immediately
- if (needWrite) {
- writeData();
+
+ // TODO(ed) this should really use protobuf, or some other serialization
+ // library, but adding another dependency is somewhat outside the scope of
+ // this application for the moment
+ void readData()
+ {
+ std::ifstream persistentFile(filename);
+ int fileRevision = 0;
+ if (persistentFile.is_open())
+ {
+ // call with exceptions disabled
+ auto data = nlohmann::json::parse(persistentFile, nullptr, false);
+ if (data.is_discarded())
+ {
+ BMCWEB_LOG_ERROR
+ << "Error parsing persistent data in json file.";
+ }
+ else
+ {
+ for (const auto& item : data.items())
+ {
+ if (item.key() == "revision")
+ {
+ fileRevision = 0;
+
+ const uint64_t* uintPtr =
+ item.value().get_ptr<const uint64_t*>();
+ if (uintPtr == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "Failed to read revision flag";
+ }
+ else
+ {
+ fileRevision = *uintPtr;
+ }
+ }
+ else if (item.key() == "system_uuid")
+ {
+ const std::string* jSystemUuid =
+ item.value().get_ptr<const std::string*>();
+ if (jSystemUuid != nullptr)
+ {
+ systemUuid = *jSystemUuid;
+ }
+ }
+ else if (item.key() == "sessions")
+ {
+ for (const auto& elem : item.value())
+ {
+ std::shared_ptr<UserSession> newSession =
+ UserSession::fromJson(elem);
+
+ if (newSession == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "Problem reading session "
+ "from persistent store";
+ continue;
+ }
+
+ BMCWEB_LOG_DEBUG
+ << "Restored session: " << newSession->csrfToken
+ << " " << newSession->uniqueId << " "
+ << newSession->sessionToken;
+ SessionStore::getInstance().authTokens.emplace(
+ newSession->sessionToken, newSession);
+ }
+ }
+ else
+ {
+ // Do nothing in the case of extra fields. We may have
+ // cases where fields are added in the future, and we
+ // want to at least attempt to gracefully support
+ // downgrades in that case, even if we don't officially
+ // support it
+ }
+ }
+ }
+ }
+ bool needWrite = false;
+
+ if (systemUuid.empty())
+ {
+ systemUuid =
+ boost::uuids::to_string(boost::uuids::random_generator()());
+ needWrite = true;
+ }
+ if (fileRevision < jsonRevision)
+ {
+ needWrite = true;
+ }
+ // write revision changes or system uuid changes immediately
+ if (needWrite)
+ {
+ writeData();
+ }
}
- }
- void writeData() {
- std::ofstream persistentFile(filename);
- nlohmann::json data{{"sessions", SessionStore::getInstance().authTokens},
- {"system_uuid", systemUuid},
- {"revision", jsonRevision}};
- persistentFile << data;
- }
+ void writeData()
+ {
+ std::ofstream persistentFile(filename);
+ nlohmann::json data{
+ {"sessions", SessionStore::getInstance().authTokens},
+ {"system_uuid", systemUuid},
+ {"revision", jsonRevision}};
+ persistentFile << data;
+ }
- std::string systemUuid{""};
+ std::string systemUuid{""};
};
-} // namespace persistent_data
-} // namespace crow
+} // namespace persistent_data
+} // namespace crow
diff --git a/include/redfish_v1.hpp b/include/redfish_v1.hpp
index b81aa5474a..13e18380ad 100644
--- a/include/redfish_v1.hpp
+++ b/include/redfish_v1.hpp
@@ -1,15 +1,18 @@
#pragma once
+#include <crow/app.h>
+
+#include <boost/algorithm/string.hpp>
#include <dbus_singleton.hpp>
-#include <persistent_data_middleware.hpp>
-#include <token_authorization_middleware.hpp>
#include <fstream>
+#include <persistent_data_middleware.hpp>
#include <streambuf>
#include <string>
-#include <crow/app.h>
-#include <boost/algorithm/string.hpp>
-namespace crow {
-namespace redfish {
+#include <token_authorization_middleware.hpp>
+namespace crow
+{
+namespace redfish
+{
using ManagedObjectType = std::vector<std::pair<
sdbusplus::message::object_path,
@@ -17,108 +20,130 @@ using ManagedObjectType = std::vector<std::pair<
std::string, boost::container::flat_map<
std::string, sdbusplus::message::variant<bool>>>>>;
-template <typename... Middlewares>
-void requestRoutes(Crow<Middlewares...>& app) {
- BMCWEB_ROUTE(app, "/redfish/")
- .methods("GET"_method)([](const crow::Request& req, crow::Response& res) {
- res.jsonValue = {{"v1", "/redfish/v1/"}};
- res.end();
- });
-
- BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
- .methods(
- "GET"_method)([&](const crow::Request& req, crow::Response& res) {
- crow::connections::systemBus->async_method_call(
- [&](const boost::system::error_code ec,
- const ManagedObjectType& users) {
- if (ec) {
- res.result(boost::beast::http::status::internal_server_error);
- } else {
- res.jsonValue = {
- {"@odata.context",
- "/redfish/v1/"
- "$metadata#ManagerAccountCollection."
- "ManagerAccountCollection"},
- {"@odata.id", "/redfish/v1/AccountService/Accounts"},
- {"@odata.type",
- "#ManagerAccountCollection.ManagerAccountCollection"},
- {"Name", "Accounts Collection"},
- {"Description", "BMC User Accounts"},
- {"Members@odata.count", users.size()}};
- nlohmann::json memberArray = nlohmann::json::array();
- int userIndex = 0;
- for (auto& user : users) {
- const std::string& path =
- static_cast<const std::string&>(user.first);
- std::size_t lastIndex = path.rfind("/");
- if (lastIndex == std::string::npos) {
- lastIndex = 0;
- } else {
- lastIndex += 1;
- }
- memberArray.push_back(
- {{"@odata.id", "/redfish/v1/AccountService/Accounts/" +
- path.substr(lastIndex)}});
- }
- res.jsonValue["Members"] = memberArray;
- }
- res.end();
- },
- "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
- "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
- });
+template <typename... Middlewares> void requestRoutes(Crow<Middlewares...>& app)
+{
+ BMCWEB_ROUTE(app, "/redfish/")
+ .methods("GET"_method)(
+ [](const crow::Request& req, crow::Response& res) {
+ res.jsonValue = {{"v1", "/redfish/v1/"}};
+ res.end();
+ });
- BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
- .methods("GET"_method)([](const crow::Request& req, crow::Response& res,
- const std::string& account_name) {
+ BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/")
+ .methods(
+ "GET"_method)([&](const crow::Request& req, crow::Response& res) {
+ crow::connections::systemBus->async_method_call(
+ [&](const boost::system::error_code ec,
+ const ManagedObjectType& users) {
+ if (ec)
+ {
+ res.result(
+ boost::beast::http::status::internal_server_error);
+ }
+ else
+ {
+ res.jsonValue = {
+ {"@odata.context",
+ "/redfish/v1/"
+ "$metadata#ManagerAccountCollection."
+ "ManagerAccountCollection"},
+ {"@odata.id",
+ "/redfish/v1/AccountService/Accounts"},
+ {"@odata.type", "#ManagerAccountCollection."
+ "ManagerAccountCollection"},
+ {"Name", "Accounts Collection"},
+ {"Description", "BMC User Accounts"},
+ {"Members@odata.count", users.size()}};
+ nlohmann::json memberArray = nlohmann::json::array();
+ int userIndex = 0;
+ for (auto& user : users)
+ {
+ const std::string& path =
+ static_cast<const std::string&>(user.first);
+ std::size_t lastIndex = path.rfind("/");
+ if (lastIndex == std::string::npos)
+ {
+ lastIndex = 0;
+ }
+ else
+ {
+ lastIndex += 1;
+ }
+ memberArray.push_back(
+ {{"@odata.id",
+ "/redfish/v1/AccountService/Accounts/" +
+ path.substr(lastIndex)}});
+ }
+ res.jsonValue["Members"] = memberArray;
+ }
+ res.end();
+ },
+ "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
+ "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
+ });
- crow::connections::systemBus->async_method_call(
- [&, accountName{std::move(account_name)} ](
- const boost::system::error_code ec,
- const ManagedObjectType& users) {
- if (ec) {
- res.result(boost::beast::http::status::internal_server_error);
- } else {
- for (auto& user : users) {
- const std::string& path =
- static_cast<const std::string&>(user.first);
- std::size_t lastIndex = path.rfind("/");
- if (lastIndex == std::string::npos) {
- lastIndex = 0;
- } else {
- lastIndex += 1;
- }
- if (path.substr(lastIndex) == accountName) {
- res.jsonValue = {
- {"@odata.context",
- "/redfish/v1/$metadata#ManagerAccount.ManagerAccount"},
- {"@odata.id", "/redfish/v1/AccountService/Accounts/1"},
- {"@odata.type",
- "#ManagerAccount.v1_0_3.ManagerAccount"},
- {"Id", "1"},
- {"Name", "User Account"},
- {"Description", "User Account"},
- {"Enabled", false},
- {"Password", nullptr},
- {"UserName", accountName},
- {"RoleId", "Administrator"},
- {"Links",
- {{"Role",
- {{"@odata.id",
- "/redfish/v1/AccountService/Roles/"
- "Administrator"}}}}}};
- break;
- }
- }
- if (res.jsonValue.is_null()) {
- res.result(boost::beast::http::status::not_found);
- }
- }
- res.end();
- },
- "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
- "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
- });
+ BMCWEB_ROUTE(app, "/redfish/v1/AccountService/Accounts/<str>/")
+ .methods("GET"_method)([](const crow::Request& req, crow::Response& res,
+ const std::string& account_name) {
+ crow::connections::systemBus->async_method_call(
+ [&, accountName{std::move(account_name)}](
+ const boost::system::error_code ec,
+ const ManagedObjectType& users) {
+ if (ec)
+ {
+ res.result(
+ boost::beast::http::status::internal_server_error);
+ }
+ else
+ {
+ for (auto& user : users)
+ {
+ const std::string& path =
+ static_cast<const std::string&>(user.first);
+ std::size_t lastIndex = path.rfind("/");
+ if (lastIndex == std::string::npos)
+ {
+ lastIndex = 0;
+ }
+ else
+ {
+ lastIndex += 1;
+ }
+ if (path.substr(lastIndex) == accountName)
+ {
+ res.jsonValue = {
+ {"@odata.context",
+ "/redfish/v1/"
+ "$metadata#ManagerAccount.ManagerAccount"},
+ {"@odata.id",
+ "/redfish/v1/AccountService/Accounts/1"},
+ {"@odata.type",
+ "#ManagerAccount.v1_0_3.ManagerAccount"},
+ {"Id", "1"},
+ {"Name", "User Account"},
+ {"Description", "User Account"},
+ {"Enabled", false},
+ {"Password", nullptr},
+ {"UserName", accountName},
+ {"RoleId", "Administrator"},
+ {"Links",
+ {{"Role",
+ {{"@odata.id",
+ "/redfish/v1/AccountService/Roles/"
+ "Administrator"}}}}}};
+ break;
+ }
+ }
+ if (res.jsonValue.is_null())
+ {
+ res.result(boost::beast::http::status::not_found);
+ }
+ }
+ res.end();
+ },
+ "xyz.openbmc_project.User.Manager", "/xyz/openbmc_project/user",
+ "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
+ });
}
-} // namespace redfish
-} // namespace crow
+} // namespace redfish
+} // namespace crow
diff --git a/include/security_headers_middleware.hpp b/include/security_headers_middleware.hpp
index 750f87b719..561fd81635 100644
--- a/include/security_headers_middleware.hpp
+++ b/include/security_headers_middleware.hpp
@@ -3,7 +3,8 @@
#include <crow/http_request.h>
#include <crow/http_response.h>
-namespace crow {
+namespace crow
+{
static const char* strictTransportSecurityKey = "Strict-Transport-Security";
static const char* strictTransportSecurityValue =
"max-age=31536000; includeSubdomains; preload";
@@ -26,40 +27,46 @@ static const char* pragmaValue = "no-cache";
static const char* cacheControlKey = "Cache-Control";
static const char* cacheControlValue = "no-Store,no-Cache";
-struct SecurityHeadersMiddleware {
- struct Context {};
+struct SecurityHeadersMiddleware
+{
+ struct Context
+ {
+ };
- void beforeHandle(crow::Request& req, Response& res, Context& ctx) {
+ void beforeHandle(crow::Request& req, Response& res, Context& ctx)
+ {
#ifdef BMCWEB_INSECURE_DISABLE_XSS_PREVENTION
- if ("OPTIONS"_method == req.method()) {
- res.end();
- }
+ if ("OPTIONS"_method == req.method())
+ {
+ res.end();
+ }
#endif
- }
+ }
- void afterHandle(Request& req, Response& res, Context& ctx) {
- /*
- TODO(ed) these should really check content types. for example,
- X-UA-Compatible header doesn't make sense when retrieving a JSON or
- javascript file. It doesn't hurt anything, it's just ugly.
- */
- res.addHeader(strictTransportSecurityKey, strictTransportSecurityValue);
- res.addHeader(uaCompatabilityKey, uaCompatabilityValue);
- res.addHeader(xframeKey, xframeValue);
- res.addHeader(xssKey, xssValue);
- res.addHeader(contentSecurityKey, contentSecurityValue);
- res.addHeader(pragmaKey, pragmaValue);
- res.addHeader(cacheControlKey, cacheControlValue);
+ void afterHandle(Request& req, Response& res, Context& ctx)
+ {
+ /*
+ TODO(ed) these should really check content types. for example,
+ X-UA-Compatible header doesn't make sense when retrieving a JSON or
+ javascript file. It doesn't hurt anything, it's just ugly.
+ */
+ res.addHeader(strictTransportSecurityKey, strictTransportSecurityValue);
+ res.addHeader(uaCompatabilityKey, uaCompatabilityValue);
+ res.addHeader(xframeKey, xframeValue);
+ res.addHeader(xssKey, xssValue);
+ res.addHeader(contentSecurityKey, contentSecurityValue);
+ res.addHeader(pragmaKey, pragmaValue);
+ res.addHeader(cacheControlKey, cacheControlValue);
#ifdef BMCWEB_INSECURE_DISABLE_XSS_PREVENTION
- res.addHeader("Access-Control-Allow-Origin", "http://localhost:8080");
- res.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH");
- res.addHeader("Access-Control-Allow-Credentials", "true");
- res.addHeader("Access-Control-Allow-Headers",
- "Origin, Content-Type, Accept, Cookie, X-XSRF-TOKEN");
+ res.addHeader("Access-Control-Allow-Origin", "http://localhost:8080");
+ res.addHeader("Access-Control-Allow-Methods", "GET, POST, PUT, PATCH");
+ res.addHeader("Access-Control-Allow-Credentials", "true");
+ res.addHeader("Access-Control-Allow-Headers",
+ "Origin, Content-Type, Accept, Cookie, X-XSRF-TOKEN");
#endif
- }
+ }
};
-} // namespace crow
+} // namespace crow
diff --git a/include/sessions.hpp b/include/sessions.hpp
index f549fde696..510f566476 100644
--- a/include/sessions.hpp
+++ b/include/sessions.hpp
@@ -1,232 +1,284 @@
#pragma once
-#include <nlohmann/json.hpp>
-#include <pam_authenticate.hpp>
-#include <webassets.hpp>
-#include <random>
#include <crow/app.h>
#include <crow/http_request.h>
#include <crow/http_response.h>
+
#include <boost/container/flat_map.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
+#include <nlohmann/json.hpp>
+#include <pam_authenticate.hpp>
+#include <random>
+#include <webassets.hpp>
-namespace crow {
+namespace crow
+{
-namespace persistent_data {
+namespace persistent_data
+{
-enum class PersistenceType {
- TIMEOUT, // User session times out after a predetermined amount of time
- SINGLE_REQUEST // User times out once this request is completed.
+enum class PersistenceType
+{
+ TIMEOUT, // User session times out after a predetermined amount of time
+ SINGLE_REQUEST // User times out once this request is completed.
};
-struct UserSession {
- std::string uniqueId;
- std::string sessionToken;
- std::string username;
- std::string csrfToken;
- std::chrono::time_point<std::chrono::steady_clock> lastUpdated;
- PersistenceType persistence;
-
- /**
- * @brief Fills object with data from UserSession's JSON representation
- *
- * This replaces nlohmann's from_json to ensure no-throw approach
- *
- * @param[in] j JSON object from which data should be loaded
- *
- * @return a shared pointer if data has been loaded properly, nullptr
- * otherwise
- */
- static std::shared_ptr<UserSession> fromJson(const nlohmann::json& j) {
- std::shared_ptr<UserSession> userSession = std::make_shared<UserSession>();
- for (const auto& element : j.items()) {
- const std::string* thisValue =
- element.value().get_ptr<const std::string*>();
- if (thisValue == nullptr) {
- BMCWEB_LOG_ERROR << "Error reading persistent store. Property "
- << element.key() << " was not of type string";
- return nullptr;
- }
- if (element.key() == "unique_id") {
- userSession->uniqueId = *thisValue;
- } else if (element.key() == "session_token") {
- userSession->sessionToken = *thisValue;
- } else if (element.key() == "csrf_token") {
- userSession->csrfToken = *thisValue;
- } else if (element.key() == "username") {
- userSession->username = *thisValue;
- } else {
- BMCWEB_LOG_ERROR << "Got unexpected property reading persistent file: "
- << element.key();
- return nullptr;
- }
- }
+struct UserSession
+{
+ std::string uniqueId;
+ std::string sessionToken;
+ std::string username;
+ std::string csrfToken;
+ std::chrono::time_point<std::chrono::steady_clock> lastUpdated;
+ PersistenceType persistence;
+
+ /**
+ * @brief Fills object with data from UserSession's JSON representation
+ *
+ * This replaces nlohmann's from_json to ensure no-throw approach
+ *
+ * @param[in] j JSON object from which data should be loaded
+ *
+ * @return a shared pointer if data has been loaded properly, nullptr
+ * otherwise
+ */
+ static std::shared_ptr<UserSession> fromJson(const nlohmann::json& j)
+ {
+ std::shared_ptr<UserSession> userSession =
+ std::make_shared<UserSession>();
+ for (const auto& element : j.items())
+ {
+ const std::string* thisValue =
+ element.value().get_ptr<const std::string*>();
+ if (thisValue == nullptr)
+ {
+ BMCWEB_LOG_ERROR << "Error reading persistent store. Property "
+ << element.key() << " was not of type string";
+ return nullptr;
+ }
+ if (element.key() == "unique_id")
+ {
+ userSession->uniqueId = *thisValue;
+ }
+ else if (element.key() == "session_token")
+ {
+ userSession->sessionToken = *thisValue;
+ }
+ else if (element.key() == "csrf_token")
+ {
+ userSession->csrfToken = *thisValue;
+ }
+ else if (element.key() == "username")
+ {
+ userSession->username = *thisValue;
+ }
+ else
+ {
+ BMCWEB_LOG_ERROR
+ << "Got unexpected property reading persistent file: "
+ << element.key();
+ return nullptr;
+ }
+ }
- // For now, sessions that were persisted through a reboot get their idle
- // timer reset. This could probably be overcome with a better understanding
- // of wall clock time and steady timer time, possibly persisting values with
- // wall clock time instead of steady timer, but the tradeoffs of all the
- // corner cases involved are non-trivial, so this is done temporarily
- userSession->lastUpdated = std::chrono::steady_clock::now();
- userSession->persistence = PersistenceType::TIMEOUT;
+ // For now, sessions that were persisted through a reboot get their idle
+ // timer reset. This could probably be overcome with a better
+ // understanding of wall clock time and steady timer time, possibly
+ // persisting values with wall clock time instead of steady timer, but
+ // the tradeoffs of all the corner cases involved are non-trivial, so
+ // this is done temporarily
+ userSession->lastUpdated = std::chrono::steady_clock::now();
+ userSession->persistence = PersistenceType::TIMEOUT;
- return userSession;
- }
+ return userSession;
+ }
};
class Middleware;
-class SessionStore {
- public:
- std::shared_ptr<UserSession> generateUserSession(
- const boost::string_view username,
- PersistenceType persistence = PersistenceType::TIMEOUT) {
- // TODO(ed) find a secure way to not generate session identifiers if
- // persistence is set to SINGLE_REQUEST
- static constexpr std::array<char, 62> alphanum = {
- '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'b', 'C',
- 'D', 'E', 'F', 'g', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
- 'Q', 'r', 'S', 'T', 'U', 'v', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c',
- 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
- 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
-
- // entropy: 30 characters, 62 possibilities. log2(62^30) = 178 bits of
- // entropy. OWASP recommends at least 60
- // https://www.owasp.org/index.php/Session_Management_Cheat_Sheet#Session_ID_Entropy
- std::string sessionToken;
- sessionToken.resize(20, '0');
- std::uniform_int_distribution<int> dist(0, alphanum.size() - 1);
- for (int i = 0; i < sessionToken.size(); ++i) {
- sessionToken[i] = alphanum[dist(rd)];
+class SessionStore
+{
+ public:
+ std::shared_ptr<UserSession> generateUserSession(
+ const boost::string_view username,
+ PersistenceType persistence = PersistenceType::TIMEOUT)
+ {
+ // TODO(ed) find a secure way to not generate session identifiers if
+ // persistence is set to SINGLE_REQUEST
+ static constexpr std::array<char, 62> alphanum = {
+ '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'b', 'C',
+ 'D', 'E', 'F', 'g', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P',
+ 'Q', 'r', 'S', 'T', 'U', 'v', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c',
+ 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p',
+ 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'};
+
+ // entropy: 30 characters, 62 possibilities. log2(62^30) = 178 bits of
+ // entropy. OWASP recommends at least 60
+ // https://www.owasp.org/index.php/Session_Management_Cheat_Sheet#Session_ID_Entropy
+ std::string sessionToken;
+ sessionToken.resize(20, '0');
+ std::uniform_int_distribution<int> dist(0, alphanum.size() - 1);
+ for (int i = 0; i < sessionToken.size(); ++i)
+ {
+ sessionToken[i] = alphanum[dist(rd)];
+ }
+ // Only need csrf tokens for cookie based auth, token doesn't matter
+ std::string csrfToken;
+ csrfToken.resize(20, '0');
+ for (int i = 0; i < csrfToken.size(); ++i)
+ {
+ csrfToken[i] = alphanum[dist(rd)];
+ }
+
+ std::string uniqueId;
+ uniqueId.resize(10, '0');
+ for (int i = 0; i < uniqueId.size(); ++i)
+ {
+ uniqueId[i] = alphanum[dist(rd)];
+ }
+ auto session = std::make_shared<UserSession>(UserSession{
+ uniqueId, sessionToken, std::string(username), csrfToken,
+ std::chrono::steady_clock::now(), persistence});
+ auto it = authTokens.emplace(std::make_pair(sessionToken, session));
+ // Only need to write to disk if session isn't about to be destroyed.
+ needWrite = persistence == PersistenceType::TIMEOUT;
+ return it.first->second;
}
- // Only need csrf tokens for cookie based auth, token doesn't matter
- std::string csrfToken;
- csrfToken.resize(20, '0');
- for (int i = 0; i < csrfToken.size(); ++i) {
- csrfToken[i] = alphanum[dist(rd)];
+
+ std::shared_ptr<UserSession>
+ loginSessionByToken(const boost::string_view token)
+ {
+ applySessionTimeouts();
+ auto sessionIt = authTokens.find(std::string(token));
+ if (sessionIt == authTokens.end())
+ {
+ return nullptr;
+ }
+ std::shared_ptr<UserSession> userSession = sessionIt->second;
+ userSession->lastUpdated = std::chrono::steady_clock::now();
+ return userSession;
}
- std::string uniqueId;
- uniqueId.resize(10, '0');
- for (int i = 0; i < uniqueId.size(); ++i) {
- uniqueId[i] = alphanum[dist(rd)];
+ std::shared_ptr<UserSession> getSessionByUid(const boost::string_view uid)
+ {
+ applySessionTimeouts();
+ // TODO(Ed) this is inefficient
+ auto sessionIt = authTokens.begin();
+ while (sessionIt != authTokens.end())
+ {
+ if (sessionIt->second->uniqueId == uid)
+ {
+ return sessionIt->second;
+ }
+ sessionIt++;
+ }
+ return nullptr;
}
- auto session = std::make_shared<UserSession>(
- UserSession{uniqueId, sessionToken, std::string(username), csrfToken,
- std::chrono::steady_clock::now(), persistence});
- auto it = authTokens.emplace(std::make_pair(sessionToken, session));
- // Only need to write to disk if session isn't about to be destroyed.
- needWrite = persistence == PersistenceType::TIMEOUT;
- return it.first->second;
- }
-
- std::shared_ptr<UserSession> loginSessionByToken(
- const boost::string_view token) {
- applySessionTimeouts();
- auto sessionIt = authTokens.find(std::string(token));
- if (sessionIt == authTokens.end()) {
- return nullptr;
+
+ void removeSession(std::shared_ptr<UserSession> session)
+ {
+ authTokens.erase(session->sessionToken);
+ needWrite = true;
}
- std::shared_ptr<UserSession> userSession = sessionIt->second;
- userSession->lastUpdated = std::chrono::steady_clock::now();
- return userSession;
- }
-
- std::shared_ptr<UserSession> getSessionByUid(const boost::string_view uid) {
- applySessionTimeouts();
- // TODO(Ed) this is inefficient
- auto sessionIt = authTokens.begin();
- while (sessionIt != authTokens.end()) {
- if (sessionIt->second->uniqueId == uid) {
- return sessionIt->second;
- }
- sessionIt++;
+
+ std::vector<const std::string*> getUniqueIds(
+ bool getAll = true,
+ const PersistenceType& type = PersistenceType::SINGLE_REQUEST)
+ {
+ applySessionTimeouts();
+
+ std::vector<const std::string*> ret;
+ ret.reserve(authTokens.size());
+ for (auto& session : authTokens)
+ {
+ if (getAll || type == session.second->persistence)
+ {
+ ret.push_back(&session.second->uniqueId);
+ }
+ }
+ return ret;
+ }
+
+ bool needsWrite()
+ {
+ return needWrite;
+ }
+ int getTimeoutInSeconds() const
+ {
+ return std::chrono::seconds(timeoutInMinutes).count();
+ };
+
+ // Persistent data middleware needs to be able to serialize our authTokens
+ // structure, which is private
+ friend Middleware;
+
+ static SessionStore& getInstance()
+ {
+ static SessionStore sessionStore;
+ return sessionStore;
}
- return nullptr;
- }
-
- void removeSession(std::shared_ptr<UserSession> session) {
- authTokens.erase(session->sessionToken);
- needWrite = true;
- }
-
- std::vector<const std::string*> getUniqueIds(
- bool getAll = true,
- const PersistenceType& type = PersistenceType::SINGLE_REQUEST) {
- applySessionTimeouts();
-
- std::vector<const std::string*> ret;
- ret.reserve(authTokens.size());
- for (auto& session : authTokens) {
- if (getAll || type == session.second->persistence) {
- ret.push_back(&session.second->uniqueId);
- }
+
+ SessionStore(const SessionStore&) = delete;
+ SessionStore& operator=(const SessionStore&) = delete;
+
+ private:
+ SessionStore() : timeoutInMinutes(60)
+ {
}
- return ret;
- }
-
- bool needsWrite() { return needWrite; }
- int getTimeoutInSeconds() const {
- return std::chrono::seconds(timeoutInMinutes).count();
- };
-
- // Persistent data middleware needs to be able to serialize our authTokens
- // structure, which is private
- friend Middleware;
-
- static SessionStore& getInstance() {
- static SessionStore sessionStore;
- return sessionStore;
- }
-
- SessionStore(const SessionStore&) = delete;
- SessionStore& operator=(const SessionStore&) = delete;
-
- private:
- SessionStore() : timeoutInMinutes(60) {}
-
- void applySessionTimeouts() {
- auto timeNow = std::chrono::steady_clock::now();
- if (timeNow - lastTimeoutUpdate > std::chrono::minutes(1)) {
- lastTimeoutUpdate = timeNow;
- auto authTokensIt = authTokens.begin();
- while (authTokensIt != authTokens.end()) {
- if (timeNow - authTokensIt->second->lastUpdated >= timeoutInMinutes) {
- authTokensIt = authTokens.erase(authTokensIt);
- needWrite = true;
- } else {
- authTokensIt++;
+
+ void applySessionTimeouts()
+ {
+ auto timeNow = std::chrono::steady_clock::now();
+ if (timeNow - lastTimeoutUpdate > std::chrono::minutes(1))
+ {
+ lastTimeoutUpdate = timeNow;
+ auto authTokensIt = authTokens.begin();
+ while (authTokensIt != authTokens.end())
+ {
+ if (timeNow - authTokensIt->second->lastUpdated >=
+ timeoutInMinutes)
+ {
+ authTokensIt = authTokens.erase(authTokensIt);
+ needWrite = true;
+ }
+ else
+ {
+ authTokensIt++;
+ }
+ }
}
- }
}
- }
- std::chrono::time_point<std::chrono::steady_clock> lastTimeoutUpdate;
- boost::container::flat_map<std::string, std::shared_ptr<UserSession>>
- authTokens;
- std::random_device rd;
- bool needWrite{false};
- std::chrono::minutes timeoutInMinutes;
+ std::chrono::time_point<std::chrono::steady_clock> lastTimeoutUpdate;
+ boost::container::flat_map<std::string, std::shared_ptr<UserSession>>
+ authTokens;
+ std::random_device rd;
+ bool needWrite{false};
+ std::chrono::minutes timeoutInMinutes;
};
-} // namespace persistent_data
-} // namespace crow
+} // namespace persistent_data
+} // namespace crow
// to_json(...) definition for objects of UserSession type
-namespace nlohmann {
+namespace nlohmann
+{
template <>
-struct adl_serializer<std::shared_ptr<crow::persistent_data::UserSession>> {
- static void to_json(
- nlohmann::json& j,
- const std::shared_ptr<crow::persistent_data::UserSession>& p) {
- if (p->persistence !=
- crow::persistent_data::PersistenceType::SINGLE_REQUEST) {
- j = nlohmann::json{{"unique_id", p->uniqueId},
- {"session_token", p->sessionToken},
- {"username", p->username},
- {"csrf_token", p->csrfToken}};
+struct adl_serializer<std::shared_ptr<crow::persistent_data::UserSession>>
+{
+ static void
+ to_json(nlohmann::json& j,
+ const std::shared_ptr<crow::persistent_data::UserSession>& p)
+ {
+ if (p->persistence !=
+ crow::persistent_data::PersistenceType::SINGLE_REQUEST)
+ {
+ j = nlohmann::json{{"unique_id", p->uniqueId},
+ {"session_token", p->sessionToken},
+ {"username", p->username},
+ {"csrf_token", p->csrfToken}};
+ }
}
- }
};
-} // namespace nlohmann
+} // namespace nlohmann
diff --git a/include/ssl_key_handler.hpp b/include/ssl_key_handler.hpp
index 4eac8035f5..47893bfb5e 100644
--- a/include/ssl_key_handler.hpp
+++ b/include/ssl_key_handler.hpp
@@ -10,304 +10,355 @@
#include <openssl/rand.h>
#include <openssl/rsa.h>
#include <openssl/ssl.h>
-#include <random>
+
#include <boost/asio.hpp>
+#include <random>
-namespace ensuressl {
+namespace ensuressl
+{
static void initOpenssl();
static void cleanupOpenssl();
static EVP_PKEY *createRsaKey();
static EVP_PKEY *createEcKey();
static void handleOpensslError();
-inline bool verifyOpensslKeyCert(const std::string &filepath) {
- bool privateKeyValid = false;
- bool certValid = false;
-
- std::cout << "Checking certs in file " << filepath << "\n";
-
- FILE *file = fopen(filepath.c_str(), "r");
- if (file != NULL) {
- EVP_PKEY *pkey = PEM_read_PrivateKey(file, NULL, NULL, NULL);
- int rc;
- if (pkey != nullptr) {
- RSA *rsa = EVP_PKEY_get1_RSA(pkey);
- if (rsa != nullptr) {
- std::cout << "Found an RSA key\n";
- if (RSA_check_key(rsa) == 1) {
- // private_key_valid = true;
- } else {
- std::cerr << "Key not valid error number " << ERR_get_error() << "\n";
- }
- RSA_free(rsa);
- } else {
- EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pkey);
- if (ec != nullptr) {
- std::cout << "Found an EC key\n";
- if (EC_KEY_check_key(ec) == 1) {
- privateKeyValid = true;
- } else {
- std::cerr << "Key not valid error number " << ERR_get_error()
- << "\n";
- }
- EC_KEY_free(ec);
- }
- }
-
- if (privateKeyValid) {
- X509 *x509 = PEM_read_X509(file, NULL, NULL, NULL);
- if (x509 == nullptr) {
- std::cout << "error getting x509 cert " << ERR_get_error() << "\n";
- } else {
- rc = X509_verify(x509, pkey);
- if (rc == 1) {
- certValid = true;
- } else {
- std::cerr << "Error in verifying private key signature "
- << ERR_get_error() << "\n";
- }
+inline bool verifyOpensslKeyCert(const std::string &filepath)
+{
+ bool privateKeyValid = false;
+ bool certValid = false;
+
+ std::cout << "Checking certs in file " << filepath << "\n";
+
+ FILE *file = fopen(filepath.c_str(), "r");
+ if (file != NULL)
+ {
+ EVP_PKEY *pkey = PEM_read_PrivateKey(file, NULL, NULL, NULL);
+ int rc;
+ if (pkey != nullptr)
+ {
+ RSA *rsa = EVP_PKEY_get1_RSA(pkey);
+ if (rsa != nullptr)
+ {
+ std::cout << "Found an RSA key\n";
+ if (RSA_check_key(rsa) == 1)
+ {
+ // private_key_valid = true;
+ }
+ else
+ {
+ std::cerr << "Key not valid error number "
+ << ERR_get_error() << "\n";
+ }
+ RSA_free(rsa);
+ }
+ else
+ {
+ EC_KEY *ec = EVP_PKEY_get1_EC_KEY(pkey);
+ if (ec != nullptr)
+ {
+ std::cout << "Found an EC key\n";
+ if (EC_KEY_check_key(ec) == 1)
+ {
+ privateKeyValid = true;
+ }
+ else
+ {
+ std::cerr << "Key not valid error number "
+ << ERR_get_error() << "\n";
+ }
+ EC_KEY_free(ec);
+ }
+ }
+
+ if (privateKeyValid)
+ {
+ X509 *x509 = PEM_read_X509(file, NULL, NULL, NULL);
+ if (x509 == nullptr)
+ {
+ std::cout << "error getting x509 cert " << ERR_get_error()
+ << "\n";
+ }
+ else
+ {
+ rc = X509_verify(x509, pkey);
+ if (rc == 1)
+ {
+ certValid = true;
+ }
+ else
+ {
+ std::cerr << "Error in verifying private key signature "
+ << ERR_get_error() << "\n";
+ }
+ }
+ }
+
+ EVP_PKEY_free(pkey);
}
- }
-
- EVP_PKEY_free(pkey);
+ fclose(file);
}
- fclose(file);
- }
- return certValid;
+ return certValid;
}
-inline void generateSslCertificate(const std::string &filepath) {
- FILE *pFile = NULL;
- std::cout << "Generating new keys\n";
- initOpenssl();
-
- // std::cerr << "Generating RSA key";
- // EVP_PKEY *pRsaPrivKey = create_rsa_key();
-
- std::cerr << "Generating EC key\n";
- EVP_PKEY *pRsaPrivKey = createEcKey();
- if (pRsaPrivKey != nullptr) {
- std::cerr << "Generating x509 Certificate\n";
- // Use this code to directly generate a certificate
- X509 *x509;
- x509 = X509_new();
- if (x509 != nullptr) {
- // get a random number from the RNG for the certificate serial number
- // If this is not random, regenerating certs throws broswer errors
- std::random_device rd;
- int serial = rd();
-
- ASN1_INTEGER_set(X509_get_serialNumber(x509), serial);
-
- // not before this moment
- X509_gmtime_adj(X509_get_notBefore(x509), 0);
- // Cert is valid for 10 years
- X509_gmtime_adj(X509_get_notAfter(x509), 60L * 60L * 24L * 365L * 10L);
-
- // set the public key to the key we just generated
- X509_set_pubkey(x509, pRsaPrivKey);
-
- // get the subject name
- X509_NAME *name;
- name = X509_get_subject_name(x509);
-
- X509_NAME_add_entry_by_txt(name, "C", MBSTRING_ASC,
- reinterpret_cast<const unsigned char *>("US"),
- -1, -1, 0);
- X509_NAME_add_entry_by_txt(
- name, "O", MBSTRING_ASC,
- reinterpret_cast<const unsigned char *>("Intel BMC"), -1, -1, 0);
- X509_NAME_add_entry_by_txt(
- name, "CN", MBSTRING_ASC,
- reinterpret_cast<const unsigned char *>("testhost"), -1, -1, 0);
- // set the CSR options
- X509_set_issuer_name(x509, name);
-
- // Sign the certificate with our private key
- X509_sign(x509, pRsaPrivKey, EVP_sha256());
-
- pFile = fopen(filepath.c_str(), "wt");
-
- if (pFile != nullptr) {
- PEM_write_PrivateKey(pFile, pRsaPrivKey, NULL, NULL, 0, 0, NULL);
-
- PEM_write_X509(pFile, x509);
- fclose(pFile);
- pFile = NULL;
- }
-
- X509_free(x509);
- }
+inline void generateSslCertificate(const std::string &filepath)
+{
+ FILE *pFile = NULL;
+ std::cout << "Generating new keys\n";
+ initOpenssl();
+
+ // std::cerr << "Generating RSA key";
+ // EVP_PKEY *pRsaPrivKey = create_rsa_key();
+
+ std::cerr << "Generating EC key\n";
+ EVP_PKEY *pRsaPrivKey = createEcKey();
+ if (pRsaPrivKey != nullptr)
+ {
+ std::cerr << "Generating x509 Certificate\n";
+ // Use this code to directly generate a certificate
+ X509 *x509;
+ x509 = X509_new();
+ if (x509 != nullptr)
+ {
+ // get a random number from the RNG for the certificate serial
+ // number If this is not random, regenerating certs throws broswer
+ // errors
+ std::random_device rd;
+ int serial = rd();
+
+ ASN1_INTEGER_set(X509_get_serialNumber(x509), serial);
+
+ // not before this moment
+ X509_gmtime_adj(X509_get_notBefore(x509), 0);
+ // Cert is valid for 10 years
+ X509_gmtime_adj(X509_get_notAfter(x509),
+ 60L * 60L * 24L * 365L * 10L);
+
+ // set the public key to the key we just generated
+ X509_set_pubkey(x509, pRsaPrivKey);
+
+ // get the subject name
+ X509_NAME *name;
+ name = X509_get_subject_name(x509);
+
+ X509_NAME_add_entry_by_txt(
+ name, "C", MBSTRING_ASC,
+ reinterpret_cast<const unsigned char *>("US"), -1, -1, 0);
+ X509_NAME_add_entry_by_txt(
+ name, "O", MBSTRING_ASC,
+ reinterpret_cast<const unsigned char *>("Intel BMC"), -1, -1,
+ 0);
+ X509_NAME_add_entry_by_txt(
+ name, "CN", MBSTRING_ASC,
+ reinterpret_cast<const unsigned char *>("testhost"), -1, -1, 0);
+ // set the CSR options
+ X509_set_issuer_name(x509, name);
+
+ // Sign the certificate with our private key
+ X509_sign(x509, pRsaPrivKey, EVP_sha256());
+
+ pFile = fopen(filepath.c_str(), "wt");
+
+ if (pFile != nullptr)
+ {
+ PEM_write_PrivateKey(pFile, pRsaPrivKey, NULL, NULL, 0, 0,
+ NULL);
+
+ PEM_write_X509(pFile, x509);
+ fclose(pFile);
+ pFile = NULL;
+ }
+
+ X509_free(x509);
+ }
- EVP_PKEY_free(pRsaPrivKey);
- pRsaPrivKey = NULL;
- }
+ EVP_PKEY_free(pRsaPrivKey);
+ pRsaPrivKey = NULL;
+ }
- // cleanup_openssl();
+ // cleanup_openssl();
}
-EVP_PKEY *createRsaKey() {
- RSA *pRSA = NULL;
+EVP_PKEY *createRsaKey()
+{
+ RSA *pRSA = NULL;
#if OPENSSL_VERSION_NUMBER < 0x00908000L
- pRSA = RSA_generate_key(2048, RSA_3, NULL, NULL);
+ pRSA = RSA_generate_key(2048, RSA_3, NULL, NULL);
#else
- RSA_generate_key_ex(pRSA, 2048, NULL, NULL);
+ RSA_generate_key_ex(pRSA, 2048, NULL, NULL);
#endif
- EVP_PKEY *pKey = EVP_PKEY_new();
- if ((pRSA != nullptr) && (pKey != nullptr) &&
- EVP_PKEY_assign_RSA(pKey, pRSA)) {
- /* pKey owns pRSA from now */
- if (RSA_check_key(pRSA) <= 0) {
- fprintf(stderr, "RSA_check_key failed.\n");
- handleOpensslError();
- EVP_PKEY_free(pKey);
- pKey = NULL;
- }
- } else {
- handleOpensslError();
- if (pRSA != nullptr) {
- RSA_free(pRSA);
- pRSA = NULL;
+ EVP_PKEY *pKey = EVP_PKEY_new();
+ if ((pRSA != nullptr) && (pKey != nullptr) &&
+ EVP_PKEY_assign_RSA(pKey, pRSA))
+ {
+ /* pKey owns pRSA from now */
+ if (RSA_check_key(pRSA) <= 0)
+ {
+ fprintf(stderr, "RSA_check_key failed.\n");
+ handleOpensslError();
+ EVP_PKEY_free(pKey);
+ pKey = NULL;
+ }
}
- if (pKey != nullptr) {
- EVP_PKEY_free(pKey);
- pKey = NULL;
+ else
+ {
+ handleOpensslError();
+ if (pRSA != nullptr)
+ {
+ RSA_free(pRSA);
+ pRSA = NULL;
+ }
+ if (pKey != nullptr)
+ {
+ EVP_PKEY_free(pKey);
+ pKey = NULL;
+ }
}
- }
- return pKey;
+ return pKey;
}
-EVP_PKEY *createEcKey() {
- EVP_PKEY *pKey = NULL;
- int eccgrp = 0;
- eccgrp = OBJ_txt2nid("prime256v1");
-
- EC_KEY *myecc = EC_KEY_new_by_curve_name(eccgrp);
- if (myecc != nullptr) {
- EC_KEY_set_asn1_flag(myecc, OPENSSL_EC_NAMED_CURVE);
- EC_KEY_generate_key(myecc);
- pKey = EVP_PKEY_new();
- if (pKey != nullptr) {
- if (EVP_PKEY_assign_EC_KEY(pKey, myecc)) {
- /* pKey owns pRSA from now */
- if (EC_KEY_check_key(myecc) <= 0) {
- fprintf(stderr, "EC_check_key failed.\n");
+EVP_PKEY *createEcKey()
+{
+ EVP_PKEY *pKey = NULL;
+ int eccgrp = 0;
+ eccgrp = OBJ_txt2nid("prime256v1");
+
+ EC_KEY *myecc = EC_KEY_new_by_curve_name(eccgrp);
+ if (myecc != nullptr)
+ {
+ EC_KEY_set_asn1_flag(myecc, OPENSSL_EC_NAMED_CURVE);
+ EC_KEY_generate_key(myecc);
+ pKey = EVP_PKEY_new();
+ if (pKey != nullptr)
+ {
+ if (EVP_PKEY_assign_EC_KEY(pKey, myecc))
+ {
+ /* pKey owns pRSA from now */
+ if (EC_KEY_check_key(myecc) <= 0)
+ {
+ fprintf(stderr, "EC_check_key failed.\n");
+ }
+ }
}
- }
}
- }
- return pKey;
+ return pKey;
}
-void initOpenssl() {
+void initOpenssl()
+{
#if OPENSSL_VERSION_NUMBER < 0x10100000L
- SSL_load_error_strings();
- OpenSSL_add_all_algorithms();
- RAND_load_file("/dev/urandom", 1024);
+ SSL_load_error_strings();
+ OpenSSL_add_all_algorithms();
+ RAND_load_file("/dev/urandom", 1024);
#endif
}
-void cleanupOpenssl() {
- CRYPTO_cleanup_all_ex_data();
- ERR_free_strings();
+void cleanupOpenssl()
+{
+ CRYPTO_cleanup_all_ex_data();
+ ERR_free_strings();
#if OPENSSL_VERSION_NUMBER < 0x10100000L
- ERR_remove_thread_state(0);
+ ERR_remove_thread_state(0);
#endif
- EVP_cleanup();
+ EVP_cleanup();
}
-void handleOpensslError() { ERR_print_errors_fp(stderr); }
-inline void ensureOpensslKeyPresentAndValid(const std::string &filepath) {
- bool pemFileValid = false;
+void handleOpensslError()
+{
+ ERR_print_errors_fp(stderr);
+}
+inline void ensureOpensslKeyPresentAndValid(const std::string &filepath)
+{
+ bool pemFileValid = false;
- pemFileValid = verifyOpensslKeyCert(filepath);
+ pemFileValid = verifyOpensslKeyCert(filepath);
- if (!pemFileValid) {
- std::cerr << "Error in verifying signature, regenerating\n";
- generateSslCertificate(filepath);
- }
+ if (!pemFileValid)
+ {
+ std::cerr << "Error in verifying signature, regenerating\n";
+ generateSslCertificate(filepath);
+ }
}
-inline boost::asio::ssl::context getSslContext(
- const std::string &ssl_pem_file) {
- boost::asio::ssl::context mSslContext{boost::asio::ssl::context::sslv23};
- mSslContext.set_options(boost::asio::ssl::context::default_workarounds |
- boost::asio::ssl::context::no_sslv2 |
- boost::asio::ssl::context::no_sslv3 |
- boost::asio::ssl::context::single_dh_use |
- boost::asio::ssl::context::no_tlsv1 |
- boost::asio::ssl::context::no_tlsv1_1);
-
- // m_ssl_context.set_verify_mode(boost::asio::ssl::verify_peer);
- mSslContext.use_certificate_file(ssl_pem_file,
- boost::asio::ssl::context::pem);
- mSslContext.use_private_key_file(ssl_pem_file,
- boost::asio::ssl::context::pem);
-
- // Set up EC curves to auto (boost asio doesn't have a method for this)
- // There is a pull request to add this. Once this is included in an asio
- // drop, use the right way
- // http://stackoverflow.com/questions/18929049/boost-asio-with-ecdsa-certificate-issue
- if (SSL_CTX_set_ecdh_auto(mSslContext.native_handle(), 1) != 1) {
- BMCWEB_LOG_ERROR << "Error setting tmp ecdh list\n";
- }
-
- // From mozilla "compatibility"
- std::string mozillaCompatibilityCiphers =
- "ECDHE-ECDSA-CHACHA20-POLY1305:"
- "ECDHE-RSA-CHACHA20-POLY1305:"
- "ECDHE-ECDSA-AES128-GCM-SHA256:"
- "ECDHE-RSA-AES128-GCM-SHA256:"
- "ECDHE-ECDSA-AES256-GCM-SHA384:"
- "ECDHE-RSA-AES256-GCM-SHA384:"
- "DHE-RSA-AES128-GCM-SHA256:"
- "DHE-RSA-AES256-GCM-SHA384:"
- "ECDHE-ECDSA-AES128-SHA256:"
- "ECDHE-RSA-AES128-SHA256:"
- "ECDHE-ECDSA-AES128-SHA:"
- "ECDHE-RSA-AES256-SHA384:"
- "ECDHE-RSA-AES128-SHA:"
- "ECDHE-ECDSA-AES256-SHA384:"
- "ECDHE-ECDSA-AES256-SHA:"
- "ECDHE-RSA-AES256-SHA:"
- "DHE-RSA-AES128-SHA256:"
- "DHE-RSA-AES128-SHA:"
- "DHE-RSA-AES256-SHA256:"
- "DHE-RSA-AES256-SHA:"
- "ECDHE-ECDSA-DES-CBC3-SHA:"
- "ECDHE-RSA-DES-CBC3-SHA:"
- "EDH-RSA-DES-CBC3-SHA:"
- "AES128-GCM-SHA256:"
- "AES256-GCM-SHA384:"
- "AES128-SHA256:"
- "AES256-SHA256:"
- "AES128-SHA:"
- "AES256-SHA:"
- "DES-CBC3-SHA:"
- "!DSS";
-
- // From mozilla "modern"
- std::string mozillaModernCiphers =
- "ECDHE-ECDSA-AES256-GCM-SHA384:"
- "ECDHE-RSA-AES256-GCM-SHA384:"
- "ECDHE-ECDSA-CHACHA20-POLY1305:"
- "ECDHE-RSA-CHACHA20-POLY1305:"
- "ECDHE-ECDSA-AES128-GCM-SHA256:"
- "ECDHE-RSA-AES128-GCM-SHA256:"
- "ECDHE-ECDSA-AES256-SHA384:"
- "ECDHE-RSA-AES256-SHA384:"
- "ECDHE-ECDSA-AES128-SHA256:"
- "ECDHE-RSA-AES128-SHA256";
-
- std::string aesOnlyCiphers = "AES128+EECDH:AES128+EDH:!aNULL:!eNULL";
-
- if (SSL_CTX_set_cipher_list(mSslContext.native_handle(),
- mozillaCompatibilityCiphers.c_str()) != 1) {
- BMCWEB_LOG_ERROR << "Error setting cipher list\n";
- }
- return mSslContext;
+inline boost::asio::ssl::context getSslContext(const std::string &ssl_pem_file)
+{
+ boost::asio::ssl::context mSslContext{boost::asio::ssl::context::sslv23};
+ mSslContext.set_options(boost::asio::ssl::context::default_workarounds |
+ boost::asio::ssl::context::no_sslv2 |
+ boost::asio::ssl::context::no_sslv3 |
+ boost::asio::ssl::context::single_dh_use |
+ boost::asio::ssl::context::no_tlsv1 |
+ boost::asio::ssl::context::no_tlsv1_1);
+
+ // m_ssl_context.set_verify_mode(boost::asio::ssl::verify_peer);
+ mSslContext.use_certificate_file(ssl_pem_file,
+ boost::asio::ssl::context::pem);
+ mSslContext.use_private_key_file(ssl_pem_file,
+ boost::asio::ssl::context::pem);
+
+ // Set up EC curves to auto (boost asio doesn't have a method for this)
+ // There is a pull request to add this. Once this is included in an asio
+ // drop, use the right way
+ // http://stackoverflow.com/questions/18929049/boost-asio-with-ecdsa-certificate-issue
+ if (SSL_CTX_set_ecdh_auto(mSslContext.native_handle(), 1) != 1)
+ {
+ BMCWEB_LOG_ERROR << "Error setting tmp ecdh list\n";
+ }
+
+ // From mozilla "compatibility"
+ std::string mozillaCompatibilityCiphers = "ECDHE-ECDSA-CHACHA20-POLY1305:"
+ "ECDHE-RSA-CHACHA20-POLY1305:"
+ "ECDHE-ECDSA-AES128-GCM-SHA256:"
+ "ECDHE-RSA-AES128-GCM-SHA256:"
+ "ECDHE-ECDSA-AES256-GCM-SHA384:"
+ "ECDHE-RSA-AES256-GCM-SHA384:"
+ "DHE-RSA-AES128-GCM-SHA256:"
+ "DHE-RSA-AES256-GCM-SHA384:"
+ "ECDHE-ECDSA-AES128-SHA256:"
+ "ECDHE-RSA-AES128-SHA256:"
+ "ECDHE-ECDSA-AES128-SHA:"
+ "ECDHE-RSA-AES256-SHA384:"
+ "ECDHE-RSA-AES128-SHA:"
+ "ECDHE-ECDSA-AES256-SHA384:"
+ "ECDHE-ECDSA-AES256-SHA:"
+ "ECDHE-RSA-AES256-SHA:"
+ "DHE-RSA-AES128-SHA256:"
+ "DHE-RSA-AES128-SHA:"
+ "DHE-RSA-AES256-SHA256:"
+ "DHE-RSA-AES256-SHA:"
+ "ECDHE-ECDSA-DES-CBC3-SHA:"
+ "ECDHE-RSA-DES-CBC3-SHA:"
+ "EDH-RSA-DES-CBC3-SHA:"
+ "AES128-GCM-SHA256:"
+ "AES256-GCM-SHA384:"
+ "AES128-SHA256:"
+ "AES256-SHA256:"
+ "AES128-SHA:"
+ "AES256-SHA:"
+ "DES-CBC3-SHA:"
+ "!DSS";
+
+ // From mozilla "modern"
+ std::string mozillaModernCiphers = "ECDHE-ECDSA-AES256-GCM-SHA384:"
+ "ECDHE-RSA-AES256-GCM-SHA384:"
+ "ECDHE-ECDSA-CHACHA20-POLY1305:"
+ "ECDHE-RSA-CHACHA20-POLY1305:"
+ "ECDHE-ECDSA-AES128-GCM-SHA256:"
+ "ECDHE-RSA-AES128-GCM-SHA256:"
+ "ECDHE-ECDSA-AES256-SHA384:"
+ "ECDHE-RSA-AES256-SHA384:"
+ "ECDHE-ECDSA-AES128-SHA256:"
+ "ECDHE-RSA-AES128-SHA256";
+
+ std::string aesOnlyCiphers = "AES128+EECDH:AES128+EDH:!aNULL:!eNULL";
+
+ if (SSL_CTX_set_cipher_list(mSslContext.native_handle(),
+ mozillaCompatibilityCiphers.c_str()) != 1)
+ {
+ BMCWEB_LOG_ERROR << "Error setting cipher list\n";
+ }
+ return mSslContext;
}
-} // namespace ensuressl
+} // namespace ensuressl
#endif \ No newline at end of file
diff --git a/include/token_authorization_middleware.hpp b/include/token_authorization_middleware.hpp
index 2e286e15ca..c419c97fa7 100644
--- a/include/token_authorization_middleware.hpp
+++ b/include/token_authorization_middleware.hpp
@@ -1,359 +1,448 @@
#pragma once
-#include <pam_authenticate.hpp>
-#include <persistent_data_middleware.hpp>
-#include <webassets.hpp>
-#include <random>
#include <crow/app.h>
#include <crow/common.h>
#include <crow/http_request.h>
#include <crow/http_response.h>
+
#include <boost/container/flat_set.hpp>
+#include <pam_authenticate.hpp>
+#include <persistent_data_middleware.hpp>
+#include <random>
+#include <webassets.hpp>
-namespace crow {
+namespace crow
+{
-namespace token_authorization {
+namespace token_authorization
+{
-class Middleware {
- public:
- struct Context {
- std::shared_ptr<crow::persistent_data::UserSession> session;
- };
+class Middleware
+{
+ public:
+ struct Context
+ {
+ std::shared_ptr<crow::persistent_data::UserSession> session;
+ };
- void beforeHandle(crow::Request& req, Response& res, Context& ctx) {
- if (isOnWhitelist(req)) {
- return;
- }
+ void beforeHandle(crow::Request& req, Response& res, Context& ctx)
+ {
+ if (isOnWhitelist(req))
+ {
+ return;
+ }
- ctx.session = performXtokenAuth(req);
- if (ctx.session == nullptr) {
- ctx.session = performCookieAuth(req);
- }
- if (ctx.session == nullptr) {
- boost::string_view authHeader = req.getHeaderValue("Authorization");
- if (!authHeader.empty()) {
- // Reject any kind of auth other than basic or token
- if (boost::starts_with(authHeader, "Token ")) {
- ctx.session = performTokenAuth(authHeader);
- } else if (boost::starts_with(authHeader, "Basic ")) {
- ctx.session = performBasicAuth(authHeader);
+ ctx.session = performXtokenAuth(req);
+ if (ctx.session == nullptr)
+ {
+ ctx.session = performCookieAuth(req);
}
- }
- }
+ if (ctx.session == nullptr)
+ {
+ boost::string_view authHeader = req.getHeaderValue("Authorization");
+ if (!authHeader.empty())
+ {
+ // Reject any kind of auth other than basic or token
+ if (boost::starts_with(authHeader, "Token "))
+ {
+ ctx.session = performTokenAuth(authHeader);
+ }
+ else if (boost::starts_with(authHeader, "Basic "))
+ {
+ ctx.session = performBasicAuth(authHeader);
+ }
+ }
+ }
+
+ if (ctx.session == nullptr)
+ {
+ BMCWEB_LOG_WARNING << "[AuthMiddleware] authorization failed";
+
+ // If it's a browser connecting, don't send the HTTP authenticate
+ // header, to avoid possible CSRF attacks with basic auth
+ if (http_helpers::requestPrefersHtml(req))
+ {
+ res.result(boost::beast::http::status::temporary_redirect);
+ res.addHeader("Location", "/#/login");
+ }
+ else
+ {
+ res.result(boost::beast::http::status::unauthorized);
+ // only send the WWW-authenticate header if this isn't a xhr
+ // from the browser. most scripts,
+ if (req.getHeaderValue("User-Agent").empty())
+ {
+ res.addHeader("WWW-Authenticate", "Basic");
+ }
+ }
- if (ctx.session == nullptr) {
- BMCWEB_LOG_WARNING << "[AuthMiddleware] authorization failed";
-
- // If it's a browser connecting, don't send the HTTP authenticate header,
- // to avoid possible CSRF attacks with basic auth
- if (http_helpers::requestPrefersHtml(req)) {
- res.result(boost::beast::http::status::temporary_redirect);
- res.addHeader("Location", "/#/login");
- } else {
- res.result(boost::beast::http::status::unauthorized);
- // only send the WWW-authenticate header if this isn't a xhr from the
- // browser. most scripts,
- if (req.getHeaderValue("User-Agent").empty()) {
- res.addHeader("WWW-Authenticate", "Basic");
+ res.end();
+ return;
}
- }
- res.end();
- return;
+ // TODO get user privileges here and propagate it via MW Context
+ // else let the request continue unharmed
}
- // TODO get user privileges here and propagate it via MW Context
- // else let the request continue unharmed
- }
-
- template <typename AllContext>
- void afterHandle(Request& req, Response& res, Context& ctx,
- AllContext& allctx) {
- // TODO(ed) THis should really be handled by the persistent data
- // middleware, but because it is upstream, it doesn't have access to the
- // session information. Should the data middleware persist the current
- // user session?
- if (ctx.session != nullptr &&
- ctx.session->persistence ==
- crow::persistent_data::PersistenceType::SINGLE_REQUEST) {
- persistent_data::SessionStore::getInstance().removeSession(ctx.session);
+ template <typename AllContext>
+ void afterHandle(Request& req, Response& res, Context& ctx,
+ AllContext& allctx)
+ {
+ // TODO(ed) THis should really be handled by the persistent data
+ // middleware, but because it is upstream, it doesn't have access to the
+ // session information. Should the data middleware persist the current
+ // user session?
+ if (ctx.session != nullptr &&
+ ctx.session->persistence ==
+ crow::persistent_data::PersistenceType::SINGLE_REQUEST)
+ {
+ persistent_data::SessionStore::getInstance().removeSession(
+ ctx.session);
+ }
}
- }
- private:
- const std::shared_ptr<crow::persistent_data::UserSession> performBasicAuth(
- boost::string_view auth_header) const {
- BMCWEB_LOG_DEBUG << "[AuthMiddleware] Basic authentication";
+ private:
+ const std::shared_ptr<crow::persistent_data::UserSession>
+ performBasicAuth(boost::string_view auth_header) const
+ {
+ BMCWEB_LOG_DEBUG << "[AuthMiddleware] Basic authentication";
+
+ std::string authData;
+ boost::string_view param = auth_header.substr(strlen("Basic "));
+ if (!crow::utility::base64Decode(param, authData))
+ {
+ return nullptr;
+ }
+ std::size_t separator = authData.find(':');
+ if (separator == std::string::npos)
+ {
+ return nullptr;
+ }
- std::string authData;
- boost::string_view param = auth_header.substr(strlen("Basic "));
- if (!crow::utility::base64Decode(param, authData)) {
- return nullptr;
- }
- std::size_t separator = authData.find(':');
- if (separator == std::string::npos) {
- return nullptr;
- }
+ std::string user = authData.substr(0, separator);
+ separator += 1;
+ if (separator > authData.size())
+ {
+ return nullptr;
+ }
+ std::string pass = authData.substr(separator);
- std::string user = authData.substr(0, separator);
- separator += 1;
- if (separator > authData.size()) {
- return nullptr;
- }
- std::string pass = authData.substr(separator);
+ BMCWEB_LOG_DEBUG << "[AuthMiddleware] Authenticating user: " << user;
- BMCWEB_LOG_DEBUG << "[AuthMiddleware] Authenticating user: " << user;
+ if (!pamAuthenticateUser(user, pass))
+ {
+ return nullptr;
+ }
- if (!pamAuthenticateUser(user, pass)) {
- return nullptr;
+ // TODO(ed) generateUserSession is a little expensive for basic
+ // auth, as it generates some random identifiers that will never be
+ // used. This should have a "fast" path for when user tokens aren't
+ // needed.
+ // This whole flow needs to be revisited anyway, as we can't be
+ // calling directly into pam for every request
+ return persistent_data::SessionStore::getInstance().generateUserSession(
+ user, crow::persistent_data::PersistenceType::SINGLE_REQUEST);
}
- // TODO(ed) generateUserSession is a little expensive for basic
- // auth, as it generates some random identifiers that will never be
- // used. This should have a "fast" path for when user tokens aren't
- // needed.
- // This whole flow needs to be revisited anyway, as we can't be
- // calling directly into pam for every request
- return persistent_data::SessionStore::getInstance().generateUserSession(
- user, crow::persistent_data::PersistenceType::SINGLE_REQUEST);
- }
-
- const std::shared_ptr<crow::persistent_data::UserSession> performTokenAuth(
- boost::string_view auth_header) const {
- BMCWEB_LOG_DEBUG << "[AuthMiddleware] Token authentication";
-
- boost::string_view token = auth_header.substr(strlen("Token "));
- auto session =
- persistent_data::SessionStore::getInstance().loginSessionByToken(token);
- return session;
- }
-
- const std::shared_ptr<crow::persistent_data::UserSession> performXtokenAuth(
- const crow::Request& req) const {
- BMCWEB_LOG_DEBUG << "[AuthMiddleware] X-Auth-Token authentication";
-
- boost::string_view token = req.getHeaderValue("X-Auth-Token");
- if (token.empty()) {
- return nullptr;
- }
- auto session =
- persistent_data::SessionStore::getInstance().loginSessionByToken(token);
- return session;
- }
-
- const std::shared_ptr<crow::persistent_data::UserSession> performCookieAuth(
- const crow::Request& req) const {
- BMCWEB_LOG_DEBUG << "[AuthMiddleware] Cookie authentication";
-
- boost::string_view cookieValue = req.getHeaderValue("Cookie");
- if (cookieValue.empty()) {
- return nullptr;
- }
+ const std::shared_ptr<crow::persistent_data::UserSession>
+ performTokenAuth(boost::string_view auth_header) const
+ {
+ BMCWEB_LOG_DEBUG << "[AuthMiddleware] Token authentication";
- auto startIndex = cookieValue.find("SESSION=");
- if (startIndex == std::string::npos) {
- return nullptr;
+ boost::string_view token = auth_header.substr(strlen("Token "));
+ auto session =
+ persistent_data::SessionStore::getInstance().loginSessionByToken(
+ token);
+ return session;
}
- startIndex += sizeof("SESSION=") - 1;
- auto endIndex = cookieValue.find(";", startIndex);
- if (endIndex == std::string::npos) {
- endIndex = cookieValue.size();
- }
- boost::string_view authKey =
- cookieValue.substr(startIndex, endIndex - startIndex);
-
- const std::shared_ptr<crow::persistent_data::UserSession> session =
- persistent_data::SessionStore::getInstance().loginSessionByToken(
- authKey);
- if (session == nullptr) {
- return nullptr;
+
+ const std::shared_ptr<crow::persistent_data::UserSession>
+ performXtokenAuth(const crow::Request& req) const
+ {
+ BMCWEB_LOG_DEBUG << "[AuthMiddleware] X-Auth-Token authentication";
+
+ boost::string_view token = req.getHeaderValue("X-Auth-Token");
+ if (token.empty())
+ {
+ return nullptr;
+ }
+ auto session =
+ persistent_data::SessionStore::getInstance().loginSessionByToken(
+ token);
+ return session;
}
+
+ const std::shared_ptr<crow::persistent_data::UserSession>
+ performCookieAuth(const crow::Request& req) const
+ {
+ BMCWEB_LOG_DEBUG << "[AuthMiddleware] Cookie authentication";
+
+ boost::string_view cookieValue = req.getHeaderValue("Cookie");
+ if (cookieValue.empty())
+ {
+ return nullptr;
+ }
+
+ auto startIndex = cookieValue.find("SESSION=");
+ if (startIndex == std::string::npos)
+ {
+ return nullptr;
+ }
+ startIndex += sizeof("SESSION=") - 1;
+ auto endIndex = cookieValue.find(";", startIndex);
+ if (endIndex == std::string::npos)
+ {
+ endIndex = cookieValue.size();
+ }
+ boost::string_view authKey =
+ cookieValue.substr(startIndex, endIndex - startIndex);
+
+ const std::shared_ptr<crow::persistent_data::UserSession> session =
+ persistent_data::SessionStore::getInstance().loginSessionByToken(
+ authKey);
+ if (session == nullptr)
+ {
+ return nullptr;
+ }
#ifndef BMCWEB_INSECURE_DISABLE_CSRF_PREVENTION
- // RFC7231 defines methods that need csrf protection
- if (req.method() != "GET"_method) {
- boost::string_view csrf = req.getHeaderValue("X-XSRF-TOKEN");
- // Make sure both tokens are filled
- if (csrf.empty() || session->csrfToken.empty()) {
- return nullptr;
- }
- // Reject if csrf token not available
- if (csrf != session->csrfToken) {
- return nullptr;
- }
- }
+ // RFC7231 defines methods that need csrf protection
+ if (req.method() != "GET"_method)
+ {
+ boost::string_view csrf = req.getHeaderValue("X-XSRF-TOKEN");
+ // Make sure both tokens are filled
+ if (csrf.empty() || session->csrfToken.empty())
+ {
+ return nullptr;
+ }
+ // Reject if csrf token not available
+ if (csrf != session->csrfToken)
+ {
+ return nullptr;
+ }
+ }
#endif
- return session;
- }
-
- // checks if request can be forwarded without authentication
- bool isOnWhitelist(const crow::Request& req) const {
- // it's allowed to GET root node without authentica tion
- if ("GET"_method == req.method()) {
- if (req.url == "/redfish/v1" || req.url == "/redfish/v1/" ||
- req.url == "/redfish" || req.url == "/redfish/" ||
- req.url == "/redfish/v1/odata" || req.url == "/redfish/v1/odata/") {
- return true;
- } else if (crow::webassets::routes.find(std::string(req.url)) !=
- crow::webassets::routes.end()) {
- return true;
- }
+ return session;
}
- // it's allowed to POST on session collection & login without
- // authentication
- if ("POST"_method == req.method()) {
- if ((req.url == "/redfish/v1/SessionService/Sessions") ||
- (req.url == "/redfish/v1/SessionService/Sessions/") ||
- (req.url == "/login")) {
- return true;
- }
- }
+ // checks if request can be forwarded without authentication
+ bool isOnWhitelist(const crow::Request& req) const
+ {
+ // it's allowed to GET root node without authentica tion
+ if ("GET"_method == req.method())
+ {
+ if (req.url == "/redfish/v1" || req.url == "/redfish/v1/" ||
+ req.url == "/redfish" || req.url == "/redfish/" ||
+ req.url == "/redfish/v1/odata" ||
+ req.url == "/redfish/v1/odata/")
+ {
+ return true;
+ }
+ else if (crow::webassets::routes.find(std::string(req.url)) !=
+ crow::webassets::routes.end())
+ {
+ return true;
+ }
+ }
+
+ // it's allowed to POST on session collection & login without
+ // authentication
+ if ("POST"_method == req.method())
+ {
+ if ((req.url == "/redfish/v1/SessionService/Sessions") ||
+ (req.url == "/redfish/v1/SessionService/Sessions/") ||
+ (req.url == "/login"))
+ {
+ return true;
+ }
+ }
- return false;
- }
+ return false;
+ }
};
// TODO(ed) see if there is a better way to allow middlewares to request
// routes.
// Possibly an init function on first construction?
-template <typename... Middlewares>
-void requestRoutes(Crow<Middlewares...>& app) {
- static_assert(
- black_magic::Contains<persistent_data::Middleware, Middlewares...>::value,
- "token_authorization middleware must be enabled in app to use "
- "auth routes");
- BMCWEB_ROUTE(app, "/login")
- .methods(
- "POST"_method)([&](const crow::Request& req, crow::Response& res) {
- boost::string_view contentType = req.getHeaderValue("content-type");
- boost::string_view username;
- boost::string_view password;
-
- bool looksLikeIbm = false;
-
- // This object needs to be declared at this scope so the strings
- // within it are not destroyed before we can use them
- nlohmann::json loginCredentials;
- // Check if auth was provided by a payload
- if (contentType == "application/json") {
- loginCredentials = nlohmann::json::parse(req.body, nullptr, false);
- if (loginCredentials.is_discarded()) {
- res.result(boost::beast::http::status::bad_request);
- res.end();
- return;
- }
-
- // check for username/password in the root object
- // THis method is how intel APIs authenticate
- nlohmann::json::iterator userIt = loginCredentials.find("username");
- nlohmann::json::iterator passIt = loginCredentials.find("password");
- if (userIt != loginCredentials.end() &&
- passIt != loginCredentials.end()) {
- const std::string* userStr = userIt->get_ptr<const std::string*>();
- const std::string* passStr = passIt->get_ptr<const std::string*>();
- if (userStr != nullptr && passStr != nullptr) {
- username = *userStr;
- password = *passStr;
- }
- } else {
- // Openbmc appears to push a data object that contains the same
- // keys (username and password), attempt to use that
- auto dataIt = loginCredentials.find("data");
- if (dataIt != loginCredentials.end()) {
- // Some apis produce an array of value ["username",
- // "password"]
- if (dataIt->is_array()) {
- if (dataIt->size() == 2) {
- nlohmann::json::iterator userIt2 = dataIt->begin();
- nlohmann::json::iterator passIt2 = dataIt->begin() + 1;
- looksLikeIbm = true;
- if (userIt2 != dataIt->end() && passIt2 != dataIt->end()) {
+template <typename... Middlewares> void requestRoutes(Crow<Middlewares...>& app)
+{
+ static_assert(
+ black_magic::Contains<persistent_data::Middleware,
+ Middlewares...>::value,
+ "token_authorization middleware must be enabled in app to use "
+ "auth routes");
+ BMCWEB_ROUTE(app, "/login")
+ .methods(
+ "POST"_method)([&](const crow::Request& req, crow::Response& res) {
+ boost::string_view contentType = req.getHeaderValue("content-type");
+ boost::string_view username;
+ boost::string_view password;
+
+ bool looksLikeIbm = false;
+
+ // This object needs to be declared at this scope so the strings
+ // within it are not destroyed before we can use them
+ nlohmann::json loginCredentials;
+ // Check if auth was provided by a payload
+ if (contentType == "application/json")
+ {
+ loginCredentials =
+ nlohmann::json::parse(req.body, nullptr, false);
+ if (loginCredentials.is_discarded())
+ {
+ res.result(boost::beast::http::status::bad_request);
+ res.end();
+ return;
+ }
+
+ // check for username/password in the root object
+ // THis method is how intel APIs authenticate
+ nlohmann::json::iterator userIt =
+ loginCredentials.find("username");
+ nlohmann::json::iterator passIt =
+ loginCredentials.find("password");
+ if (userIt != loginCredentials.end() &&
+ passIt != loginCredentials.end())
+ {
const std::string* userStr =
- userIt2->get_ptr<const std::string*>();
+ userIt->get_ptr<const std::string*>();
const std::string* passStr =
- passIt2->get_ptr<const std::string*>();
- if (userStr != nullptr && passStr != nullptr) {
- username = *userStr;
- password = *passStr;
+ passIt->get_ptr<const std::string*>();
+ if (userStr != nullptr && passStr != nullptr)
+ {
+ username = *userStr;
+ password = *passStr;
}
- }
}
-
- } else if (dataIt->is_object()) {
- nlohmann::json::iterator userIt2 = dataIt->find("username");
- nlohmann::json::iterator passIt2 = dataIt->find("password");
- if (userIt2 != dataIt->end() && passIt2 != dataIt->end()) {
- const std::string* userStr =
- userIt2->get_ptr<const std::string*>();
- const std::string* passStr =
- passIt2->get_ptr<const std::string*>();
- if (userStr != nullptr && passStr != nullptr) {
- username = *userStr;
- password = *passStr;
- }
+ else
+ {
+ // Openbmc appears to push a data object that contains the
+ // same keys (username and password), attempt to use that
+ auto dataIt = loginCredentials.find("data");
+ if (dataIt != loginCredentials.end())
+ {
+ // Some apis produce an array of value ["username",
+ // "password"]
+ if (dataIt->is_array())
+ {
+ if (dataIt->size() == 2)
+ {
+ nlohmann::json::iterator userIt2 =
+ dataIt->begin();
+ nlohmann::json::iterator passIt2 =
+ dataIt->begin() + 1;
+ looksLikeIbm = true;
+ if (userIt2 != dataIt->end() &&
+ passIt2 != dataIt->end())
+ {
+ const std::string* userStr =
+ userIt2->get_ptr<const std::string*>();
+ const std::string* passStr =
+ passIt2->get_ptr<const std::string*>();
+ if (userStr != nullptr &&
+ passStr != nullptr)
+ {
+ username = *userStr;
+ password = *passStr;
+ }
+ }
+ }
+ }
+ else if (dataIt->is_object())
+ {
+ nlohmann::json::iterator userIt2 =
+ dataIt->find("username");
+ nlohmann::json::iterator passIt2 =
+ dataIt->find("password");
+ if (userIt2 != dataIt->end() &&
+ passIt2 != dataIt->end())
+ {
+ const std::string* userStr =
+ userIt2->get_ptr<const std::string*>();
+ const std::string* passStr =
+ passIt2->get_ptr<const std::string*>();
+ if (userStr != nullptr && passStr != nullptr)
+ {
+ username = *userStr;
+ password = *passStr;
+ }
+ }
+ }
+ }
}
- }
}
- }
- } else {
- // check if auth was provided as a headers
- username = req.getHeaderValue("username");
- password = req.getHeaderValue("password");
- }
-
- if (!username.empty() && !password.empty()) {
- if (!pamAuthenticateUser(username, password)) {
- res.result(boost::beast::http::status::unauthorized);
- } else {
- auto session = persistent_data::SessionStore::getInstance()
- .generateUserSession(username);
-
- if (looksLikeIbm) {
- // IBM requires a very specific login structure, and doesn't
- // actually look at the status code. TODO(ed).... Fix that
- // upstream
- res.jsonValue = {
- {"data", "User '" + std::string(username) + "' logged in"},
- {"message", "200 OK"},
- {"status", "ok"}};
-
- // Hack alert. Boost beast by default doesn't let you declare
- // multiple headers of the same name, and in most cases this is
- // fine. Unfortunately here we need to set the Session cookie,
- // which requires the httpOnly attribute, as well as the XSRF
- // cookie, which requires it to not have an httpOnly attribute.
- // To get the behavior we want, we simply inject the second
- // "set-cookie" string into the value header, and get the result
- // we want, even though we are technicaly declaring two headers
- // here.
- res.addHeader("Set-Cookie",
- "XSRF-TOKEN=" + session->csrfToken +
- "; Secure\r\nSet-Cookie: SESSION=" +
- session->sessionToken + "; Secure; HttpOnly");
- } else {
- // if content type is json, assume json token
- res.jsonValue = {{"token", session->sessionToken}};
+ else
+ {
+ // check if auth was provided as a headers
+ username = req.getHeaderValue("username");
+ password = req.getHeaderValue("password");
}
- }
- } else {
- res.result(boost::beast::http::status::bad_request);
- }
- res.end();
- });
-
- BMCWEB_ROUTE(app, "/logout")
- .methods(
- "POST"_method)([&](const crow::Request& req, crow::Response& res) {
- auto& session =
- app.template getContext<token_authorization::Middleware>(req)
- .session;
- if (session != nullptr) {
- persistent_data::SessionStore::getInstance().removeSession(session);
- }
- res.end();
- return;
- });
+ if (!username.empty() && !password.empty())
+ {
+ if (!pamAuthenticateUser(username, password))
+ {
+ res.result(boost::beast::http::status::unauthorized);
+ }
+ else
+ {
+ auto session = persistent_data::SessionStore::getInstance()
+ .generateUserSession(username);
+
+ if (looksLikeIbm)
+ {
+ // IBM requires a very specific login structure, and
+ // doesn't actually look at the status code.
+ // TODO(ed).... Fix that upstream
+ res.jsonValue = {
+ {"data",
+ "User '" + std::string(username) + "' logged in"},
+ {"message", "200 OK"},
+ {"status", "ok"}};
+
+ // Hack alert. Boost beast by default doesn't let you
+ // declare multiple headers of the same name, and in
+ // most cases this is fine. Unfortunately here we need
+ // to set the Session cookie, which requires the
+ // httpOnly attribute, as well as the XSRF cookie, which
+ // requires it to not have an httpOnly attribute. To get
+ // the behavior we want, we simply inject the second
+ // "set-cookie" string into the value header, and get
+ // the result we want, even though we are technicaly
+ // declaring two headers here.
+ res.addHeader("Set-Cookie",
+ "XSRF-TOKEN=" + session->csrfToken +
+ "; Secure\r\nSet-Cookie: SESSION=" +
+ session->sessionToken +
+ "; Secure; HttpOnly");
+ }
+ else
+ {
+ // if content type is json, assume json token
+ res.jsonValue = {{"token", session->sessionToken}};
+ }
+ }
+ }
+ else
+ {
+ res.result(boost::beast::http::status::bad_request);
+ }
+ res.end();
+ });
+
+ BMCWEB_ROUTE(app, "/logout")
+ .methods(
+ "POST"_method)([&](const crow::Request& req, crow::Response& res) {
+ auto& session =
+ app.template getContext<token_authorization::Middleware>(req)
+ .session;
+ if (session != nullptr)
+ {
+ persistent_data::SessionStore::getInstance().removeSession(
+ session);
+ }
+ res.end();
+ return;
+ });
}
-} // namespace token_authorization
-} // namespace crow
+} // namespace token_authorization
+} // namespace crow
diff --git a/include/web_kvm.hpp b/include/web_kvm.hpp
index ad4b352eb4..747a137b87 100644
--- a/include/web_kvm.hpp
+++ b/include/web_kvm.hpp
@@ -1,181 +1,202 @@
-#include <string>
#include <crow/app.h>
-#include <boost/endian/arithmetic.hpp>
#include <ast_jpeg_decoder.hpp>
#include <ast_video_puller.hpp>
+#include <boost/endian/arithmetic.hpp>
+#include <string>
-namespace crow {
-namespace kvm {
+namespace crow
+{
+namespace kvm
+{
static const std::string rfb33VersionString = "RFB 003.003\n";
static const std::string rfb37VersionString = "RFB 003.007\n";
static const std::string rfb38VersionString = "RFB 003.008\n";
-enum class RfbAuthScheme : uint8_t {
- connection_failed = 0,
- no_authentication = 1,
- vnc_authentication = 2
+enum class RfbAuthScheme : uint8_t
+{
+ connection_failed = 0,
+ no_authentication = 1,
+ vnc_authentication = 2
};
-struct PixelFormatStruct {
- boost::endian::big_uint8_t bitsPerPixel;
- boost::endian::big_uint8_t depth;
- boost::endian::big_uint8_t isBigEndian;
- boost::endian::big_uint8_t isTrueColor;
- boost::endian::big_uint16_t redMax;
- boost::endian::big_uint16_t greenMax;
- boost::endian::big_uint16_t blueMax;
- boost::endian::big_uint8_t redShift;
- boost::endian::big_uint8_t greenShift;
- boost::endian::big_uint8_t blueShift;
- boost::endian::big_uint8_t pad1;
- boost::endian::big_uint8_t pad2;
- boost::endian::big_uint8_t pad3;
+struct PixelFormatStruct
+{
+ boost::endian::big_uint8_t bitsPerPixel;
+ boost::endian::big_uint8_t depth;
+ boost::endian::big_uint8_t isBigEndian;
+ boost::endian::big_uint8_t isTrueColor;
+ boost::endian::big_uint16_t redMax;
+ boost::endian::big_uint16_t greenMax;
+ boost::endian::big_uint16_t blueMax;
+ boost::endian::big_uint8_t redShift;
+ boost::endian::big_uint8_t greenShift;
+ boost::endian::big_uint8_t blueShift;
+ boost::endian::big_uint8_t pad1;
+ boost::endian::big_uint8_t pad2;
+ boost::endian::big_uint8_t pad3;
};
-struct ServerInitializationMsg {
- boost::endian::big_uint16_t framebufferWidth;
- boost::endian::big_uint16_t framebufferHeight;
- PixelFormatStruct pixelFormat;
- boost::endian::big_uint32_t nameLength;
+struct ServerInitializationMsg
+{
+ boost::endian::big_uint16_t framebufferWidth;
+ boost::endian::big_uint16_t framebufferHeight;
+ PixelFormatStruct pixelFormat;
+ boost::endian::big_uint32_t nameLength;
};
-enum class client_to_server_msg_type : uint8_t {
- set_pixel_format = 0,
- fix_color_map_entries = 1,
- set_encodings = 2,
- framebuffer_update_request = 3,
- key_event = 4,
- pointer_event = 5,
- client_cut_text = 6
+enum class client_to_server_msg_type : uint8_t
+{
+ set_pixel_format = 0,
+ fix_color_map_entries = 1,
+ set_encodings = 2,
+ framebuffer_update_request = 3,
+ key_event = 4,
+ pointer_event = 5,
+ client_cut_text = 6
};
-enum class server_to_client_message_type : uint8_t {
- framebuffer_update = 0,
- set_color_map_entries = 1,
- bell_message = 2,
- server_cut_text = 3
+enum class server_to_client_message_type : uint8_t
+{
+ framebuffer_update = 0,
+ set_color_map_entries = 1,
+ bell_message = 2,
+ server_cut_text = 3
};
-struct SetPixelFormatMsg {
- boost::endian::big_uint8_t pad1;
- boost::endian::big_uint8_t pad2;
- boost::endian::big_uint8_t pad3;
- PixelFormatStruct pixelFormat;
+struct SetPixelFormatMsg
+{
+ boost::endian::big_uint8_t pad1;
+ boost::endian::big_uint8_t pad2;
+ boost::endian::big_uint8_t pad3;
+ PixelFormatStruct pixelFormat;
};
-struct FrameBufferUpdateReq {
- boost::endian::big_uint8_t incremental;
- boost::endian::big_uint16_t xPosition;
- boost::endian::big_uint16_t yPosition;
- boost::endian::big_uint16_t width;
- boost::endian::big_uint16_t height;
+struct FrameBufferUpdateReq
+{
+ boost::endian::big_uint8_t incremental;
+ boost::endian::big_uint16_t xPosition;
+ boost::endian::big_uint16_t yPosition;
+ boost::endian::big_uint16_t width;
+ boost::endian::big_uint16_t height;
};
-struct KeyEventMsg {
- boost::endian::big_uint8_t downFlag;
- boost::endian::big_uint8_t pad1;
- boost::endian::big_uint8_t pad2;
- boost::endian::big_uint32_t key;
+struct KeyEventMsg
+{
+ boost::endian::big_uint8_t downFlag;
+ boost::endian::big_uint8_t pad1;
+ boost::endian::big_uint8_t pad2;
+ boost::endian::big_uint32_t key;
};
-struct PointerEventMsg {
- boost::endian::big_uint8_t buttonMask;
- boost::endian::big_uint16_t xPosition;
- boost::endian::big_uint16_t yPosition;
+struct PointerEventMsg
+{
+ boost::endian::big_uint8_t buttonMask;
+ boost::endian::big_uint16_t xPosition;
+ boost::endian::big_uint16_t yPosition;
};
-struct ClientCutTextMsg {
- std::vector<uint8_t> data;
+struct ClientCutTextMsg
+{
+ std::vector<uint8_t> data;
};
-enum class encoding_type : uint32_t {
- raw = 0x00,
- copy_rectangle = 0x01,
- rising_rectangle = 0x02,
- corre = 0x04,
- hextile = 0x05,
- zlib = 0x06,
- tight = 0x07,
- zlibhex = 0x08,
- ultra = 0x09,
- zrle = 0x10,
- zywrle = 0x011,
- cache_enable = 0xFFFF0001,
- xor_enable = 0xFFFF0006,
- server_state_ultranvc = 0xFFFF8000,
- enable_keepAlive = 0xFFFF8001,
- enableftp_protocol_version = 0xFFFF8002,
- tight_compress_level_0 = 0xFFFFFF00,
- tight_compress_level_9 = 0xFFFFFF09,
- x_cursor = 0xFFFFFF10,
- rich_cursor = 0xFFFFFF11,
- pointer_pos = 0xFFFFFF18,
- last_rect = 0xFFFFFF20,
- new_framebuffer_size = 0xFFFFFF21,
- tight_quality_level_0 = 0xFFFFFFE0,
- tight_quality_level_9 = 0xFFFFFFE9
+enum class encoding_type : uint32_t
+{
+ raw = 0x00,
+ copy_rectangle = 0x01,
+ rising_rectangle = 0x02,
+ corre = 0x04,
+ hextile = 0x05,
+ zlib = 0x06,
+ tight = 0x07,
+ zlibhex = 0x08,
+ ultra = 0x09,
+ zrle = 0x10,
+ zywrle = 0x011,
+ cache_enable = 0xFFFF0001,
+ xor_enable = 0xFFFF0006,
+ server_state_ultranvc = 0xFFFF8000,
+ enable_keepAlive = 0xFFFF8001,
+ enableftp_protocol_version = 0xFFFF8002,
+ tight_compress_level_0 = 0xFFFFFF00,
+ tight_compress_level_9 = 0xFFFFFF09,
+ x_cursor = 0xFFFFFF10,
+ rich_cursor = 0xFFFFFF11,
+ pointer_pos = 0xFFFFFF18,
+ last_rect = 0xFFFFFF20,
+ new_framebuffer_size = 0xFFFFFF21,
+ tight_quality_level_0 = 0xFFFFFFE0,
+ tight_quality_level_9 = 0xFFFFFFE9
};
-struct FramebufferRectangle {
- boost::endian::big_uint16_t x{};
- boost::endian::big_uint16_t y{};
- boost::endian::big_uint16_t width{};
- boost::endian::big_uint16_t height{};
- boost::endian::big_uint32_t encoding{};
- std::vector<uint8_t> data;
+struct FramebufferRectangle
+{
+ boost::endian::big_uint16_t x{};
+ boost::endian::big_uint16_t y{};
+ boost::endian::big_uint16_t width{};
+ boost::endian::big_uint16_t height{};
+ boost::endian::big_uint32_t encoding{};
+ std::vector<uint8_t> data;
};
-struct FramebufferUpdateMsg {
- boost::endian::big_uint8_t messageType{};
- std::vector<FramebufferRectangle> rectangles;
+struct FramebufferUpdateMsg
+{
+ boost::endian::big_uint8_t messageType{};
+ std::vector<FramebufferRectangle> rectangles;
};
-inline std::string serialize(const FramebufferUpdateMsg& msg) {
- // calculate the size of the needed vector for serialization
- size_t vectorSize = 4;
- for (const auto& rect : msg.rectangles) {
- vectorSize += 12 + rect.data.size();
- }
-
- std::string serialized(vectorSize, 0);
-
- size_t i = 0;
- serialized[i++] = static_cast<char>(
- server_to_client_message_type::framebuffer_update); // Type
- serialized[i++] = 0; // Pad byte
- boost::endian::big_uint16_t numberOfRectangles = msg.rectangles.size();
- std::memcpy(&serialized[i], &numberOfRectangles, sizeof(numberOfRectangles));
- i += sizeof(numberOfRectangles);
-
- for (const auto& rect : msg.rectangles) {
- // copy the first part of the struct
- size_t bufferSize =
- sizeof(FramebufferRectangle) - sizeof(std::vector<uint8_t>);
- std::memcpy(&serialized[i], &rect, bufferSize);
- i += bufferSize;
-
- std::memcpy(&serialized[i], rect.data.data(), rect.data.size());
- i += rect.data.size();
- }
-
- return serialized;
+inline std::string serialize(const FramebufferUpdateMsg& msg)
+{
+ // calculate the size of the needed vector for serialization
+ size_t vectorSize = 4;
+ for (const auto& rect : msg.rectangles)
+ {
+ vectorSize += 12 + rect.data.size();
+ }
+
+ std::string serialized(vectorSize, 0);
+
+ size_t i = 0;
+ serialized[i++] = static_cast<char>(
+ server_to_client_message_type::framebuffer_update); // Type
+ serialized[i++] = 0; // Pad byte
+ boost::endian::big_uint16_t numberOfRectangles = msg.rectangles.size();
+ std::memcpy(&serialized[i], &numberOfRectangles,
+ sizeof(numberOfRectangles));
+ i += sizeof(numberOfRectangles);
+
+ for (const auto& rect : msg.rectangles)
+ {
+ // copy the first part of the struct
+ size_t bufferSize =
+ sizeof(FramebufferRectangle) - sizeof(std::vector<uint8_t>);
+ std::memcpy(&serialized[i], &rect, bufferSize);
+ i += bufferSize;
+
+ std::memcpy(&serialized[i], rect.data.data(), rect.data.size());
+ i += rect.data.size();
+ }
+
+ return serialized;
}
-enum class VncState {
- UNSTARTED,
- AWAITING_CLIENT_VERSION,
- AWAITING_CLIENT_AUTH_METHOD,
- AWAITING_CLIENT_INIT_msg,
- MAIN_LOOP
+enum class VncState
+{
+ UNSTARTED,
+ AWAITING_CLIENT_VERSION,
+ AWAITING_CLIENT_AUTH_METHOD,
+ AWAITING_CLIENT_INIT_msg,
+ MAIN_LOOP
};
-class ConnectionMetadata {
- public:
- ConnectionMetadata(){};
+class ConnectionMetadata
+{
+ public:
+ ConnectionMetadata(){};
- VncState vncState{VncState::UNSTARTED};
+ VncState vncState{VncState::UNSTARTED};
};
using meta_list = std::vector<ConnectionMetadata>;
@@ -183,171 +204,219 @@ meta_list connectionStates(10);
ConnectionMetadata meta;
-template <typename... Middlewares>
-void requestRoutes(Crow<Middlewares...>& app) {
- BMCWEB_ROUTE(app, "/kvmws")
- .websocket()
- .onopen([&](crow::websocket::Connection& conn) {
- if (meta.vncState == VncState::UNSTARTED) {
- meta.vncState = VncState::AWAITING_CLIENT_VERSION;
- conn.sendBinary(rfb38VersionString);
- } else { // SHould never happen
- conn.close();
- }
-
- })
- .onclose(
- [&](crow::websocket::Connection& conn, const std::string& reason) {
- meta.vncState = VncState::UNSTARTED;
- })
- .onmessage([&](crow::websocket::Connection& conn, const std::string& data,
- bool is_binary) {
- switch (meta.vncState) {
- case VncState::AWAITING_CLIENT_VERSION: {
- std::cout << "Client sent: " << data;
- if (data == rfb38VersionString || data == rfb37VersionString) {
- std::string authTypes{1,
- (uint8_t)RfbAuthScheme::no_authentication};
- conn.sendBinary(authTypes);
- meta.vncState = VncState::AWAITING_CLIENT_AUTH_METHOD;
- } else if (data == rfb33VersionString) {
- // TODO(ed) Support older protocols
- meta.vncState = VncState::UNSTARTED;
- conn.close();
- } else {
- // TODO(ed) Support older protocols
- meta.vncState = VncState::UNSTARTED;
- conn.close();
+template <typename... Middlewares> void requestRoutes(Crow<Middlewares...>& app)
+{
+ BMCWEB_ROUTE(app, "/kvmws")
+ .websocket()
+ .onopen([&](crow::websocket::Connection& conn) {
+ if (meta.vncState == VncState::UNSTARTED)
+ {
+ meta.vncState = VncState::AWAITING_CLIENT_VERSION;
+ conn.sendBinary(rfb38VersionString);
}
- } break;
- case VncState::AWAITING_CLIENT_AUTH_METHOD: {
- std::string securityResult{{0, 0, 0, 0}};
- if (data[0] == (uint8_t)RfbAuthScheme::no_authentication) {
- meta.vncState = VncState::AWAITING_CLIENT_INIT_msg;
- } else {
- // Mark auth as failed
- securityResult[3] = 1;
- meta.vncState = VncState::UNSTARTED;
+ else
+ { // SHould never happen
+ conn.close();
}
- conn.sendBinary(securityResult);
- } break;
- case VncState::AWAITING_CLIENT_INIT_msg: {
- // Now send the server initialization
- ServerInitializationMsg serverInitMsg{};
- serverInitMsg.framebufferWidth = 800;
- serverInitMsg.framebufferHeight = 600;
- serverInitMsg.pixelFormat.bitsPerPixel = 32;
- serverInitMsg.pixelFormat.isBigEndian = 0;
- serverInitMsg.pixelFormat.isTrueColor = 1;
- serverInitMsg.pixelFormat.redMax = 255;
- serverInitMsg.pixelFormat.greenMax = 255;
- serverInitMsg.pixelFormat.blueMax = 255;
- serverInitMsg.pixelFormat.redShift = 16;
- serverInitMsg.pixelFormat.greenShift = 8;
- serverInitMsg.pixelFormat.blueShift = 0;
- serverInitMsg.nameLength = 0;
- std::cout << "size: " << sizeof(serverInitMsg);
- // TODO(ed) this is ugly. Crow should really have a span type
- // interface
- // to avoid the copy, but alas, today it does not.
- std::string s(reinterpret_cast<char*>(&serverInitMsg),
- sizeof(serverInitMsg));
- std::cout << "s.size() " << s.size();
- conn.sendBinary(s);
- meta.vncState = VncState::MAIN_LOOP;
- } break;
- case VncState::MAIN_LOOP: {
- if (data.size() >= sizeof(client_to_server_msg_type)) {
- auto type = static_cast<client_to_server_msg_type>(data[0]);
- std::cout << "Received client message type "
- << static_cast<std::size_t>(type) << "\n";
- switch (type) {
- case client_to_server_msg_type::set_pixel_format: {
- } break;
-
- case client_to_server_msg_type::fix_color_map_entries: {
- } break;
- case client_to_server_msg_type::set_encodings: {
- } break;
- case client_to_server_msg_type::framebuffer_update_request: {
- // Make sure the buffer is long enough to handle what we're
- // about to do
- if (data.size() >= sizeof(FrameBufferUpdateReq) +
- sizeof(client_to_server_msg_type)) {
- auto msg = reinterpret_cast<const FrameBufferUpdateReq*>(
- data.data() + // NOLINT
- sizeof(client_to_server_msg_type));
- // TODO(ed) find a better way to do this deserialization
-
- // Todo(ed) lifecycle of the video puller and decoder
- // should be
- // with the websocket, not recreated every time
- ast_video::SimpleVideoPuller p;
- p.initialize();
- auto out = p.readVideo();
- ast_video::AstJpegDecoder d;
- d.decode(out.buffer, out.width, out.height, out.mode,
- out.ySelector, out.uvSelector);
-
- FramebufferUpdateMsg bufferUpdateMsg;
-
- // If the viewer is requesting a full update, force write
- // of all pixels
-
- FramebufferRectangle thisRect;
- thisRect.x = msg->xPosition;
- thisRect.y = msg->yPosition;
- thisRect.width = out.width;
- thisRect.height = out.height;
- thisRect.encoding =
- static_cast<uint8_t>(encoding_type::raw);
- std::cout << "Encoding is " << thisRect.encoding;
- thisRect.data.reserve(
- static_cast<std::size_t>(thisRect.width) *
- static_cast<std::size_t>(thisRect.height) * 4);
- std::cout << "Width " << out.width << " Height "
- << out.height;
-
- for (int i = 0; i < out.width * out.height; i++) {
- auto& pixel = d.outBuffer[i];
- thisRect.data.push_back(pixel.b);
- thisRect.data.push_back(pixel.g);
- thisRect.data.push_back(pixel.r);
- thisRect.data.push_back(0);
+ })
+ .onclose(
+ [&](crow::websocket::Connection& conn, const std::string& reason) {
+ meta.vncState = VncState::UNSTARTED;
+ })
+ .onmessage([&](crow::websocket::Connection& conn,
+ const std::string& data, bool is_binary) {
+ switch (meta.vncState)
+ {
+ case VncState::AWAITING_CLIENT_VERSION:
+ {
+ std::cout << "Client sent: " << data;
+ if (data == rfb38VersionString ||
+ data == rfb37VersionString)
+ {
+ std::string authTypes{
+ 1, (uint8_t)RfbAuthScheme::no_authentication};
+ conn.sendBinary(authTypes);
+ meta.vncState = VncState::AWAITING_CLIENT_AUTH_METHOD;
+ }
+ else if (data == rfb33VersionString)
+ {
+ // TODO(ed) Support older protocols
+ meta.vncState = VncState::UNSTARTED;
+ conn.close();
+ }
+ else
+ {
+ // TODO(ed) Support older protocols
+ meta.vncState = VncState::UNSTARTED;
+ conn.close();
}
-
- bufferUpdateMsg.rectangles.push_back(std::move(thisRect));
- auto serialized = serialize(bufferUpdateMsg);
-
- conn.sendBinary(serialized);
-
- } // TODO(Ed) handle error
-
}
-
break;
-
- case client_to_server_msg_type::key_event: {
- } break;
-
- case client_to_server_msg_type::pointer_event: {
- } break;
-
- case client_to_server_msg_type::client_cut_text: {
- } break;
-
- default:
- break;
- }
+ case VncState::AWAITING_CLIENT_AUTH_METHOD:
+ {
+ std::string securityResult{{0, 0, 0, 0}};
+ if (data[0] == (uint8_t)RfbAuthScheme::no_authentication)
+ {
+ meta.vncState = VncState::AWAITING_CLIENT_INIT_msg;
+ }
+ else
+ {
+ // Mark auth as failed
+ securityResult[3] = 1;
+ meta.vncState = VncState::UNSTARTED;
+ }
+ conn.sendBinary(securityResult);
+ }
+ break;
+ case VncState::AWAITING_CLIENT_INIT_msg:
+ {
+ // Now send the server initialization
+ ServerInitializationMsg serverInitMsg{};
+ serverInitMsg.framebufferWidth = 800;
+ serverInitMsg.framebufferHeight = 600;
+ serverInitMsg.pixelFormat.bitsPerPixel = 32;
+ serverInitMsg.pixelFormat.isBigEndian = 0;
+ serverInitMsg.pixelFormat.isTrueColor = 1;
+ serverInitMsg.pixelFormat.redMax = 255;
+ serverInitMsg.pixelFormat.greenMax = 255;
+ serverInitMsg.pixelFormat.blueMax = 255;
+ serverInitMsg.pixelFormat.redShift = 16;
+ serverInitMsg.pixelFormat.greenShift = 8;
+ serverInitMsg.pixelFormat.blueShift = 0;
+ serverInitMsg.nameLength = 0;
+ std::cout << "size: " << sizeof(serverInitMsg);
+ // TODO(ed) this is ugly. Crow should really have a span
+ // type interface to avoid the copy, but alas, today it does
+ // not.
+ std::string s(reinterpret_cast<char*>(&serverInitMsg),
+ sizeof(serverInitMsg));
+ std::cout << "s.size() " << s.size();
+ conn.sendBinary(s);
+ meta.vncState = VncState::MAIN_LOOP;
+ }
+ break;
+ case VncState::MAIN_LOOP:
+ {
+ if (data.size() >= sizeof(client_to_server_msg_type))
+ {
+ auto type =
+ static_cast<client_to_server_msg_type>(data[0]);
+ std::cout << "Received client message type "
+ << static_cast<std::size_t>(type) << "\n";
+ switch (type)
+ {
+ case client_to_server_msg_type::set_pixel_format:
+ {
+ }
+ break;
+
+ case client_to_server_msg_type::
+ fix_color_map_entries:
+ {
+ }
+ break;
+ case client_to_server_msg_type::set_encodings:
+ {
+ }
+ break;
+ case client_to_server_msg_type::
+ framebuffer_update_request:
+ {
+ // Make sure the buffer is long enough to handle
+ // what we're about to do
+ if (data.size() >=
+ sizeof(FrameBufferUpdateReq) +
+ sizeof(client_to_server_msg_type))
+ {
+ auto msg = reinterpret_cast<
+ const FrameBufferUpdateReq*>(
+ data.data() + // NOLINT
+ sizeof(client_to_server_msg_type));
+ // TODO(ed) find a better way to do this
+ // deserialization
+
+ // Todo(ed) lifecycle of the video puller
+ // and decoder should be with the websocket,
+ // not recreated every time
+ ast_video::SimpleVideoPuller p;
+ p.initialize();
+ auto out = p.readVideo();
+ ast_video::AstJpegDecoder d;
+ d.decode(out.buffer, out.width, out.height,
+ out.mode, out.ySelector,
+ out.uvSelector);
+
+ FramebufferUpdateMsg bufferUpdateMsg;
+
+ // If the viewer is requesting a full
+ // update, force write of all pixels
+
+ FramebufferRectangle thisRect;
+ thisRect.x = msg->xPosition;
+ thisRect.y = msg->yPosition;
+ thisRect.width = out.width;
+ thisRect.height = out.height;
+ thisRect.encoding = static_cast<uint8_t>(
+ encoding_type::raw);
+ std::cout << "Encoding is "
+ << thisRect.encoding;
+ thisRect.data.reserve(
+ static_cast<std::size_t>(
+ thisRect.width) *
+ static_cast<std::size_t>(
+ thisRect.height) *
+ 4);
+ std::cout << "Width " << out.width
+ << " Height " << out.height;
+
+ for (int i = 0; i < out.width * out.height;
+ i++)
+ {
+ auto& pixel = d.outBuffer[i];
+ thisRect.data.push_back(pixel.b);
+ thisRect.data.push_back(pixel.g);
+ thisRect.data.push_back(pixel.r);
+ thisRect.data.push_back(0);
+ }
+
+ bufferUpdateMsg.rectangles.push_back(
+ std::move(thisRect));
+ auto serialized =
+ serialize(bufferUpdateMsg);
+
+ conn.sendBinary(serialized);
+
+ } // TODO(Ed) handle error
+ }
+
+ break;
+
+ case client_to_server_msg_type::key_event:
+ {
+ }
+ break;
+
+ case client_to_server_msg_type::pointer_event:
+ {
+ }
+ break;
+
+ case client_to_server_msg_type::client_cut_text:
+ {
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ break;
+ case VncState::UNSTARTED:
+ // Error? TODO
+ break;
}
-
- } break;
- case VncState::UNSTARTED:
- // Error? TODO
- break;
- }
-
- });
+ });
}
-} // namespace kvm
-} // namespace crow \ No newline at end of file
+} // namespace kvm
+} // namespace crow \ No newline at end of file
diff --git a/include/webassets.hpp b/include/webassets.hpp
index 5eabffedb9..7f1c1f5701 100644
--- a/include/webassets.hpp
+++ b/include/webassets.hpp
@@ -1,137 +1,161 @@
#pragma once
-#include <experimental/filesystem>
-#include <fstream>
-#include <string>
#include <crow/app.h>
#include <crow/http_request.h>
#include <crow/http_response.h>
#include <crow/routing.h>
+
#include <boost/algorithm/string/replace.hpp>
#include <boost/container/flat_set.hpp>
+#include <experimental/filesystem>
+#include <fstream>
+#include <string>
-namespace crow {
-namespace webassets {
+namespace crow
+{
+namespace webassets
+{
namespace filesystem = std::experimental::filesystem;
-struct CmpStr {
- bool operator()(const char* a, const char* b) const {
- return std::strcmp(a, b) < 0;
- }
+struct CmpStr
+{
+ bool operator()(const char* a, const char* b) const
+ {
+ return std::strcmp(a, b) < 0;
+ }
};
static boost::container::flat_set<std::string> routes;
-template <typename... Middlewares>
-void requestRoutes(Crow<Middlewares...>& app) {
- const static boost::container::flat_map<const char*, const char*, CmpStr>
- contentTypes{
- {{".css", "text/css;charset=UTF-8"},
- {".html", "text/html;charset=UTF-8"},
- {".js", "text/html;charset=UTF-8"},
- {".png", "image/png;charset=UTF-8"},
- {".woff", "application/x-font-woff"},
- {".woff2", "application/x-font-woff2"},
- {".gif", "image/gif"},
- {".ico", "image/x-icon"},
- {".ttf", "application/x-font-ttf"},
- {".svg", "image/svg+xml"},
- {".eot", "application/vnd.ms-fontobject"},
- {".xml", "application/xml"},
- {".jpg", "image/jpeg"},
- {".jpeg", "image/jpeg"},
- {".json", "application/json"},
- // dev tools don't care about map type, setting to json causes
- // browser to show as text
- // https://stackoverflow.com/questions/19911929/what-mime-type-should-i-use-for-javascript-source-map-files
- {".map", "application/json"}}};
- filesystem::path rootpath{"/usr/share/www/"};
- filesystem::recursive_directory_iterator dirIter(rootpath);
- // In certain cases, we might have both a gzipped version of the file AND a
- // non-gzipped version. To avoid duplicated routes, we need to make sure we
- // get the gzipped version first. Because the gzipped path should be longer
- // than the non gzipped path, if we sort in Ascending order, we should be
- // guaranteed to get the gzip version first.
- std::vector<filesystem::directory_entry> paths(filesystem::begin(dirIter),
- filesystem::end(dirIter));
- std::sort(paths.rbegin(), paths.rend());
-
- for (const filesystem::directory_entry& dir : paths) {
- filesystem::path absolutePath = dir.path();
- filesystem::path relativePath{
- absolutePath.string().substr(rootpath.string().size() - 1)};
- if (filesystem::is_directory(dir)) {
- // don't recurse into hidden directories or symlinks
- if (boost::starts_with(dir.path().filename().string(), ".") ||
- filesystem::is_symlink(dir)) {
- dirIter.disable_recursion_pending();
- }
- } else if (filesystem::is_regular_file(dir)) {
- std::string extension = relativePath.extension();
- filesystem::path webpath = relativePath;
- const char* contentEncoding = nullptr;
-
- if (extension == ".gz") {
- webpath = webpath.replace_extension("");
- // Use the non-gzip version for determining content type
- extension = webpath.extension().string();
- contentEncoding = "gzip";
- }
-
- if (boost::starts_with(webpath.filename().string(), "index.")) {
- webpath = webpath.parent_path();
- if (webpath.string().size() == 0 || webpath.string().back() != '/') {
- // insert the non-directory version of this path
- routes.insert(webpath);
- webpath += "/";
+template <typename... Middlewares> void requestRoutes(Crow<Middlewares...>& app)
+{
+ const static boost::container::flat_map<const char*, const char*, CmpStr>
+ contentTypes{
+ {{".css", "text/css;charset=UTF-8"},
+ {".html", "text/html;charset=UTF-8"},
+ {".js", "text/html;charset=UTF-8"},
+ {".png", "image/png;charset=UTF-8"},
+ {".woff", "application/x-font-woff"},
+ {".woff2", "application/x-font-woff2"},
+ {".gif", "image/gif"},
+ {".ico", "image/x-icon"},
+ {".ttf", "application/x-font-ttf"},
+ {".svg", "image/svg+xml"},
+ {".eot", "application/vnd.ms-fontobject"},
+ {".xml", "application/xml"},
+ {".jpg", "image/jpeg"},
+ {".jpeg", "image/jpeg"},
+ {".json", "application/json"},
+ // dev tools don't care about map type, setting to json causes
+ // browser to show as text
+ // https://stackoverflow.com/questions/19911929/what-mime-type-should-i-use-for-javascript-source-map-files
+ {".map", "application/json"}}};
+ filesystem::path rootpath{"/usr/share/www/"};
+ filesystem::recursive_directory_iterator dirIter(rootpath);
+ // In certain cases, we might have both a gzipped version of the file AND a
+ // non-gzipped version. To avoid duplicated routes, we need to make sure we
+ // get the gzipped version first. Because the gzipped path should be longer
+ // than the non gzipped path, if we sort in Ascending order, we should be
+ // guaranteed to get the gzip version first.
+ std::vector<filesystem::directory_entry> paths(filesystem::begin(dirIter),
+ filesystem::end(dirIter));
+ std::sort(paths.rbegin(), paths.rend());
+
+ for (const filesystem::directory_entry& dir : paths)
+ {
+ filesystem::path absolutePath = dir.path();
+ filesystem::path relativePath{
+ absolutePath.string().substr(rootpath.string().size() - 1)};
+ if (filesystem::is_directory(dir))
+ {
+ // don't recurse into hidden directories or symlinks
+ if (boost::starts_with(dir.path().filename().string(), ".") ||
+ filesystem::is_symlink(dir))
+ {
+ dirIter.disable_recursion_pending();
+ }
}
- }
-
- std::pair<boost::container::flat_set<std::string>::iterator, bool>
- inserted = routes.insert(webpath);
-
- if (!inserted.second) {
- // Got a duplicated path. This is expected in certain situations
- BMCWEB_LOG_DEBUG << "Got duplicated path " << webpath;
- continue;
- }
- const char* contentType = nullptr;
-
- auto contentTypeIt = contentTypes.find(extension.c_str());
- if (contentTypeIt == contentTypes.end()) {
- BMCWEB_LOG_ERROR << "Cannot determine content-type for " << absolutePath
- << " with extension " << extension;
- } else {
- contentType = contentTypeIt->second;
- }
-
- app.routeDynamic(webpath)(
- [absolutePath, contentType, contentEncoding](const crow::Request& req,
- crow::Response& res) {
- if (contentType != nullptr) {
- res.addHeader("Content-Type", contentType);
+ else if (filesystem::is_regular_file(dir))
+ {
+ std::string extension = relativePath.extension();
+ filesystem::path webpath = relativePath;
+ const char* contentEncoding = nullptr;
+
+ if (extension == ".gz")
+ {
+ webpath = webpath.replace_extension("");
+ // Use the non-gzip version for determining content type
+ extension = webpath.extension().string();
+ contentEncoding = "gzip";
}
- if (contentEncoding != nullptr) {
- res.addHeader("Content-Encoding", contentEncoding);
+ if (boost::starts_with(webpath.filename().string(), "index."))
+ {
+ webpath = webpath.parent_path();
+ if (webpath.string().size() == 0 ||
+ webpath.string().back() != '/')
+ {
+ // insert the non-directory version of this path
+ routes.insert(webpath);
+ webpath += "/";
+ }
}
- // res.set_header("Cache-Control", "public, max-age=86400");
- std::ifstream inf(absolutePath);
- if (!inf) {
- BMCWEB_LOG_DEBUG << "failed to read file";
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
- return;
+ std::pair<boost::container::flat_set<std::string>::iterator, bool>
+ inserted = routes.insert(webpath);
+
+ if (!inserted.second)
+ {
+ // Got a duplicated path. This is expected in certain
+ // situations
+ BMCWEB_LOG_DEBUG << "Got duplicated path " << webpath;
+ continue;
+ }
+ const char* contentType = nullptr;
+
+ auto contentTypeIt = contentTypes.find(extension.c_str());
+ if (contentTypeIt == contentTypes.end())
+ {
+ BMCWEB_LOG_ERROR << "Cannot determine content-type for "
+ << absolutePath << " with extension "
+ << extension;
+ }
+ else
+ {
+ contentType = contentTypeIt->second;
}
- res.body() = {std::istreambuf_iterator<char>(inf),
- std::istreambuf_iterator<char>()};
- res.end();
- });
+ app.routeDynamic(webpath)(
+ [absolutePath, contentType, contentEncoding](
+ const crow::Request& req, crow::Response& res) {
+ if (contentType != nullptr)
+ {
+ res.addHeader("Content-Type", contentType);
+ }
+
+ if (contentEncoding != nullptr)
+ {
+ res.addHeader("Content-Encoding", contentEncoding);
+ }
+
+ // res.set_header("Cache-Control", "public, max-age=86400");
+ std::ifstream inf(absolutePath);
+ if (!inf)
+ {
+ BMCWEB_LOG_DEBUG << "failed to read file";
+ res.result(
+ boost::beast::http::status::internal_server_error);
+ res.end();
+ return;
+ }
+
+ res.body() = {std::istreambuf_iterator<char>(inf),
+ std::istreambuf_iterator<char>()};
+ res.end();
+ });
+ }
}
- }
-} // namespace webassets
-} // namespace webassets
-} // namespace crow
+} // namespace webassets
+} // namespace webassets
+} // namespace crow
diff --git a/redfish-core/include/error_messages.hpp b/redfish-core/include/error_messages.hpp
index 4865516b7a..085b76f6bd 100644
--- a/redfish-core/include/error_messages.hpp
+++ b/redfish-core/include/error_messages.hpp
@@ -24,9 +24,11 @@
#pragma once
#include <nlohmann/json.hpp>
-namespace redfish {
+namespace redfish
+{
-namespace messages {
+namespace messages
+{
constexpr const char* messageVersionPrefix = "Base.1.2.0.";
constexpr const char* messageAnnotation = "@Message.ExtendedInfo";
@@ -636,6 +638,6 @@ nlohmann::json queryParameterOutOfRange(const std::string& arg1,
* AUTOGENERATED FUNCTIONS END *
*********************************/
-} // namespace messages
+} // namespace messages
-} // namespace redfish
+} // namespace redfish
diff --git a/redfish-core/include/node.hpp b/redfish-core/include/node.hpp
index 20d295197e..8dbb0c2d70 100644
--- a/redfish-core/include/node.hpp
+++ b/redfish-core/include/node.hpp
@@ -18,161 +18,190 @@
#include "privileges.hpp"
#include "token_authorization_middleware.hpp"
#include "webserver_common.hpp"
+
#include "crow.h"
-namespace redfish {
+namespace redfish
+{
/**
* AsyncResp
* Gathers data needed for response processing after async calls are done
*/
-class AsyncResp {
- public:
- AsyncResp(crow::Response& response) : res(response) {}
+class AsyncResp
+{
+ public:
+ AsyncResp(crow::Response& response) : res(response)
+ {
+ }
- ~AsyncResp() { res.end(); }
+ ~AsyncResp()
+ {
+ res.end();
+ }
- crow::Response& res;
+ crow::Response& res;
};
/**
* @brief Abstract class used for implementing Redfish nodes.
*
*/
-class Node {
- public:
- template <typename... Params>
- Node(CrowApp& app, std::string&& entityUrl, Params... params) {
- app.routeDynamic(entityUrl.c_str())
- .methods("GET"_method, "PATCH"_method, "POST"_method,
- "DELETE"_method)([&](const crow::Request& req,
- crow::Response& res, Params... params) {
- std::vector<std::string> paramVec = {params...};
- dispatchRequest(app, req, res, paramVec);
- });
- }
-
- virtual ~Node() = default;
-
- const std::string* getUrl() const {
- auto odataId = json.find("@odata.id");
- if (odataId == json.end()) {
- return nullptr;
+class Node
+{
+ public:
+ template <typename... Params>
+ Node(CrowApp& app, std::string&& entityUrl, Params... params)
+ {
+ app.routeDynamic(entityUrl.c_str())
+ .methods("GET"_method, "PATCH"_method, "POST"_method,
+ "DELETE"_method)([&](const crow::Request& req,
+ crow::Response& res,
+ Params... params) {
+ std::vector<std::string> paramVec = {params...};
+ dispatchRequest(app, req, res, paramVec);
+ });
}
- return odataId->get_ptr<const std::string*>();
- }
-
- /**
- * @brief Inserts subroute fields into for the node's json in the form:
- * "subroute_name" : { "odata.id": "node_url/subroute_name/" }
- * Excludes metadata urls starting with "$" and child urls having
- * more than one level.
- *
- * @return None
- */
- void getSubRoutes(const std::vector<std::unique_ptr<Node>>& allNodes) {
- const std::string* url = getUrl();
- if (url == nullptr) {
- // BMCWEB_LOG_CRITICAL << "Unable to get url for route";
- return;
- }
+ virtual ~Node() = default;
- for (const auto& node : allNodes) {
- const std::string* route = node->getUrl();
- if (route == nullptr) {
- // BMCWEB_LOG_CRITICAL << "Unable to get url for route";
- continue;
- }
- if (boost::starts_with(*route, *url)) {
- std::string subRoute = route->substr(url->size());
- if (subRoute.empty()) {
- continue;
+ const std::string* getUrl() const
+ {
+ auto odataId = json.find("@odata.id");
+ if (odataId == json.end())
+ {
+ return nullptr;
}
- if (boost::starts_with(subRoute, "/")) {
- subRoute.erase(0, 1);
- }
+ return odataId->get_ptr<const std::string*>();
+ }
- if (boost::ends_with(subRoute, "/")) {
- subRoute.pop_back();
+ /**
+ * @brief Inserts subroute fields into for the node's json in the form:
+ * "subroute_name" : { "odata.id": "node_url/subroute_name/" }
+ * Excludes metadata urls starting with "$" and child urls having
+ * more than one level.
+ *
+ * @return None
+ */
+ void getSubRoutes(const std::vector<std::unique_ptr<Node>>& allNodes)
+ {
+ const std::string* url = getUrl();
+ if (url == nullptr)
+ {
+ // BMCWEB_LOG_CRITICAL << "Unable to get url for route";
+ return;
}
- if (!boost::starts_with(subRoute, "$") &&
- subRoute.find('/') == std::string::npos) {
- json[subRoute] = nlohmann::json{{"@odata.id", *route}};
+ for (const auto& node : allNodes)
+ {
+ const std::string* route = node->getUrl();
+ if (route == nullptr)
+ {
+ // BMCWEB_LOG_CRITICAL << "Unable to get url for route";
+ continue;
+ }
+ if (boost::starts_with(*route, *url))
+ {
+ std::string subRoute = route->substr(url->size());
+ if (subRoute.empty())
+ {
+ continue;
+ }
+
+ if (boost::starts_with(subRoute, "/"))
+ {
+ subRoute.erase(0, 1);
+ }
+
+ if (boost::ends_with(subRoute, "/"))
+ {
+ subRoute.pop_back();
+ }
+
+ if (!boost::starts_with(subRoute, "$") &&
+ subRoute.find('/') == std::string::npos)
+ {
+ json[subRoute] = nlohmann::json{{"@odata.id", *route}};
+ }
+ }
}
- }
- }
- }
-
- OperationMap entityPrivileges;
-
- protected:
- // Node is designed to be an abstract class, so doGet is pure virtual
- virtual void doGet(crow::Response& res, const crow::Request& req,
- const std::vector<std::string>& params) {
- res.result(boost::beast::http::status::method_not_allowed);
- res.end();
- }
-
- virtual void doPatch(crow::Response& res, const crow::Request& req,
- const std::vector<std::string>& params) {
- res.result(boost::beast::http::status::method_not_allowed);
- res.end();
- }
-
- virtual void doPost(crow::Response& res, const crow::Request& req,
- const std::vector<std::string>& params) {
- res.result(boost::beast::http::status::method_not_allowed);
- res.end();
- }
-
- virtual void doDelete(crow::Response& res, const crow::Request& req,
- const std::vector<std::string>& params) {
- res.result(boost::beast::http::status::method_not_allowed);
- res.end();
- }
-
- nlohmann::json json;
-
- private:
- void dispatchRequest(CrowApp& app, const crow::Request& req,
- crow::Response& res,
- const std::vector<std::string>& params) {
- auto ctx =
- app.template getContext<crow::token_authorization::Middleware>(req);
-
- if (!isMethodAllowedForUser(req.method(), entityPrivileges,
- ctx.session->username)) {
- res.result(boost::beast::http::status::method_not_allowed);
- res.end();
- return;
}
- switch (req.method()) {
- case "GET"_method:
- doGet(res, req, params);
- break;
+ OperationMap entityPrivileges;
- case "PATCH"_method:
- doPatch(res, req, params);
- break;
+ protected:
+ // Node is designed to be an abstract class, so doGet is pure virtual
+ virtual void doGet(crow::Response& res, const crow::Request& req,
+ const std::vector<std::string>& params)
+ {
+ res.result(boost::beast::http::status::method_not_allowed);
+ res.end();
+ }
- case "POST"_method:
- doPost(res, req, params);
- break;
+ virtual void doPatch(crow::Response& res, const crow::Request& req,
+ const std::vector<std::string>& params)
+ {
+ res.result(boost::beast::http::status::method_not_allowed);
+ res.end();
+ }
- case "DELETE"_method:
- doDelete(res, req, params);
- break;
+ virtual void doPost(crow::Response& res, const crow::Request& req,
+ const std::vector<std::string>& params)
+ {
+ res.result(boost::beast::http::status::method_not_allowed);
+ res.end();
+ }
- default:
- res.result(boost::beast::http::status::not_found);
+ virtual void doDelete(crow::Response& res, const crow::Request& req,
+ const std::vector<std::string>& params)
+ {
+ res.result(boost::beast::http::status::method_not_allowed);
res.end();
}
- return;
- }
+
+ nlohmann::json json;
+
+ private:
+ void dispatchRequest(CrowApp& app, const crow::Request& req,
+ crow::Response& res,
+ const std::vector<std::string>& params)
+ {
+ auto ctx =
+ app.template getContext<crow::token_authorization::Middleware>(req);
+
+ if (!isMethodAllowedForUser(req.method(), entityPrivileges,
+ ctx.session->username))
+ {
+ res.result(boost::beast::http::status::method_not_allowed);
+ res.end();
+ return;
+ }
+
+ switch (req.method())
+ {
+ case "GET"_method:
+ doGet(res, req, params);
+ break;
+
+ case "PATCH"_method:
+ doPatch(res, req, params);
+ break;
+
+ case "POST"_method:
+ doPost(res, req, params);
+ break;
+
+ case "DELETE"_method:
+ doDelete(res, req, params);
+ break;
+
+ default:
+ res.result(boost::beast::http::status::not_found);
+ res.end();
+ }
+ return;
+ }
};
-} // namespace redfish
+} // namespace redfish
diff --git a/redfish-core/include/privileges.hpp b/redfish-core/include/privileges.hpp
index 437bb15e04..0f6b903793 100644
--- a/redfish-core/include/privileges.hpp
+++ b/redfish-core/include/privileges.hpp
@@ -16,15 +16,21 @@
#pragma once
#include <bitset>
+#include <boost/container/flat_map.hpp>
+#include <boost/optional.hpp>
#include <cstdint>
#include <vector>
+
#include "crow.h"
-#include <boost/container/flat_map.hpp>
-#include <boost/optional.hpp>
-namespace redfish {
+namespace redfish
+{
-enum class PrivilegeType { BASE, OEM };
+enum class PrivilegeType
+{
+ BASE,
+ OEM
+};
/** @brief A fixed array of compile time privileges */
constexpr std::array<const char*, 5> basePrivileges{
@@ -56,105 +62,118 @@ static const std::vector<std::string> privilegeNames{basePrivileges.begin(),
* (user domain) and false otherwise.
*
*/
-class Privileges {
- public:
- /**
- * @brief Constructs object without any privileges active
- *
- */
- Privileges() = default;
-
- /**
- * @brief Constructs object with given privileges active
- *
- * @param[in] privilegeList List of privileges to be activated
- *
- */
- Privileges(std::initializer_list<const char*> privilegeList) {
- for (const char* privilege : privilegeList) {
- if (!setSinglePrivilege(privilege)) {
- BMCWEB_LOG_CRITICAL << "Unable to set privilege " << privilege
- << "in constructor";
- }
+class Privileges
+{
+ public:
+ /**
+ * @brief Constructs object without any privileges active
+ *
+ */
+ Privileges() = default;
+
+ /**
+ * @brief Constructs object with given privileges active
+ *
+ * @param[in] privilegeList List of privileges to be activated
+ *
+ */
+ Privileges(std::initializer_list<const char*> privilegeList)
+ {
+ for (const char* privilege : privilegeList)
+ {
+ if (!setSinglePrivilege(privilege))
+ {
+ BMCWEB_LOG_CRITICAL << "Unable to set privilege " << privilege
+ << "in constructor";
+ }
+ }
}
- }
-
- /**
- * @brief Sets given privilege in the bitset
- *
- * @param[in] privilege Privilege to be set
- *
- * @return None
- *
- */
- bool setSinglePrivilege(const char* privilege) {
- for (int searchIndex = 0; searchIndex < privilegeNames.size();
- searchIndex++) {
- if (privilege == privilegeNames[searchIndex]) {
- privilegeBitset.set(searchIndex);
- return true;
- }
+
+ /**
+ * @brief Sets given privilege in the bitset
+ *
+ * @param[in] privilege Privilege to be set
+ *
+ * @return None
+ *
+ */
+ bool setSinglePrivilege(const char* privilege)
+ {
+ for (int searchIndex = 0; searchIndex < privilegeNames.size();
+ searchIndex++)
+ {
+ if (privilege == privilegeNames[searchIndex])
+ {
+ privilegeBitset.set(searchIndex);
+ return true;
+ }
+ }
+
+ return false;
}
- return false;
- }
-
- /**
- * @brief Sets given privilege in the bitset
- *
- * @param[in] privilege Privilege to be set
- *
- * @return None
- *
- */
- bool setSinglePrivilege(const std::string& privilege) {
- return setSinglePrivilege(privilege.c_str());
- }
-
- /**
- * @brief Retrieves names of all active privileges for a given type
- *
- * @param[in] type Base or OEM
- *
- * @return Vector of active privileges. Pointers are valid until
- * the setSinglePrivilege is called, or the Privilege structure is destroyed
- *
- */
- std::vector<const std::string*> getActivePrivilegeNames(
- const PrivilegeType type) const {
- std::vector<const std::string*> activePrivileges;
-
- int searchIndex = 0;
- int endIndex = basePrivilegeCount;
- if (type == PrivilegeType::OEM) {
- searchIndex = basePrivilegeCount - 1;
- endIndex = privilegeNames.size();
+ /**
+ * @brief Sets given privilege in the bitset
+ *
+ * @param[in] privilege Privilege to be set
+ *
+ * @return None
+ *
+ */
+ bool setSinglePrivilege(const std::string& privilege)
+ {
+ return setSinglePrivilege(privilege.c_str());
}
- for (; searchIndex < endIndex; searchIndex++) {
- if (privilegeBitset.test(searchIndex)) {
- activePrivileges.emplace_back(&privilegeNames[searchIndex]);
- }
+ /**
+ * @brief Retrieves names of all active privileges for a given type
+ *
+ * @param[in] type Base or OEM
+ *
+ * @return Vector of active privileges. Pointers are valid until
+ * the setSinglePrivilege is called, or the Privilege structure is destroyed
+ *
+ */
+ std::vector<const std::string*>
+ getActivePrivilegeNames(const PrivilegeType type) const
+ {
+ std::vector<const std::string*> activePrivileges;
+
+ int searchIndex = 0;
+ int endIndex = basePrivilegeCount;
+ if (type == PrivilegeType::OEM)
+ {
+ searchIndex = basePrivilegeCount - 1;
+ endIndex = privilegeNames.size();
+ }
+
+ for (; searchIndex < endIndex; searchIndex++)
+ {
+ if (privilegeBitset.test(searchIndex))
+ {
+ activePrivileges.emplace_back(&privilegeNames[searchIndex]);
+ }
+ }
+
+ return activePrivileges;
}
- return activePrivileges;
- }
-
- /**
- * @brief Determines if this Privilege set is a superset of the given
- * privilege set
- *
- * @param[in] privilege Privilege to be checked
- *
- * @return None
- *
- */
- bool isSupersetOf(const Privileges& p) const {
- return (privilegeBitset & p.privilegeBitset) == p.privilegeBitset;
- }
-
- private:
- std::bitset<maxPrivilegeCount> privilegeBitset = 0;
+ /**
+ * @brief Determines if this Privilege set is a superset of the given
+ * privilege set
+ *
+ * @param[in] privilege Privilege to be checked
+ *
+ * @return None
+ *
+ */
+ bool isSupersetOf(const Privileges& p) const
+ {
+ return (privilegeBitset & p.privilegeBitset) == p.privilegeBitset;
+ }
+
+ private:
+ std::bitset<maxPrivilegeCount> privilegeBitset = 0;
};
using OperationMap = boost::container::flat_map<boost::beast::http::verb,
@@ -171,23 +190,28 @@ using OperationMap = boost::container::flat_map<boost::beast::http::verb,
*/
inline bool isMethodAllowedWithPrivileges(const boost::beast::http::verb method,
const OperationMap& operationMap,
- const Privileges& userPrivileges) {
- const auto& it = operationMap.find(method);
- if (it == operationMap.end()) {
- return false;
- }
+ const Privileges& userPrivileges)
+{
+ const auto& it = operationMap.find(method);
+ if (it == operationMap.end())
+ {
+ return false;
+ }
- // If there are no privileges assigned, assume no privileges required
- if (it->second.empty()) {
- return true;
- }
+ // If there are no privileges assigned, assume no privileges required
+ if (it->second.empty())
+ {
+ return true;
+ }
- for (auto& requiredPrivileges : it->second) {
- if (userPrivileges.isSupersetOf(requiredPrivileges)) {
- return true;
+ for (auto& requiredPrivileges : it->second)
+ {
+ if (userPrivileges.isSupersetOf(requiredPrivileges))
+ {
+ return true;
+ }
}
- }
- return false;
+ return false;
}
/**
@@ -201,13 +225,14 @@ inline bool isMethodAllowedWithPrivileges(const boost::beast::http::verb method,
*/
inline bool isMethodAllowedForUser(const boost::beast::http::verb method,
const OperationMap& operationMap,
- const std::string& user) {
- // TODO: load user privileges from configuration as soon as its available
- // now we are granting all privileges to everyone.
- Privileges userPrivileges{"Login", "ConfigureManager", "ConfigureSelf",
- "ConfigureUsers", "ConfigureComponents"};
-
- return isMethodAllowedWithPrivileges(method, operationMap, userPrivileges);
+ const std::string& user)
+{
+ // TODO: load user privileges from configuration as soon as its available
+ // now we are granting all privileges to everyone.
+ Privileges userPrivileges{"Login", "ConfigureManager", "ConfigureSelf",
+ "ConfigureUsers", "ConfigureComponents"};
+
+ return isMethodAllowedWithPrivileges(method, operationMap, userPrivileges);
}
-} // namespace redfish
+} // namespace redfish
diff --git a/redfish-core/include/redfish.hpp b/redfish-core/include/redfish.hpp
index ab60abb90f..7f41b6339f 100644
--- a/redfish-core/include/redfish.hpp
+++ b/redfish-core/include/redfish.hpp
@@ -28,48 +28,53 @@
#include "../lib/update_service.hpp"
#include "webserver_common.hpp"
-namespace redfish {
+namespace redfish
+{
/*
* @brief Top level class installing and providing Redfish services
*/
-class RedfishService {
- public:
- /*
- * @brief Redfish service constructor
- *
- * Loads Redfish configuration and installs schema resources
- *
- * @param[in] app Crow app on which Redfish will initialize
- */
- RedfishService(CrowApp& app) {
- nodes.emplace_back(std::make_unique<AccountService>(app));
- nodes.emplace_back(std::make_unique<SessionCollection>(app));
- nodes.emplace_back(std::make_unique<Roles>(app));
- nodes.emplace_back(std::make_unique<RoleCollection>(app));
- nodes.emplace_back(std::make_unique<ServiceRoot>(app));
- nodes.emplace_back(std::make_unique<NetworkProtocol>(app));
- nodes.emplace_back(std::make_unique<SessionService>(app));
- nodes.emplace_back(std::make_unique<EthernetCollection>(app));
- nodes.emplace_back(std::make_unique<EthernetInterface>(app));
- nodes.emplace_back(std::make_unique<Thermal>(app));
- nodes.emplace_back(std::make_unique<ManagerCollection>(app));
- nodes.emplace_back(std::make_unique<Manager>(app));
- nodes.emplace_back(std::make_unique<ChassisCollection>(app));
- nodes.emplace_back(std::make_unique<Chassis>(app));
- nodes.emplace_back(std::make_unique<UpdateService>(app));
- nodes.emplace_back(std::make_unique<SoftwareInventoryCollection>(app));
- nodes.emplace_back(std::make_unique<SoftwareInventory>(app));
- nodes.emplace_back(std::make_unique<VlanNetworkInterfaceCollection>(app));
- nodes.emplace_back(std::make_unique<SystemsCollection>(app));
- nodes.emplace_back(std::make_unique<Systems>(app));
+class RedfishService
+{
+ public:
+ /*
+ * @brief Redfish service constructor
+ *
+ * Loads Redfish configuration and installs schema resources
+ *
+ * @param[in] app Crow app on which Redfish will initialize
+ */
+ RedfishService(CrowApp& app)
+ {
+ nodes.emplace_back(std::make_unique<AccountService>(app));
+ nodes.emplace_back(std::make_unique<SessionCollection>(app));
+ nodes.emplace_back(std::make_unique<Roles>(app));
+ nodes.emplace_back(std::make_unique<RoleCollection>(app));
+ nodes.emplace_back(std::make_unique<ServiceRoot>(app));
+ nodes.emplace_back(std::make_unique<NetworkProtocol>(app));
+ nodes.emplace_back(std::make_unique<SessionService>(app));
+ nodes.emplace_back(std::make_unique<EthernetCollection>(app));
+ nodes.emplace_back(std::make_unique<EthernetInterface>(app));
+ nodes.emplace_back(std::make_unique<Thermal>(app));
+ nodes.emplace_back(std::make_unique<ManagerCollection>(app));
+ nodes.emplace_back(std::make_unique<Manager>(app));
+ nodes.emplace_back(std::make_unique<ChassisCollection>(app));
+ nodes.emplace_back(std::make_unique<Chassis>(app));
+ nodes.emplace_back(std::make_unique<UpdateService>(app));
+ nodes.emplace_back(std::make_unique<SoftwareInventoryCollection>(app));
+ nodes.emplace_back(std::make_unique<SoftwareInventory>(app));
+ nodes.emplace_back(
+ std::make_unique<VlanNetworkInterfaceCollection>(app));
+ nodes.emplace_back(std::make_unique<SystemsCollection>(app));
+ nodes.emplace_back(std::make_unique<Systems>(app));
- for (auto& node : nodes) {
- node->getSubRoutes(nodes);
+ for (auto& node : nodes)
+ {
+ node->getSubRoutes(nodes);
+ }
}
- }
- private:
- std::vector<std::unique_ptr<Node>> nodes;
+ private:
+ std::vector<std::unique_ptr<Node>> nodes;
};
-} // namespace redfish
+} // namespace redfish
diff --git a/redfish-core/include/utils/json_utils.hpp b/redfish-core/include/utils/json_utils.hpp
index 25ac95417d..bde81ce72d 100644
--- a/redfish-core/include/utils/json_utils.hpp
+++ b/redfish-core/include/utils/json_utils.hpp
@@ -14,26 +14,36 @@
// limitations under the License.
*/
#pragma once
-#include <nlohmann/json.hpp>
#include <crow/http_request.h>
#include <crow/http_response.h>
-namespace redfish {
+#include <nlohmann/json.hpp>
+
+namespace redfish
+{
-namespace json_util {
+namespace json_util
+{
/**
* @brief Defines JSON utils operation status
*/
-enum class Result { SUCCESS, NOT_EXIST, WRONG_TYPE, NULL_POINTER };
+enum class Result
+{
+ SUCCESS,
+ NOT_EXIST,
+ WRONG_TYPE,
+ NULL_POINTER
+};
/**
* @brief Describes JSON utils messages requirement
*/
-enum class MessageSetting {
- NONE = 0x0, ///< No messages will be added
- MISSING = 0x1, ///< PropertyMissing message will be added
- TYPE_ERROR = 0x2 ///< PropertyValueTypeError message will be added
+enum class MessageSetting
+{
+ NONE = 0x0, ///< No messages will be added
+ MISSING = 0x1, ///< PropertyMissing message will be added
+ TYPE_ERROR = 0x2 ///< PropertyValueTypeError message will be added
};
/**
@@ -287,6 +297,6 @@ Result getDouble(const char* fieldName, const nlohmann::json& json,
bool processJsonFromRequest(crow::Response& res, const crow::Request& req,
nlohmann::json& reqJson);
-} // namespace json_util
+} // namespace json_util
-} // namespace redfish
+} // namespace redfish
diff --git a/redfish-core/lib/account_service.hpp b/redfish-core/lib/account_service.hpp
index 47b4c4c7b6..c58cafd633 100644
--- a/redfish-core/lib/account_service.hpp
+++ b/redfish-core/lib/account_service.hpp
@@ -17,40 +17,45 @@
#include "node.hpp"
-namespace redfish {
+namespace redfish
+{
-class AccountService : public Node {
- public:
- AccountService(CrowApp& app) : Node(app, "/redfish/v1/AccountService/") {
- Node::json["@odata.id"] = "/redfish/v1/AccountService";
- Node::json["@odata.type"] = "#AccountService.v1_1_0.AccountService";
- Node::json["@odata.context"] =
- "/redfish/v1/$metadata#AccountService.AccountService";
- Node::json["Id"] = "AccountService";
- Node::json["Description"] = "BMC User Accounts";
- Node::json["Name"] = "Account Service";
- Node::json["ServiceEnabled"] = true;
- Node::json["MinPasswordLength"] = 1;
- Node::json["MaxPasswordLength"] = 20;
- Node::json["Accounts"]["@odata.id"] = "/redfish/v1/AccountService/Accounts";
- Node::json["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles";
+class AccountService : public Node
+{
+ public:
+ AccountService(CrowApp& app) : Node(app, "/redfish/v1/AccountService/")
+ {
+ Node::json["@odata.id"] = "/redfish/v1/AccountService";
+ Node::json["@odata.type"] = "#AccountService.v1_1_0.AccountService";
+ Node::json["@odata.context"] =
+ "/redfish/v1/$metadata#AccountService.AccountService";
+ Node::json["Id"] = "AccountService";
+ Node::json["Description"] = "BMC User Accounts";
+ Node::json["Name"] = "Account Service";
+ Node::json["ServiceEnabled"] = true;
+ Node::json["MinPasswordLength"] = 1;
+ Node::json["MaxPasswordLength"] = 20;
+ Node::json["Accounts"]["@odata.id"] =
+ "/redfish/v1/AccountService/Accounts";
+ Node::json["Roles"]["@odata.id"] = "/redfish/v1/AccountService/Roles";
- entityPrivileges = {
- {boost::beast::http::verb::get,
- {{"ConfigureUsers"}, {"ConfigureManager"}}},
- {boost::beast::http::verb::head, {{"Login"}}},
- {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
- {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
- {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
- }
+ entityPrivileges = {
+ {boost::beast::http::verb::get,
+ {{"ConfigureUsers"}, {"ConfigureManager"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureUsers"}}},
+ {boost::beast::http::verb::put, {{"ConfigureUsers"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureUsers"}}},
+ {boost::beast::http::verb::post, {{"ConfigureUsers"}}}};
+ }
- private:
- void doGet(crow::Response& res, const crow::Request& req,
- const std::vector<std::string>& params) override {
- res.jsonValue = Node::json;
- res.end();
- }
+ private:
+ void doGet(crow::Response& res, const crow::Request& req,
+ const std::vector<std::string>& params) override
+ {
+ res.jsonValue = Node::json;
+ res.end();
+ }
};
-} // namespace redfish
+} // namespace redfish
diff --git a/redfish-core/lib/chassis.hpp b/redfish-core/lib/chassis.hpp
index b1c20a538a..7b68a270ad 100644
--- a/redfish-core/lib/chassis.hpp
+++ b/redfish-core/lib/chassis.hpp
@@ -16,9 +16,11 @@
#pragma once
#include "node.hpp"
+
#include <boost/container/flat_map.hpp>
-namespace redfish {
+namespace redfish
+{
/**
* DBus types primitives for several generic DBus interfaces
@@ -47,220 +49,251 @@ using PropertiesType = boost::container::flat_map<std::string, VariantType>;
* This perhaps shall be different file, which has to be chosen on compile time
* depending on OEM needs
*/
-class OnDemandChassisProvider {
- public:
- /**
- * Function that retrieves all Chassis available through EntityManager.
- * @param callback a function that shall be called to convert Dbus output into
- * JSON.
- */
- template <typename CallbackFunc>
- void getChassisList(CallbackFunc &&callback) {
- const std::array<const char *, 4> interfaces = {
- "xyz.openbmc_project.Inventory.Item.Board",
- "xyz.openbmc_project.Inventory.Item.Chassis",
- "xyz.openbmc_project.Inventory.Item.PowerSupply",
- "xyz.openbmc_project.Inventory.Item.System",
+class OnDemandChassisProvider
+{
+ public:
+ /**
+ * Function that retrieves all Chassis available through EntityManager.
+ * @param callback a function that shall be called to convert Dbus output
+ * into JSON.
+ */
+ template <typename CallbackFunc>
+ void getChassisList(CallbackFunc &&callback)
+ {
+ const std::array<const char *, 4> interfaces = {
+ "xyz.openbmc_project.Inventory.Item.Board",
+ "xyz.openbmc_project.Inventory.Item.Chassis",
+ "xyz.openbmc_project.Inventory.Item.PowerSupply",
+ "xyz.openbmc_project.Inventory.Item.System",
+ };
+ crow::connections::systemBus->async_method_call(
+ [callback{std::move(callback)}](
+ const boost::system::error_code error_code,
+ const std::vector<std::string> &resp) {
+ // Callback requires vector<string> to retrieve all available
+ // chassis list.
+ std::vector<std::string> chassisList;
+ if (error_code)
+ {
+ // Something wrong on DBus, the error_code is not important
+ // at this moment, just return success=false, and empty
+ // output. Since size of vector may vary depending on
+ // information from Entity Manager, and empty output could
+ // not be treated same way as error.
+ callback(false, chassisList);
+ return;
+ }
+ // Iterate over all retrieved ObjectPaths.
+ for (const std::string &objpath : resp)
+ {
+ std::size_t lastPos = objpath.rfind("/");
+ if (lastPos != std::string::npos)
+ {
+ // and put it into output vector.
+ chassisList.emplace_back(objpath.substr(lastPos + 1));
+ }
+ }
+ // Finally make a callback with useful data
+ callback(true, chassisList);
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
+ "/xyz/openbmc_project/inventory", int32_t(3), interfaces);
};
- crow::connections::systemBus->async_method_call(
- [callback{std::move(callback)}](
- const boost::system::error_code error_code,
- const std::vector<std::string> &resp) {
- // Callback requires vector<string> to retrieve all available chassis
- // list.
- std::vector<std::string> chassisList;
- if (error_code) {
- // Something wrong on DBus, the error_code is not important at this
- // moment, just return success=false, and empty output. Since size
- // of vector may vary depending on information from Entity Manager,
- // and empty output could not be treated same way as error.
- callback(false, chassisList);
- return;
- }
- // Iterate over all retrieved ObjectPaths.
- for (const std::string &objpath : resp) {
- std::size_t lastPos = objpath.rfind("/");
- if (lastPos != std::string::npos) {
- // and put it into output vector.
- chassisList.emplace_back(objpath.substr(lastPos + 1));
- }
- }
- // Finally make a callback with useful data
- callback(true, chassisList);
- },
- "xyz.openbmc_project.ObjectMapper",
- "/xyz/openbmc_project/object_mapper",
- "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
- "/xyz/openbmc_project/inventory", int32_t(3), interfaces);
- };
};
/**
* ChassisCollection derived class for delivering Chassis Collection Schema
*/
-class ChassisCollection : public Node {
- public:
- ChassisCollection(CrowApp &app) : Node(app, "/redfish/v1/Chassis/") {
- Node::json["@odata.type"] = "#ChassisCollection.ChassisCollection";
- Node::json["@odata.id"] = "/redfish/v1/Chassis";
- Node::json["@odata.context"] =
- "/redfish/v1/$metadata#ChassisCollection.ChassisCollection";
- Node::json["Name"] = "Chassis Collection";
+class ChassisCollection : public Node
+{
+ public:
+ ChassisCollection(CrowApp &app) : Node(app, "/redfish/v1/Chassis/")
+ {
+ Node::json["@odata.type"] = "#ChassisCollection.ChassisCollection";
+ Node::json["@odata.id"] = "/redfish/v1/Chassis";
+ Node::json["@odata.context"] =
+ "/redfish/v1/$metadata#ChassisCollection.ChassisCollection";
+ Node::json["Name"] = "Chassis Collection";
- entityPrivileges = {
- {boost::beast::http::verb::get, {{"Login"}}},
- {boost::beast::http::verb::head, {{"Login"}}},
- {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
- }
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
+ }
- private:
- /**
- * Functions triggers appropriate requests on DBus
- */
- void doGet(crow::Response &res, const crow::Request &req,
- const std::vector<std::string> &params) override {
- // get chassis list, and call the below callback for JSON preparation
- chassisProvider.getChassisList(
- [&](const bool &success, const std::vector<std::string> &output) {
- if (success) {
- // ... prepare json array with appropriate @odata.id links
- nlohmann::json chassisArray = nlohmann::json::array();
- for (const std::string &chassisItem : output) {
- chassisArray.push_back(
- {{"@odata.id", "/redfish/v1/Chassis/" + chassisItem}});
- }
- // Then attach members, count size and return,
- Node::json["Members"] = chassisArray;
- Node::json["Members@odata.count"] = chassisArray.size();
- res.jsonValue = Node::json;
- } else {
- // ... otherwise, return INTERNALL ERROR
- res.result(boost::beast::http::status::internal_server_error);
- }
- res.end();
- });
- }
+ private:
+ /**
+ * Functions triggers appropriate requests on DBus
+ */
+ void doGet(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> &params) override
+ {
+ // get chassis list, and call the below callback for JSON preparation
+ chassisProvider.getChassisList(
+ [&](const bool &success, const std::vector<std::string> &output) {
+ if (success)
+ {
+ // ... prepare json array with appropriate @odata.id links
+ nlohmann::json chassisArray = nlohmann::json::array();
+ for (const std::string &chassisItem : output)
+ {
+ chassisArray.push_back(
+ {{"@odata.id",
+ "/redfish/v1/Chassis/" + chassisItem}});
+ }
+ // Then attach members, count size and return,
+ Node::json["Members"] = chassisArray;
+ Node::json["Members@odata.count"] = chassisArray.size();
+ res.jsonValue = Node::json;
+ }
+ else
+ {
+ // ... otherwise, return INTERNALL ERROR
+ res.result(
+ boost::beast::http::status::internal_server_error);
+ }
+ res.end();
+ });
+ }
- // Chassis Provider object
- // TODO(Pawel) consider move it to singleton
- OnDemandChassisProvider chassisProvider;
+ // Chassis Provider object
+ // TODO(Pawel) consider move it to singleton
+ OnDemandChassisProvider chassisProvider;
};
/**
* Chassis override class for delivering Chassis Schema
*/
-class Chassis : public Node {
- public:
- Chassis(CrowApp &app)
- : Node(app, "/redfish/v1/Chassis/<str>/", std::string()) {
- Node::json["@odata.type"] = "#Chassis.v1_4_0.Chassis";
- Node::json["@odata.id"] = "/redfish/v1/Chassis";
- Node::json["@odata.context"] = "/redfish/v1/$metadata#Chassis.Chassis";
- Node::json["Name"] = "Chassis Collection";
- Node::json["ChassisType"] = "RackMount";
-
- entityPrivileges = {
- {boost::beast::http::verb::get, {{"Login"}}},
- {boost::beast::http::verb::head, {{"Login"}}},
- {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
- }
+class Chassis : public Node
+{
+ public:
+ Chassis(CrowApp &app) :
+ Node(app, "/redfish/v1/Chassis/<str>/", std::string())
+ {
+ Node::json["@odata.type"] = "#Chassis.v1_4_0.Chassis";
+ Node::json["@odata.id"] = "/redfish/v1/Chassis";
+ Node::json["@odata.context"] = "/redfish/v1/$metadata#Chassis.Chassis";
+ Node::json["Name"] = "Chassis Collection";
+ Node::json["ChassisType"] = "RackMount";
- private:
- /**
- * Functions triggers appropriate requests on DBus
- */
- void doGet(crow::Response &res, const crow::Request &req,
- const std::vector<std::string> &params) override {
- // Check if there is required param, truly entering this shall be
- // impossible.
- if (params.size() != 1) {
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
- return;
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
}
- res.jsonValue = Node::json;
- const std::string &chassisId = params[0];
- crow::connections::systemBus->async_method_call(
- [&res, chassisId(std::string(chassisId)) ](
- const boost::system::error_code error_code,
- const std::vector<std::pair<
- std::string,
- std::vector<std::pair<std::string, std::vector<std::string>>>>>
- &subtree) {
- if (error_code) {
- res.jsonValue = {};
+ private:
+ /**
+ * Functions triggers appropriate requests on DBus
+ */
+ void doGet(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> &params) override
+ {
+ // Check if there is required param, truly entering this shall be
+ // impossible.
+ if (params.size() != 1)
+ {
res.result(boost::beast::http::status::internal_server_error);
res.end();
return;
- }
- // Iterate over all retrieved ObjectPaths.
- for (const std::pair<std::string,
- std::vector<std::pair<std::string,
- std::vector<std::string>>>>
- &object : subtree) {
- const std::string &path = object.first;
- const std::vector<std::pair<std::string, std::vector<std::string>>>
- &connectionNames = object.second;
+ }
- if (!boost::ends_with(path, chassisId)) {
- continue;
- }
- if (connectionNames.size() < 1) {
- BMCWEB_LOG_ERROR << "Only got " << connectionNames.size()
- << " Connection names";
- continue;
- }
+ res.jsonValue = Node::json;
+ const std::string &chassisId = params[0];
+ crow::connections::systemBus->async_method_call(
+ [&res, chassisId(std::string(chassisId))](
+ const boost::system::error_code error_code,
+ const std::vector<std::pair<
+ std::string, std::vector<std::pair<
+ std::string, std::vector<std::string>>>>>
+ &subtree) {
+ if (error_code)
+ {
+ res.jsonValue = {};
+ res.result(
+ boost::beast::http::status::internal_server_error);
+ res.end();
+ return;
+ }
+ // Iterate over all retrieved ObjectPaths.
+ for (const std::pair<
+ std::string,
+ std::vector<
+ std::pair<std::string, std::vector<std::string>>>>
+ &object : subtree)
+ {
+ const std::string &path = object.first;
+ const std::vector<
+ std::pair<std::string, std::vector<std::string>>>
+ &connectionNames = object.second;
- const std::string connectionName = connectionNames[0].first;
- crow::connections::systemBus->async_method_call(
- [&res, chassisId(std::string(chassisId)) ](
- const boost::system::error_code error_code,
- const std::vector<std::pair<std::string, VariantType>>
- &propertiesList) {
- for (const std::pair<std::string, VariantType> &property :
- propertiesList) {
- const std::string *value =
- mapbox::getPtr<const std::string>(property.second);
- if (value != nullptr) {
- res.jsonValue[property.first] = *value;
+ if (!boost::ends_with(path, chassisId))
+ {
+ continue;
}
- }
- res.jsonValue["Name"] = chassisId;
- res.jsonValue["Id"] = chassisId;
- res.jsonValue["Thermal"] = {
- {"@odata.id",
- "/redfish/v1/Chassis/" + chassisId + "/Thermal"}};
- res.end();
- },
- connectionName, path, "org.freedesktop.DBus.Properties",
- "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset");
- // Found the Connection we were looking for, return
- return;
- }
+ if (connectionNames.size() < 1)
+ {
+ BMCWEB_LOG_ERROR << "Only got "
+ << connectionNames.size()
+ << " Connection names";
+ continue;
+ }
+
+ const std::string connectionName = connectionNames[0].first;
+ crow::connections::systemBus->async_method_call(
+ [&res, chassisId(std::string(chassisId))](
+ const boost::system::error_code error_code,
+ const std::vector<std::pair<
+ std::string, VariantType>> &propertiesList) {
+ for (const std::pair<std::string, VariantType>
+ &property : propertiesList)
+ {
+ const std::string *value =
+ mapbox::getPtr<const std::string>(
+ property.second);
+ if (value != nullptr)
+ {
+ res.jsonValue[property.first] = *value;
+ }
+ }
+ res.jsonValue["Name"] = chassisId;
+ res.jsonValue["Id"] = chassisId;
+ res.jsonValue["Thermal"] = {
+ {"@odata.id", "/redfish/v1/Chassis/" +
+ chassisId + "/Thermal"}};
+ res.end();
+ },
+ connectionName, path, "org.freedesktop.DBus.Properties",
+ "GetAll",
+ "xyz.openbmc_project.Inventory.Decorator.Asset");
+ // Found the Connection we were looking for, return
+ return;
+ }
- // Couldn't find an object with that name. return an error
- res.result(boost::beast::http::status::not_found);
+ // Couldn't find an object with that name. return an error
+ res.result(boost::beast::http::status::not_found);
- res.end();
- },
- "xyz.openbmc_project.ObjectMapper",
- "/xyz/openbmc_project/object_mapper",
- "xyz.openbmc_project.ObjectMapper", "GetSubTree",
- "/xyz/openbmc_project/inventory", int32_t(0),
- std::array<const char *, 1>{
- "xyz.openbmc_project.Inventory.Decorator.Asset"});
- }
+ res.end();
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
+ "/xyz/openbmc_project/inventory", int32_t(0),
+ std::array<const char *, 1>{
+ "xyz.openbmc_project.Inventory.Decorator.Asset"});
+ }
- // Chassis Provider object
- // TODO(Pawel) consider move it to singleton
- OnDemandChassisProvider chassisProvider;
-}; // namespace redfish
+ // Chassis Provider object
+ // TODO(Pawel) consider move it to singleton
+ OnDemandChassisProvider chassisProvider;
+}; // namespace redfish
-} // namespace redfish
+} // namespace redfish
diff --git a/redfish-core/lib/ethernet.hpp b/redfish-core/lib/ethernet.hpp
index 01111a4e5f..0c642798b5 100644
--- a/redfish-core/lib/ethernet.hpp
+++ b/redfish-core/lib/ethernet.hpp
@@ -15,13 +15,14 @@
*/
#pragma once
+#include <boost/container/flat_map.hpp>
#include <dbus_singleton.hpp>
#include <error_messages.hpp>
#include <node.hpp>
#include <utils/json_utils.hpp>
-#include <boost/container/flat_map.hpp>
-namespace redfish {
+namespace redfish
+{
/**
* DBus types primitives for several generic DBus interfaces
@@ -45,35 +46,40 @@ using GetManagedObjectsType = boost::container::flat_map<
* Structure for keeping IPv4 data required by Redfish
* TODO(Pawel) consider change everything to ptr, or to non-ptr values.
*/
-struct IPv4AddressData {
- std::string id;
- const std::string *address;
- const std::string *domain;
- const std::string *gateway;
- std::string netmask;
- std::string origin;
- bool global;
- /**
- * @brief Operator< to enable sorting
- *
- * @param[in] obj Object to compare with
- *
- * @return This object id < supplied object id
- */
- bool operator<(const IPv4AddressData &obj) const { return (id < obj.id); }
+struct IPv4AddressData
+{
+ std::string id;
+ const std::string *address;
+ const std::string *domain;
+ const std::string *gateway;
+ std::string netmask;
+ std::string origin;
+ bool global;
+ /**
+ * @brief Operator< to enable sorting
+ *
+ * @param[in] obj Object to compare with
+ *
+ * @return This object id < supplied object id
+ */
+ bool operator<(const IPv4AddressData &obj) const
+ {
+ return (id < obj.id);
+ }
};
/**
* Structure for keeping basic single Ethernet Interface information
* available from DBus
*/
-struct EthernetInterfaceData {
- const unsigned int *speed;
- const bool *autoNeg;
- const std::string *hostname;
- const std::string *defaultGateway;
- const std::string *macAddress;
- const unsigned int *vlanId;
+struct EthernetInterfaceData
+{
+ const unsigned int *speed;
+ const bool *autoNeg;
+ const std::string *hostname;
+ const std::string *defaultGateway;
+ const std::string *macAddress;
+ const unsigned int *vlanId;
};
/**
@@ -85,1264 +91,1493 @@ struct EthernetInterfaceData {
* This perhaps shall be different file, which has to be chosen on compile time
* depending on OEM needs
*/
-class OnDemandEthernetProvider {
- private:
- // Consts that may have influence on EthernetProvider performance/memory usage
- const size_t maxIpV4AddressesPerInterface = 10;
-
- // Helper function that allows to extract GetAllPropertiesType from
- // GetManagedObjectsType, based on object path, and interface name
- const PropertiesMapType *extractInterfaceProperties(
- const sdbusplus::message::object_path &objpath,
- const std::string &interface, const GetManagedObjectsType &dbus_data) {
- const auto &dbusObj = dbus_data.find(objpath);
- if (dbusObj != dbus_data.end()) {
- const auto &iface = dbusObj->second.find(interface);
- if (iface != dbusObj->second.end()) {
- return &iface->second;
- }
+class OnDemandEthernetProvider
+{
+ private:
+ // Consts that may have influence on EthernetProvider performance/memory
+ // usage
+ const size_t maxIpV4AddressesPerInterface = 10;
+
+ // Helper function that allows to extract GetAllPropertiesType from
+ // GetManagedObjectsType, based on object path, and interface name
+ const PropertiesMapType *extractInterfaceProperties(
+ const sdbusplus::message::object_path &objpath,
+ const std::string &interface, const GetManagedObjectsType &dbus_data)
+ {
+ const auto &dbusObj = dbus_data.find(objpath);
+ if (dbusObj != dbus_data.end())
+ {
+ const auto &iface = dbusObj->second.find(interface);
+ if (iface != dbusObj->second.end())
+ {
+ return &iface->second;
+ }
+ }
+ return nullptr;
}
- return nullptr;
- }
-
- // Helper Wrapper that does inline object_path conversion from string
- // into sdbusplus::message::object_path type
- inline const PropertiesMapType *extractInterfaceProperties(
- const std::string &objpath, const std::string &interface,
- const GetManagedObjectsType &dbus_data) {
- const auto &dbusObj = sdbusplus::message::object_path{objpath};
- return extractInterfaceProperties(dbusObj, interface, dbus_data);
- }
-
- // Helper function that allows to get pointer to the property from
- // GetAllPropertiesType native, or extracted by GetAllPropertiesType
- template <typename T>
- inline T const *const extractProperty(const PropertiesMapType &properties,
- const std::string &name) {
- const auto &property = properties.find(name);
- if (property != properties.end()) {
- return mapbox::getPtr<const T>(property->second);
+
+ // Helper Wrapper that does inline object_path conversion from string
+ // into sdbusplus::message::object_path type
+ inline const PropertiesMapType *
+ extractInterfaceProperties(const std::string &objpath,
+ const std::string &interface,
+ const GetManagedObjectsType &dbus_data)
+ {
+ const auto &dbusObj = sdbusplus::message::object_path{objpath};
+ return extractInterfaceProperties(dbusObj, interface, dbus_data);
}
- return nullptr;
- }
- // TODO(Pawel) Consider to move the above functions to dbus
- // generic_interfaces.hpp
-
- // Helper function that extracts data from several dbus objects and several
- // interfaces required by single ethernet interface instance
- void extractEthernetInterfaceData(const std::string &ethifaceId,
- const GetManagedObjectsType &dbus_data,
- EthernetInterfaceData &eth_data) {
- // Extract data that contains MAC Address
- const PropertiesMapType *macProperties = extractInterfaceProperties(
- "/xyz/openbmc_project/network/" + ethifaceId,
- "xyz.openbmc_project.Network.MACAddress", dbus_data);
-
- if (macProperties != nullptr) {
- eth_data.macAddress =
- extractProperty<std::string>(*macProperties, "MACAddress");
+
+ // Helper function that allows to get pointer to the property from
+ // GetAllPropertiesType native, or extracted by GetAllPropertiesType
+ template <typename T>
+ inline T const *const extractProperty(const PropertiesMapType &properties,
+ const std::string &name)
+ {
+ const auto &property = properties.find(name);
+ if (property != properties.end())
+ {
+ return mapbox::getPtr<const T>(property->second);
+ }
+ return nullptr;
}
+ // TODO(Pawel) Consider to move the above functions to dbus
+ // generic_interfaces.hpp
+
+ // Helper function that extracts data from several dbus objects and several
+ // interfaces required by single ethernet interface instance
+ void extractEthernetInterfaceData(const std::string &ethifaceId,
+ const GetManagedObjectsType &dbus_data,
+ EthernetInterfaceData &eth_data)
+ {
+ // Extract data that contains MAC Address
+ const PropertiesMapType *macProperties = extractInterfaceProperties(
+ "/xyz/openbmc_project/network/" + ethifaceId,
+ "xyz.openbmc_project.Network.MACAddress", dbus_data);
+
+ if (macProperties != nullptr)
+ {
+ eth_data.macAddress =
+ extractProperty<std::string>(*macProperties, "MACAddress");
+ }
- const PropertiesMapType *vlanProperties = extractInterfaceProperties(
- "/xyz/openbmc_project/network/" + ethifaceId,
- "xyz.openbmc_project.Network.VLAN", dbus_data);
+ const PropertiesMapType *vlanProperties = extractInterfaceProperties(
+ "/xyz/openbmc_project/network/" + ethifaceId,
+ "xyz.openbmc_project.Network.VLAN", dbus_data);
- if (vlanProperties != nullptr) {
- eth_data.vlanId = extractProperty<unsigned int>(*vlanProperties, "Id");
- }
+ if (vlanProperties != nullptr)
+ {
+ eth_data.vlanId =
+ extractProperty<unsigned int>(*vlanProperties, "Id");
+ }
- // Extract data that contains link information (auto negotiation and speed)
- const PropertiesMapType *ethProperties = extractInterfaceProperties(
- "/xyz/openbmc_project/network/" + ethifaceId,
- "xyz.openbmc_project.Network.EthernetInterface", dbus_data);
+ // Extract data that contains link information (auto negotiation and
+ // speed)
+ const PropertiesMapType *ethProperties = extractInterfaceProperties(
+ "/xyz/openbmc_project/network/" + ethifaceId,
+ "xyz.openbmc_project.Network.EthernetInterface", dbus_data);
+
+ if (ethProperties != nullptr)
+ {
+ eth_data.autoNeg = extractProperty<bool>(*ethProperties, "AutoNeg");
+ eth_data.speed =
+ extractProperty<unsigned int>(*ethProperties, "Speed");
+ }
- if (ethProperties != nullptr) {
- eth_data.autoNeg = extractProperty<bool>(*ethProperties, "AutoNeg");
- eth_data.speed = extractProperty<unsigned int>(*ethProperties, "Speed");
+ // Extract data that contains network config (HostName and DefaultGW)
+ const PropertiesMapType *configProperties = extractInterfaceProperties(
+ "/xyz/openbmc_project/network/config",
+ "xyz.openbmc_project.Network.SystemConfiguration", dbus_data);
+
+ if (configProperties != nullptr)
+ {
+ eth_data.hostname =
+ extractProperty<std::string>(*configProperties, "HostName");
+ eth_data.defaultGateway = extractProperty<std::string>(
+ *configProperties, "DefaultGateway");
+ }
}
- // Extract data that contains network config (HostName and DefaultGW)
- const PropertiesMapType *configProperties = extractInterfaceProperties(
- "/xyz/openbmc_project/network/config",
- "xyz.openbmc_project.Network.SystemConfiguration", dbus_data);
-
- if (configProperties != nullptr) {
- eth_data.hostname =
- extractProperty<std::string>(*configProperties, "HostName");
- eth_data.defaultGateway =
- extractProperty<std::string>(*configProperties, "DefaultGateway");
+ // Helper function that changes bits netmask notation (i.e. /24)
+ // into full dot notation
+ inline std::string getNetmask(unsigned int bits)
+ {
+ uint32_t value = 0xffffffff << (32 - bits);
+ std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
+ std::to_string((value >> 16) & 0xff) + "." +
+ std::to_string((value >> 8) & 0xff) + "." +
+ std::to_string(value & 0xff);
+ return netmask;
}
- }
-
- // Helper function that changes bits netmask notation (i.e. /24)
- // into full dot notation
- inline std::string getNetmask(unsigned int bits) {
- uint32_t value = 0xffffffff << (32 - bits);
- std::string netmask = std::to_string((value >> 24) & 0xff) + "." +
- std::to_string((value >> 16) & 0xff) + "." +
- std::to_string((value >> 8) & 0xff) + "." +
- std::to_string(value & 0xff);
- return netmask;
- }
-
- // Helper function that extracts data for single ethernet ipv4 address
- void extractIPv4Data(const std::string &ethifaceId,
- const GetManagedObjectsType &dbus_data,
- std::vector<IPv4AddressData> &ipv4_config) {
- const std::string pathStart =
- "/xyz/openbmc_project/network/" + ethifaceId + "/ipv4/";
-
- // Since there might be several IPv4 configurations aligned with
- // single ethernet interface, loop over all of them
- for (auto &objpath : dbus_data) {
- // Check if proper patter for object path appears
- if (boost::starts_with(static_cast<const std::string &>(objpath.first),
- pathStart)) {
- // and get approrpiate interface
- const auto &interface =
- objpath.second.find("xyz.openbmc_project.Network.IP");
- if (interface != objpath.second.end()) {
- // Make a properties 'shortcut', to make everything more readable
- const PropertiesMapType &properties = interface->second;
- // Instance IPv4AddressData structure, and set as appropriate
- IPv4AddressData ipv4Address;
-
- ipv4Address.id = static_cast<const std::string &>(objpath.first)
- .substr(pathStart.size());
-
- // IPv4 address
- ipv4Address.address =
- extractProperty<std::string>(properties, "Address");
- // IPv4 gateway
- ipv4Address.gateway =
- extractProperty<std::string>(properties, "Gateway");
-
- // Origin is kind of DBus object so fetch pointer...
- const std::string *origin =
- extractProperty<std::string>(properties, "Origin");
- if (origin != nullptr) {
- ipv4Address.origin =
- translateAddressOriginBetweenDBusAndRedfish(origin, true, true);
- }
-
- // Netmask is presented as PrefixLength
- const auto *mask =
- extractProperty<uint8_t>(properties, "PrefixLength");
- if (mask != nullptr) {
- // convert it to the string
- ipv4Address.netmask = getNetmask(*mask);
- }
-
- // Attach IPv4 only if address is present
- if (ipv4Address.address != nullptr) {
- // Check if given address is local, or global
- if (boost::starts_with(*ipv4Address.address, "169.254")) {
- ipv4Address.global = false;
- } else {
- ipv4Address.global = true;
+
+ // Helper function that extracts data for single ethernet ipv4 address
+ void extractIPv4Data(const std::string &ethifaceId,
+ const GetManagedObjectsType &dbus_data,
+ std::vector<IPv4AddressData> &ipv4_config)
+ {
+ const std::string pathStart =
+ "/xyz/openbmc_project/network/" + ethifaceId + "/ipv4/";
+
+ // Since there might be several IPv4 configurations aligned with
+ // single ethernet interface, loop over all of them
+ for (auto &objpath : dbus_data)
+ {
+ // Check if proper patter for object path appears
+ if (boost::starts_with(
+ static_cast<const std::string &>(objpath.first), pathStart))
+ {
+ // and get approrpiate interface
+ const auto &interface =
+ objpath.second.find("xyz.openbmc_project.Network.IP");
+ if (interface != objpath.second.end())
+ {
+ // Make a properties 'shortcut', to make everything more
+ // readable
+ const PropertiesMapType &properties = interface->second;
+ // Instance IPv4AddressData structure, and set as
+ // appropriate
+ IPv4AddressData ipv4Address;
+
+ ipv4Address.id =
+ static_cast<const std::string &>(objpath.first)
+ .substr(pathStart.size());
+
+ // IPv4 address
+ ipv4Address.address =
+ extractProperty<std::string>(properties, "Address");
+ // IPv4 gateway
+ ipv4Address.gateway =
+ extractProperty<std::string>(properties, "Gateway");
+
+ // Origin is kind of DBus object so fetch pointer...
+ const std::string *origin =
+ extractProperty<std::string>(properties, "Origin");
+ if (origin != nullptr)
+ {
+ ipv4Address.origin =
+ translateAddressOriginBetweenDBusAndRedfish(
+ origin, true, true);
+ }
+
+ // Netmask is presented as PrefixLength
+ const auto *mask =
+ extractProperty<uint8_t>(properties, "PrefixLength");
+ if (mask != nullptr)
+ {
+ // convert it to the string
+ ipv4Address.netmask = getNetmask(*mask);
+ }
+
+ // Attach IPv4 only if address is present
+ if (ipv4Address.address != nullptr)
+ {
+ // Check if given address is local, or global
+ if (boost::starts_with(*ipv4Address.address, "169.254"))
+ {
+ ipv4Address.global = false;
+ }
+ else
+ {
+ ipv4Address.global = true;
+ }
+ ipv4_config.emplace_back(std::move(ipv4Address));
+ }
+ }
}
- ipv4_config.emplace_back(std::move(ipv4Address));
- }
}
- }
+
+ /**
+ * We have to sort this vector and ensure that order of IPv4 addresses
+ * is consistent between GETs to allow modification and deletion in
+ * PATCHes
+ */
+ std::sort(ipv4_config.begin(), ipv4_config.end());
}
+ static const constexpr int ipV4AddressSectionsCount = 4;
+
+ public:
/**
- * We have to sort this vector and ensure that order of IPv4 addresses
- * is consistent between GETs to allow modification and deletion in PATCHes
+ * @brief Creates VLAN for given interface with given Id through D-Bus
+ *
+ * @param[in] ifaceId Id of interface for which VLAN will be created
+ * @param[in] inputVlanId ID of the new VLAN
+ * @param[in] callback Function that will be called after the operation
+ *
+ * @return None.
*/
- std::sort(ipv4_config.begin(), ipv4_config.end());
- }
-
- static const constexpr int ipV4AddressSectionsCount = 4;
-
- public:
- /**
- * @brief Creates VLAN for given interface with given Id through D-Bus
- *
- * @param[in] ifaceId Id of interface for which VLAN will be created
- * @param[in] inputVlanId ID of the new VLAN
- * @param[in] callback Function that will be called after the operation
- *
- * @return None.
- */
- template <typename CallbackFunc>
- void createVlan(const std::string &ifaceId, const uint64_t &inputVlanId,
- CallbackFunc &&callback) {
- crow::connections::systemBus->async_method_call(
- callback, "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
- "xyz.openbmc_project.Network.VLAN.Create", "VLAN", ifaceId,
- static_cast<uint32_t>(inputVlanId));
- };
-
- /**
- * @brief Sets given Id on the given VLAN interface through D-Bus
- *
- * @param[in] ifaceId Id of VLAN interface that should be modified
- * @param[in] inputVlanId New ID of the VLAN
- * @param[in] callback Function that will be called after the operation
- *
- * @return None.
- */
- template <typename CallbackFunc>
- static void changeVlanId(const std::string &ifaceId,
- const uint32_t &inputVlanId,
- CallbackFunc &&callback) {
- crow::connections::systemBus->async_method_call(
- callback, "xyz.openbmc_project.Network",
- std::string("/xyz/openbmc_project/network/") + ifaceId,
- "org.freedesktop.DBus.Properties", "Set",
- "xyz.openbmc_project.Network.VLAN", "Id",
- sdbusplus::message::variant<uint32_t>(inputVlanId));
- };
-
- /**
- * @brief Helper function that verifies IP address to check if it is in
- * proper format. If bits pointer is provided, also calculates active
- * bit count for Subnet Mask.
- *
- * @param[in] ip IP that will be verified
- * @param[out] bits Calculated mask in bits notation
- *
- * @return true in case of success, false otherwise
- */
- bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
- uint8_t *bits = nullptr) {
- std::vector<std::string> bytesInMask;
-
- boost::split(bytesInMask, ip, boost::is_any_of("."));
-
- if (bytesInMask.size() != ipV4AddressSectionsCount) {
- return false;
- }
+ template <typename CallbackFunc>
+ void createVlan(const std::string &ifaceId, const uint64_t &inputVlanId,
+ CallbackFunc &&callback)
+ {
+ crow::connections::systemBus->async_method_call(
+ callback, "xyz.openbmc_project.Network",
+ "/xyz/openbmc_project/network",
+ "xyz.openbmc_project.Network.VLAN.Create", "VLAN", ifaceId,
+ static_cast<uint32_t>(inputVlanId));
+ };
- if (bits != nullptr) {
- *bits = 0;
- }
+ /**
+ * @brief Sets given Id on the given VLAN interface through D-Bus
+ *
+ * @param[in] ifaceId Id of VLAN interface that should be modified
+ * @param[in] inputVlanId New ID of the VLAN
+ * @param[in] callback Function that will be called after the operation
+ *
+ * @return None.
+ */
+ template <typename CallbackFunc>
+ static void changeVlanId(const std::string &ifaceId,
+ const uint32_t &inputVlanId,
+ CallbackFunc &&callback)
+ {
+ crow::connections::systemBus->async_method_call(
+ callback, "xyz.openbmc_project.Network",
+ std::string("/xyz/openbmc_project/network/") + ifaceId,
+ "org.freedesktop.DBus.Properties", "Set",
+ "xyz.openbmc_project.Network.VLAN", "Id",
+ sdbusplus::message::variant<uint32_t>(inputVlanId));
+ };
+
+ /**
+ * @brief Helper function that verifies IP address to check if it is in
+ * proper format. If bits pointer is provided, also calculates active
+ * bit count for Subnet Mask.
+ *
+ * @param[in] ip IP that will be verified
+ * @param[out] bits Calculated mask in bits notation
+ *
+ * @return true in case of success, false otherwise
+ */
+ bool ipv4VerifyIpAndGetBitcount(const std::string &ip,
+ uint8_t *bits = nullptr)
+ {
+ std::vector<std::string> bytesInMask;
+
+ boost::split(bytesInMask, ip, boost::is_any_of("."));
- char *endPtr;
- long previousValue = 255;
- bool firstZeroInByteHit;
- for (const std::string &byte : bytesInMask) {
- if (byte.empty()) {
- return false;
- }
-
- // Use strtol instead of stroi to avoid exceptions
- long value = std::strtol(byte.c_str(), &endPtr, 10);
-
- // endPtr should point to the end of the string, otherwise given string
- // is not 100% number
- if (*endPtr != '\0') {
- return false;
- }
-
- // Value should be contained in byte
- if (value < 0 || value > 255) {
- return false;
- }
-
- if (bits != nullptr) {
- // Mask has to be continuous between bytes
- if (previousValue != 255 && value != 0) {
- return false;
+ if (bytesInMask.size() != ipV4AddressSectionsCount)
+ {
+ return false;
}
- // Mask has to be continuous inside bytes
- firstZeroInByteHit = false;
-
- // Count bits
- for (int bitIdx = 7; bitIdx >= 0; bitIdx--) {
- if (value & (1 << bitIdx)) {
- if (firstZeroInByteHit) {
- // Continuity not preserved
- return false;
- } else {
- (*bits)++;
+ if (bits != nullptr)
+ {
+ *bits = 0;
+ }
+
+ char *endPtr;
+ long previousValue = 255;
+ bool firstZeroInByteHit;
+ for (const std::string &byte : bytesInMask)
+ {
+ if (byte.empty())
+ {
+ return false;
+ }
+
+ // Use strtol instead of stroi to avoid exceptions
+ long value = std::strtol(byte.c_str(), &endPtr, 10);
+
+ // endPtr should point to the end of the string, otherwise given
+ // string is not 100% number
+ if (*endPtr != '\0')
+ {
+ return false;
+ }
+
+ // Value should be contained in byte
+ if (value < 0 || value > 255)
+ {
+ return false;
}
- } else {
- firstZeroInByteHit = true;
- }
+
+ if (bits != nullptr)
+ {
+ // Mask has to be continuous between bytes
+ if (previousValue != 255 && value != 0)
+ {
+ return false;
+ }
+
+ // Mask has to be continuous inside bytes
+ firstZeroInByteHit = false;
+
+ // Count bits
+ for (int bitIdx = 7; bitIdx >= 0; bitIdx--)
+ {
+ if (value & (1 << bitIdx))
+ {
+ if (firstZeroInByteHit)
+ {
+ // Continuity not preserved
+ return false;
+ }
+ else
+ {
+ (*bits)++;
+ }
+ }
+ else
+ {
+ firstZeroInByteHit = true;
+ }
+ }
+ }
+
+ previousValue = value;
}
- }
- previousValue = value;
+ return true;
}
- return true;
- }
-
- /**
- * @brief Changes IPv4 address type property (Address, Gateway)
- *
- * @param[in] ifaceId Id of interface whose IP should be modified
- * @param[in] ipIdx index of IP in input array that should be modified
- * @param[in] ipHash DBus Hash id of modified IP
- * @param[in] name Name of field in JSON representation
- * @param[in] newValue New value that should be written
- * @param[io] asyncResp Response object that will be returned to client
- *
- * @return true if give IP is valid and has been sent do D-Bus, false
- * otherwise
- */
- void changeIPv4AddressProperty(const std::string &ifaceId, int ipIdx,
- const std::string &ipHash,
- const std::string &name,
- const std::string &newValue,
- const std::shared_ptr<AsyncResp> &asyncResp) {
- auto callback = [
- asyncResp, ipIdx{std::move(ipIdx)}, name{std::move(name)},
- newValue{std::move(newValue)}
- ](const boost::system::error_code ec) {
- if (ec) {
- messages::addMessageToJson(
- asyncResp->res.jsonValue, messages::internalError(),
- "/IPv4Addresses/" + std::to_string(ipIdx) + "/" + name);
- } else {
- asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] = newValue;
- }
+ /**
+ * @brief Changes IPv4 address type property (Address, Gateway)
+ *
+ * @param[in] ifaceId Id of interface whose IP should be modified
+ * @param[in] ipIdx index of IP in input array that should be modified
+ * @param[in] ipHash DBus Hash id of modified IP
+ * @param[in] name Name of field in JSON representation
+ * @param[in] newValue New value that should be written
+ * @param[io] asyncResp Response object that will be returned to client
+ *
+ * @return true if give IP is valid and has been sent do D-Bus, false
+ * otherwise
+ */
+ void changeIPv4AddressProperty(const std::string &ifaceId, int ipIdx,
+ const std::string &ipHash,
+ const std::string &name,
+ const std::string &newValue,
+ const std::shared_ptr<AsyncResp> &asyncResp)
+ {
+ auto callback = [asyncResp, ipIdx{std::move(ipIdx)},
+ name{std::move(name)}, newValue{std::move(newValue)}](
+ const boost::system::error_code ec) {
+ if (ec)
+ {
+ messages::addMessageToJson(
+ asyncResp->res.jsonValue, messages::internalError(),
+ "/IPv4Addresses/" + std::to_string(ipIdx) + "/" + name);
+ }
+ else
+ {
+ asyncResp->res.jsonValue["IPv4Addresses"][ipIdx][name] =
+ newValue;
+ }
+ };
+
+ crow::connections::systemBus->async_method_call(
+ std::move(callback), "xyz.openbmc_project.Network",
+ "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
+ "org.freedesktop.DBus.Properties", "Set",
+ "xyz.openbmc_project.Network.IP", name,
+ sdbusplus::message::variant<std::string>(newValue));
};
- crow::connections::systemBus->async_method_call(
- std::move(callback), "xyz.openbmc_project.Network",
- "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
- "org.freedesktop.DBus.Properties", "Set",
- "xyz.openbmc_project.Network.IP", name,
- sdbusplus::message::variant<std::string>(newValue));
- };
-
- /**
- * @brief Changes IPv4 address origin property
- *
- * @param[in] ifaceId Id of interface whose IP should be modified
- * @param[in] ipIdx index of IP in input array that should be modified
- * @param[in] ipHash DBus Hash id of modified IP
- * @param[in] newValue New value in Redfish format
- * @param[in] newValueDbus New value in D-Bus format
- * @param[io] asyncResp Response object that will be returned to client
- *
- * @return true if give IP is valid and has been sent do D-Bus, false
- * otherwise
- */
- void changeIPv4Origin(const std::string &ifaceId, int ipIdx,
- const std::string &ipHash, const std::string &newValue,
- const std::string &newValueDbus,
- const std::shared_ptr<AsyncResp> &asyncResp) {
- auto callback =
- [ asyncResp, ipIdx{std::move(ipIdx)},
- newValue{std::move(newValue)} ](const boost::system::error_code ec) {
- if (ec) {
- messages::addMessageToJson(
- asyncResp->res.jsonValue, messages::internalError(),
- "/IPv4Addresses/" + std::to_string(ipIdx) + "/AddressOrigin");
- } else {
- asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] =
- newValue;
- }
+ /**
+ * @brief Changes IPv4 address origin property
+ *
+ * @param[in] ifaceId Id of interface whose IP should be modified
+ * @param[in] ipIdx index of IP in input array that should be
+ * modified
+ * @param[in] ipHash DBus Hash id of modified IP
+ * @param[in] newValue New value in Redfish format
+ * @param[in] newValueDbus New value in D-Bus format
+ * @param[io] asyncResp Response object that will be returned to client
+ *
+ * @return true if give IP is valid and has been sent do D-Bus, false
+ * otherwise
+ */
+ void changeIPv4Origin(const std::string &ifaceId, int ipIdx,
+ const std::string &ipHash,
+ const std::string &newValue,
+ const std::string &newValueDbus,
+ const std::shared_ptr<AsyncResp> &asyncResp)
+ {
+ auto callback = [asyncResp, ipIdx{std::move(ipIdx)},
+ newValue{std::move(newValue)}](
+ const boost::system::error_code ec) {
+ if (ec)
+ {
+ messages::addMessageToJson(
+ asyncResp->res.jsonValue, messages::internalError(),
+ "/IPv4Addresses/" + std::to_string(ipIdx) +
+ "/AddressOrigin");
+ }
+ else
+ {
+ asyncResp->res
+ .jsonValue["IPv4Addresses"][ipIdx]["AddressOrigin"] =
+ newValue;
+ }
+ };
+
+ crow::connections::systemBus->async_method_call(
+ std::move(callback), "xyz.openbmc_project.Network",
+ "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
+ "org.freedesktop.DBus.Properties", "Set",
+ "xyz.openbmc_project.Network.IP", "Origin",
+ sdbusplus::message::variant<std::string>(newValueDbus));
};
- crow::connections::systemBus->async_method_call(
- std::move(callback), "xyz.openbmc_project.Network",
- "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
- "org.freedesktop.DBus.Properties", "Set",
- "xyz.openbmc_project.Network.IP", "Origin",
- sdbusplus::message::variant<std::string>(newValueDbus));
- };
-
- /**
- * @brief Modifies SubnetMask for given IP
- *
- * @param[in] ifaceId Id of interface whose IP should be modified
- * @param[in] ipIdx index of IP in input array that should be modified
- * @param[in] ipHash DBus Hash id of modified IP
- * @param[in] newValueStr Mask in dot notation as string
- * @param[in] newValue Mask as PrefixLength in bitcount
- * @param[io] asyncResp Response object that will be returned to client
- *
- * @return None
- */
- void changeIPv4SubnetMaskProperty(
- const std::string &ifaceId, int ipIdx, const std::string &ipHash,
- const std::string &newValueStr, uint8_t &newValue,
- const std::shared_ptr<AsyncResp> &asyncResp) {
- auto callback = [
- asyncResp, ipIdx{std::move(ipIdx)}, newValueStr{std::move(newValueStr)}
- ](const boost::system::error_code ec) {
- if (ec) {
- messages::addMessageToJson(
- asyncResp->res.jsonValue, messages::internalError(),
- "/IPv4Addresses/" + std::to_string(ipIdx) + "/SubnetMask");
- } else {
- asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] =
- newValueStr;
- }
+ /**
+ * @brief Modifies SubnetMask for given IP
+ *
+ * @param[in] ifaceId Id of interface whose IP should be modified
+ * @param[in] ipIdx index of IP in input array that should be
+ * modified
+ * @param[in] ipHash DBus Hash id of modified IP
+ * @param[in] newValueStr Mask in dot notation as string
+ * @param[in] newValue Mask as PrefixLength in bitcount
+ * @param[io] asyncResp Response object that will be returned to client
+ *
+ * @return None
+ */
+ void changeIPv4SubnetMaskProperty(
+ const std::string &ifaceId, int ipIdx, const std::string &ipHash,
+ const std::string &newValueStr, uint8_t &newValue,
+ const std::shared_ptr<AsyncResp> &asyncResp)
+ {
+ auto callback = [asyncResp, ipIdx{std::move(ipIdx)},
+ newValueStr{std::move(newValueStr)}](
+ const boost::system::error_code ec) {
+ if (ec)
+ {
+ messages::addMessageToJson(
+ asyncResp->res.jsonValue, messages::internalError(),
+ "/IPv4Addresses/" + std::to_string(ipIdx) + "/SubnetMask");
+ }
+ else
+ {
+ asyncResp->res.jsonValue["IPv4Addresses"][ipIdx]["SubnetMask"] =
+ newValueStr;
+ }
+ };
+
+ crow::connections::systemBus->async_method_call(
+ std::move(callback), "xyz.openbmc_project.Network",
+ "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
+ "org.freedesktop.DBus.Properties", "Set",
+ "xyz.openbmc_project.Network.IP", "PrefixLength",
+ sdbusplus::message::variant<uint8_t>(newValue));
};
- crow::connections::systemBus->async_method_call(
- std::move(callback), "xyz.openbmc_project.Network",
- "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
- "org.freedesktop.DBus.Properties", "Set",
- "xyz.openbmc_project.Network.IP", "PrefixLength",
- sdbusplus::message::variant<uint8_t>(newValue));
- };
-
- /**
- * @brief Disables VLAN with given ifaceId
- *
- * @param[in] ifaceId Id of VLAN interface that should be disabled
- * @param[in] callback Function that will be called after the operation
- *
- * @return None.
- */
- template <typename CallbackFunc>
- static void disableVlan(const std::string &ifaceId, CallbackFunc &&callback) {
- crow::connections::systemBus->async_method_call(
- callback, "xyz.openbmc_project.Network",
- std::string("/xyz/openbmc_project/network/") + ifaceId,
- "xyz.openbmc_project.Object.Delete", "Delete");
- };
-
- /**
- * @brief Sets given HostName of the machine through D-Bus
- *
- * @param[in] newHostname New name that HostName will be changed to
- * @param[in] callback Function that will be called after the operation
- *
- * @return None.
- */
- template <typename CallbackFunc>
- void setHostName(const std::string &newHostname, CallbackFunc &&callback) {
- crow::connections::systemBus->async_method_call(
- callback, "xyz.openbmc_project.Network",
- "/xyz/openbmc_project/network/config",
- "org.freedesktop.DBus.Properties", "Set",
- "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
- sdbusplus::message::variant<std::string>(newHostname));
- };
-
- /**
- * @brief Deletes given IPv4
- *
- * @param[in] ifaceId Id of interface whose IP should be deleted
- * @param[in] ipIdx index of IP in input array that should be deleted
- * @param[in] ipHash DBus Hash id of IP that should be deleted
- * @param[io] asyncResp Response object that will be returned to client
- *
- * @return None
- */
- void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
- unsigned int ipIdx,
- const std::shared_ptr<AsyncResp> &asyncResp) {
- crow::connections::systemBus->async_method_call(
- [ ipIdx{std::move(ipIdx)}, asyncResp{std::move(asyncResp)} ](
- const boost::system::error_code ec) {
- if (ec) {
- messages::addMessageToJson(
- asyncResp->res.jsonValue, messages::internalError(),
- "/IPv4Addresses/" + std::to_string(ipIdx) + "/");
- } else {
- asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr;
- }
- },
- "xyz.openbmc_project.Network",
- "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
- "xyz.openbmc_project.Object.Delete", "Delete");
- }
-
- /**
- * @brief Creates IPv4 with given data
- *
- * @param[in] ifaceId Id of interface whose IP should be deleted
- * @param[in] ipIdx index of IP in input array that should be deleted
- * @param[in] ipHash DBus Hash id of IP that should be deleted
- * @param[io] asyncResp Response object that will be returned to client
- *
- * @return None
- */
- void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
- uint8_t subnetMask, const std::string &gateway,
- const std::string &address,
- const std::shared_ptr<AsyncResp> &asyncResp) {
- auto createIpHandler = [
- ipIdx{std::move(ipIdx)}, asyncResp{std::move(asyncResp)}
- ](const boost::system::error_code ec) {
- if (ec) {
- messages::addMessageToJson(
- asyncResp->res.jsonValue, messages::internalError(),
- "/IPv4Addresses/" + std::to_string(ipIdx) + "/");
- }
+ /**
+ * @brief Disables VLAN with given ifaceId
+ *
+ * @param[in] ifaceId Id of VLAN interface that should be disabled
+ * @param[in] callback Function that will be called after the operation
+ *
+ * @return None.
+ */
+ template <typename CallbackFunc>
+ static void disableVlan(const std::string &ifaceId, CallbackFunc &&callback)
+ {
+ crow::connections::systemBus->async_method_call(
+ callback, "xyz.openbmc_project.Network",
+ std::string("/xyz/openbmc_project/network/") + ifaceId,
+ "xyz.openbmc_project.Object.Delete", "Delete");
};
- crow::connections::systemBus->async_method_call(
- std::move(createIpHandler), "xyz.openbmc_project.Network",
- "/xyz/openbmc_project/network/" + ifaceId,
- "xyz.openbmc_project.Network.IP.Create", "IP",
- "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
- gateway);
- }
-
- /**
- * @brief Translates Address Origin value from D-Bus to Redfish format and
- * vice-versa
- *
- * @param[in] inputOrigin Input value that should be translated
- * @param[in] isIPv4 True for IPv4 origins, False for IPv6
- * @param[in] isFromDBus True for DBus->Redfish conversion, false for reverse
- *
- * @return Empty string in case of failure, translated value otherwise
- */
- std::string translateAddressOriginBetweenDBusAndRedfish(
- const std::string *inputOrigin, bool isIPv4, bool isFromDBus) {
- // Invalid pointer
- if (inputOrigin == nullptr) {
- return "";
+ /**
+ * @brief Sets given HostName of the machine through D-Bus
+ *
+ * @param[in] newHostname New name that HostName will be changed to
+ * @param[in] callback Function that will be called after the operation
+ *
+ * @return None.
+ */
+ template <typename CallbackFunc>
+ void setHostName(const std::string &newHostname, CallbackFunc &&callback)
+ {
+ crow::connections::systemBus->async_method_call(
+ callback, "xyz.openbmc_project.Network",
+ "/xyz/openbmc_project/network/config",
+ "org.freedesktop.DBus.Properties", "Set",
+ "xyz.openbmc_project.Network.SystemConfiguration", "HostName",
+ sdbusplus::message::variant<std::string>(newHostname));
+ };
+
+ /**
+ * @brief Deletes given IPv4
+ *
+ * @param[in] ifaceId Id of interface whose IP should be deleted
+ * @param[in] ipIdx index of IP in input array that should be deleted
+ * @param[in] ipHash DBus Hash id of IP that should be deleted
+ * @param[io] asyncResp Response object that will be returned to client
+ *
+ * @return None
+ */
+ void deleteIPv4(const std::string &ifaceId, const std::string &ipHash,
+ unsigned int ipIdx,
+ const std::shared_ptr<AsyncResp> &asyncResp)
+ {
+ crow::connections::systemBus->async_method_call(
+ [ipIdx{std::move(ipIdx)}, asyncResp{std::move(asyncResp)}](
+ const boost::system::error_code ec) {
+ if (ec)
+ {
+ messages::addMessageToJson(
+ asyncResp->res.jsonValue, messages::internalError(),
+ "/IPv4Addresses/" + std::to_string(ipIdx) + "/");
+ }
+ else
+ {
+ asyncResp->res.jsonValue["IPv4Addresses"][ipIdx] = nullptr;
+ }
+ },
+ "xyz.openbmc_project.Network",
+ "/xyz/openbmc_project/network/" + ifaceId + "/ipv4/" + ipHash,
+ "xyz.openbmc_project.Object.Delete", "Delete");
}
- static const constexpr unsigned int firstIPv4OnlyIdx = 1;
- static const constexpr unsigned int firstIPv6OnlyIdx = 3;
-
- std::array<std::pair<const char *, const char *>, 6> translationTable{
- {{"xyz.openbmc_project.Network.IP.AddressOrigin.Static", "Static"},
- {"xyz.openbmc_project.Network.IP.AddressOrigin.DHCP", "DHCP"},
- {"xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal",
- "IPv4LinkLocal"},
- {"xyz.openbmc_project.Network.IP.AddressOrigin.DHCP", "DHCPv6"},
- {"xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal",
- "LinkLocal"},
- {"xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC", "SLAAC"}}};
-
- for (unsigned int i = 0; i < translationTable.size(); i++) {
- // Skip unrelated
- if (isIPv4 && i >= firstIPv6OnlyIdx) break;
- if (!isIPv4 && i >= firstIPv4OnlyIdx && i < firstIPv6OnlyIdx) continue;
-
- // When translating D-Bus to Redfish compare input to first element
- if (isFromDBus && translationTable[i].first == *inputOrigin)
- return translationTable[i].second;
-
- // When translating Redfish to D-Bus compare input to second element
- if (!isFromDBus && translationTable[i].second == *inputOrigin)
- return translationTable[i].first;
+ /**
+ * @brief Creates IPv4 with given data
+ *
+ * @param[in] ifaceId Id of interface whose IP should be deleted
+ * @param[in] ipIdx index of IP in input array that should be deleted
+ * @param[in] ipHash DBus Hash id of IP that should be deleted
+ * @param[io] asyncResp Response object that will be returned to client
+ *
+ * @return None
+ */
+ void createIPv4(const std::string &ifaceId, unsigned int ipIdx,
+ uint8_t subnetMask, const std::string &gateway,
+ const std::string &address,
+ const std::shared_ptr<AsyncResp> &asyncResp)
+ {
+ auto createIpHandler = [ipIdx{std::move(ipIdx)},
+ asyncResp{std::move(asyncResp)}](
+ const boost::system::error_code ec) {
+ if (ec)
+ {
+ messages::addMessageToJson(
+ asyncResp->res.jsonValue, messages::internalError(),
+ "/IPv4Addresses/" + std::to_string(ipIdx) + "/");
+ }
+ };
+
+ crow::connections::systemBus->async_method_call(
+ std::move(createIpHandler), "xyz.openbmc_project.Network",
+ "/xyz/openbmc_project/network/" + ifaceId,
+ "xyz.openbmc_project.Network.IP.Create", "IP",
+ "xyz.openbmc_project.Network.IP.Protocol.IPv4", address, subnetMask,
+ gateway);
}
- // If we are still here, that means that value has not been found
- return "";
- }
-
- /**
- * Function that retrieves all properties for given Ethernet Interface
- * Object
- * from EntityManager Network Manager
- * @param ethifaceId a eth interface id to query on DBus
- * @param callback a function that shall be called to convert Dbus output
- * into JSON
- */
- template <typename CallbackFunc>
- void getEthernetIfaceData(const std::string &ethifaceId,
- CallbackFunc &&callback) {
- crow::connections::systemBus->async_method_call(
- [
- this, ethifaceId{std::move(ethifaceId)}, callback{std::move(callback)}
- ](const boost::system::error_code error_code,
- const GetManagedObjectsType &resp) {
- EthernetInterfaceData ethData{};
- std::vector<IPv4AddressData> ipv4Data;
- ipv4Data.reserve(maxIpV4AddressesPerInterface);
-
- if (error_code) {
- // Something wrong on DBus, the error_code is not important at
- // this moment, just return success=false, and empty output. Since
- // size of vector may vary depending on information from Network
- // Manager, and empty output could not be treated same way as
- // error.
- callback(false, ethData, ipv4Data);
- return;
- }
+ /**
+ * @brief Translates Address Origin value from D-Bus to Redfish format and
+ * vice-versa
+ *
+ * @param[in] inputOrigin Input value that should be translated
+ * @param[in] isIPv4 True for IPv4 origins, False for IPv6
+ * @param[in] isFromDBus True for DBus->Redfish conversion, false for
+ * reverse
+ *
+ * @return Empty string in case of failure, translated value otherwise
+ */
+ std::string translateAddressOriginBetweenDBusAndRedfish(
+ const std::string *inputOrigin, bool isIPv4, bool isFromDBus)
+ {
+ // Invalid pointer
+ if (inputOrigin == nullptr)
+ {
+ return "";
+ }
- // Find interface
- if (resp.find("/xyz/openbmc_project/network/" + ethifaceId) ==
- resp.end()) {
- // Interface has not been found
- callback(false, ethData, ipv4Data);
- return;
- }
+ static const constexpr unsigned int firstIPv4OnlyIdx = 1;
+ static const constexpr unsigned int firstIPv6OnlyIdx = 3;
+
+ std::array<std::pair<const char *, const char *>, 6> translationTable{
+ {{"xyz.openbmc_project.Network.IP.AddressOrigin.Static", "Static"},
+ {"xyz.openbmc_project.Network.IP.AddressOrigin.DHCP", "DHCP"},
+ {"xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal",
+ "IPv4LinkLocal"},
+ {"xyz.openbmc_project.Network.IP.AddressOrigin.DHCP", "DHCPv6"},
+ {"xyz.openbmc_project.Network.IP.AddressOrigin.LinkLocal",
+ "LinkLocal"},
+ {"xyz.openbmc_project.Network.IP.AddressOrigin.SLAAC", "SLAAC"}}};
+
+ for (unsigned int i = 0; i < translationTable.size(); i++)
+ {
+ // Skip unrelated
+ if (isIPv4 && i >= firstIPv6OnlyIdx)
+ break;
+ if (!isIPv4 && i >= firstIPv4OnlyIdx && i < firstIPv6OnlyIdx)
+ continue;
+
+ // When translating D-Bus to Redfish compare input to first element
+ if (isFromDBus && translationTable[i].first == *inputOrigin)
+ return translationTable[i].second;
+
+ // When translating Redfish to D-Bus compare input to second element
+ if (!isFromDBus && translationTable[i].second == *inputOrigin)
+ return translationTable[i].first;
+ }
- extractEthernetInterfaceData(ethifaceId, resp, ethData);
- extractIPv4Data(ethifaceId, resp, ipv4Data);
+ // If we are still here, that means that value has not been found
+ return "";
+ }
- // Fix global GW
- for (IPv4AddressData &ipv4 : ipv4Data) {
- if ((ipv4.global) &&
- ((ipv4.gateway == nullptr) || (*ipv4.gateway == "0.0.0.0"))) {
- ipv4.gateway = ethData.defaultGateway;
- }
- }
-
- // Finally make a callback with useful data
- callback(true, ethData, ipv4Data);
- },
- "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
- "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
- };
-
- /**
- * Function that retrieves all Ethernet Interfaces available through Network
- * Manager
- * @param callback a function that shall be called to convert Dbus output into
- * JSON.
- */
- template <typename CallbackFunc>
- void getEthernetIfaceList(CallbackFunc &&callback) {
- crow::connections::systemBus->async_method_call(
- [ this, callback{std::move(callback)} ](
- const boost::system::error_code error_code,
- GetManagedObjectsType &resp) {
- // Callback requires vector<string> to retrieve all available ethernet
- // interfaces
- std::vector<std::string> ifaceList;
- ifaceList.reserve(resp.size());
- if (error_code) {
- // Something wrong on DBus, the error_code is not important at this
- // moment, just return success=false, and empty output. Since size
- // of vector may vary depending on information from Network Manager,
- // and empty output could not be treated same way as error.
- callback(false, ifaceList);
- return;
- }
-
- // Iterate over all retrieved ObjectPaths.
- for (auto &objpath : resp) {
- // And all interfaces available for certain ObjectPath.
- for (auto &interface : objpath.second) {
- // If interface is xyz.openbmc_project.Network.EthernetInterface,
- // this is what we're looking for.
- if (interface.first ==
- "xyz.openbmc_project.Network.EthernetInterface") {
- // Cut out everything until last "/", ...
- const std::string &ifaceId =
- static_cast<const std::string &>(objpath.first);
- std::size_t lastPos = ifaceId.rfind("/");
- if (lastPos != std::string::npos) {
- // and put it into output vector.
- ifaceList.emplace_back(ifaceId.substr(lastPos + 1));
+ /**
+ * Function that retrieves all properties for given Ethernet Interface
+ * Object
+ * from EntityManager Network Manager
+ * @param ethifaceId a eth interface id to query on DBus
+ * @param callback a function that shall be called to convert Dbus output
+ * into JSON
+ */
+ template <typename CallbackFunc>
+ void getEthernetIfaceData(const std::string &ethifaceId,
+ CallbackFunc &&callback)
+ {
+ crow::connections::systemBus->async_method_call(
+ [this, ethifaceId{std::move(ethifaceId)},
+ callback{std::move(callback)}](
+ const boost::system::error_code error_code,
+ const GetManagedObjectsType &resp) {
+ EthernetInterfaceData ethData{};
+ std::vector<IPv4AddressData> ipv4Data;
+ ipv4Data.reserve(maxIpV4AddressesPerInterface);
+
+ if (error_code)
+ {
+ // Something wrong on DBus, the error_code is not important
+ // at this moment, just return success=false, and empty
+ // output. Since size of vector may vary depending on
+ // information from Network Manager, and empty output could
+ // not be treated same way as error.
+ callback(false, ethData, ipv4Data);
+ return;
}
- }
- }
- }
- // Finally make a callback with useful data
- callback(true, ifaceList);
- },
- "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
- "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
- };
+
+ // Find interface
+ if (resp.find("/xyz/openbmc_project/network/" + ethifaceId) ==
+ resp.end())
+ {
+ // Interface has not been found
+ callback(false, ethData, ipv4Data);
+ return;
+ }
+
+ extractEthernetInterfaceData(ethifaceId, resp, ethData);
+ extractIPv4Data(ethifaceId, resp, ipv4Data);
+
+ // Fix global GW
+ for (IPv4AddressData &ipv4 : ipv4Data)
+ {
+ if ((ipv4.global) && ((ipv4.gateway == nullptr) ||
+ (*ipv4.gateway == "0.0.0.0")))
+ {
+ ipv4.gateway = ethData.defaultGateway;
+ }
+ }
+
+ // Finally make a callback with useful data
+ callback(true, ethData, ipv4Data);
+ },
+ "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
+ "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
+ };
+
+ /**
+ * Function that retrieves all Ethernet Interfaces available through Network
+ * Manager
+ * @param callback a function that shall be called to convert Dbus output
+ * into JSON.
+ */
+ template <typename CallbackFunc>
+ void getEthernetIfaceList(CallbackFunc &&callback)
+ {
+ crow::connections::systemBus->async_method_call(
+ [this, callback{std::move(callback)}](
+ const boost::system::error_code error_code,
+ GetManagedObjectsType &resp) {
+ // Callback requires vector<string> to retrieve all available
+ // ethernet interfaces
+ std::vector<std::string> ifaceList;
+ ifaceList.reserve(resp.size());
+ if (error_code)
+ {
+ // Something wrong on DBus, the error_code is not important
+ // at this moment, just return success=false, and empty
+ // output. Since size of vector may vary depending on
+ // information from Network Manager, and empty output could
+ // not be treated same way as error.
+ callback(false, ifaceList);
+ return;
+ }
+
+ // Iterate over all retrieved ObjectPaths.
+ for (auto &objpath : resp)
+ {
+ // And all interfaces available for certain ObjectPath.
+ for (auto &interface : objpath.second)
+ {
+ // If interface is
+ // xyz.openbmc_project.Network.EthernetInterface, this
+ // is what we're looking for.
+ if (interface.first ==
+ "xyz.openbmc_project.Network.EthernetInterface")
+ {
+ // Cut out everything until last "/", ...
+ const std::string &ifaceId =
+ static_cast<const std::string &>(objpath.first);
+ std::size_t lastPos = ifaceId.rfind("/");
+ if (lastPos != std::string::npos)
+ {
+ // and put it into output vector.
+ ifaceList.emplace_back(
+ ifaceId.substr(lastPos + 1));
+ }
+ }
+ }
+ }
+ // Finally make a callback with useful data
+ callback(true, ifaceList);
+ },
+ "xyz.openbmc_project.Network", "/xyz/openbmc_project/network",
+ "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
+ };
};
/**
* EthernetCollection derived class for delivering Ethernet Collection Schema
*/
-class EthernetCollection : public Node {
- public:
- // TODO(Pawel) Remove line from below, where we assume that there is only one
- // manager called openbmc This shall be generic, but requires to update
- // GetSubroutes method
- EthernetCollection(CrowApp &app)
- : Node(app, "/redfish/v1/Managers/openbmc/EthernetInterfaces/") {
- Node::json["@odata.type"] =
- "#EthernetInterfaceCollection.EthernetInterfaceCollection";
- Node::json["@odata.context"] =
- "/redfish/v1/"
- "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
- Node::json["@odata.id"] = "/redfish/v1/Managers/openbmc/EthernetInterfaces";
- Node::json["Name"] = "Ethernet Network Interface Collection";
- Node::json["Description"] =
- "Collection of EthernetInterfaces for this Manager";
-
- entityPrivileges = {
- {boost::beast::http::verb::get, {{"Login"}}},
- {boost::beast::http::verb::head, {{"Login"}}},
- {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
- }
-
- private:
- /**
- * Functions triggers appropriate requests on DBus
- */
- void doGet(crow::Response &res, const crow::Request &req,
- const std::vector<std::string> &params) override {
- // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces for
- // any Manager, not only hardcoded 'openbmc'.
- std::string managerId = "openbmc";
-
- // get eth interface list, and call the below callback for JSON preparation
- ethernetProvider.getEthernetIfaceList([&, managerId{std::move(managerId)} ](
- const bool &success, const std::vector<std::string> &iface_list) {
- if (success) {
- nlohmann::json ifaceArray = nlohmann::json::array();
- for (const std::string &ifaceItem : iface_list) {
- ifaceArray.push_back(
- {{"@odata.id", "/redfish/v1/Managers/" + managerId +
- "/EthernetInterfaces/" + ifaceItem}});
- }
- Node::json["Members"] = ifaceArray;
- Node::json["Members@odata.count"] = ifaceArray.size();
+class EthernetCollection : public Node
+{
+ public:
+ // TODO(Pawel) Remove line from below, where we assume that there is only
+ // one manager called openbmc This shall be generic, but requires to update
+ // GetSubroutes method
+ EthernetCollection(CrowApp &app) :
+ Node(app, "/redfish/v1/Managers/openbmc/EthernetInterfaces/")
+ {
+ Node::json["@odata.type"] =
+ "#EthernetInterfaceCollection.EthernetInterfaceCollection";
+ Node::json["@odata.context"] =
+ "/redfish/v1/"
+ "$metadata#EthernetInterfaceCollection.EthernetInterfaceCollection";
Node::json["@odata.id"] =
- "/redfish/v1/Managers/" + managerId + "/EthernetInterfaces";
- res.jsonValue = Node::json;
- } else {
- // No success, best what we can do is return INTERNALL ERROR
- res.result(boost::beast::http::status::internal_server_error);
- }
- res.end();
- });
- }
-
- // Ethernet Provider object
- // TODO(Pawel) consider move it to singleton
- OnDemandEthernetProvider ethernetProvider;
+ "/redfish/v1/Managers/openbmc/EthernetInterfaces";
+ Node::json["Name"] = "Ethernet Network Interface Collection";
+ Node::json["Description"] =
+ "Collection of EthernetInterfaces for this Manager";
+
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
+ }
+
+ private:
+ /**
+ * Functions triggers appropriate requests on DBus
+ */
+ void doGet(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> &params) override
+ {
+ // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces
+ // for any Manager, not only hardcoded 'openbmc'.
+ std::string managerId = "openbmc";
+
+ // get eth interface list, and call the below callback for JSON
+ // preparation
+ ethernetProvider.getEthernetIfaceList(
+ [&, managerId{std::move(managerId)}](
+ const bool &success,
+ const std::vector<std::string> &iface_list) {
+ if (success)
+ {
+ nlohmann::json ifaceArray = nlohmann::json::array();
+ for (const std::string &ifaceItem : iface_list)
+ {
+ ifaceArray.push_back(
+ {{"@odata.id", "/redfish/v1/Managers/" + managerId +
+ "/EthernetInterfaces/" +
+ ifaceItem}});
+ }
+ Node::json["Members"] = ifaceArray;
+ Node::json["Members@odata.count"] = ifaceArray.size();
+ Node::json["@odata.id"] = "/redfish/v1/Managers/" +
+ managerId + "/EthernetInterfaces";
+ res.jsonValue = Node::json;
+ }
+ else
+ {
+ // No success, best what we can do is return INTERNALL ERROR
+ res.result(
+ boost::beast::http::status::internal_server_error);
+ }
+ res.end();
+ });
+ }
+
+ // Ethernet Provider object
+ // TODO(Pawel) consider move it to singleton
+ OnDemandEthernetProvider ethernetProvider;
};
/**
* EthernetInterface derived class for delivering Ethernet Schema
*/
-class EthernetInterface : public Node {
- public:
- /*
- * Default Constructor
- */
- // TODO(Pawel) Remove line from below, where we assume that there is only one
- // manager called openbmc This shall be generic, but requires to update
- // GetSubroutes method
- EthernetInterface(CrowApp &app)
- : Node(app, "/redfish/v1/Managers/openbmc/EthernetInterfaces/<str>/",
- std::string()) {
- Node::json["@odata.type"] = "#EthernetInterface.v1_2_0.EthernetInterface";
- Node::json["@odata.context"] =
- "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
- Node::json["Name"] = "Manager Ethernet Interface";
- Node::json["Description"] = "Management Network Interface";
-
- entityPrivileges = {
- {boost::beast::http::verb::get, {{"Login"}}},
- {boost::beast::http::verb::head, {{"Login"}}},
- {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
- }
-
- // TODO(kkowalsk) Find a suitable class/namespace for this
- static void handleVlanPatch(const std::string &ifaceId,
- const nlohmann::json &input,
- const EthernetInterfaceData &eth_data,
- const std::string &pathPrefix,
- const std::shared_ptr<AsyncResp> &asyncResp) {
- if (!input.is_object()) {
- messages::addMessageToJson(
- asyncResp->res.jsonValue,
- messages::propertyValueTypeError(input.dump(), "VLAN"), pathPrefix);
- return;
+class EthernetInterface : public Node
+{
+ public:
+ /*
+ * Default Constructor
+ */
+ // TODO(Pawel) Remove line from below, where we assume that there is only
+ // one manager called openbmc This shall be generic, but requires to update
+ // GetSubroutes method
+ EthernetInterface(CrowApp &app) :
+ Node(app, "/redfish/v1/Managers/openbmc/EthernetInterfaces/<str>/",
+ std::string())
+ {
+ Node::json["@odata.type"] =
+ "#EthernetInterface.v1_2_0.EthernetInterface";
+ Node::json["@odata.context"] =
+ "/redfish/v1/$metadata#EthernetInterface.EthernetInterface";
+ Node::json["Name"] = "Manager Ethernet Interface";
+ Node::json["Description"] = "Management Network Interface";
+
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
}
- const std::string pathStart = (pathPrefix == "/") ? "" : pathPrefix;
- nlohmann::json &paramsJson =
- (pathPrefix == "/")
- ? asyncResp->res.jsonValue
- : asyncResp->res.jsonValue[nlohmann::json_pointer<nlohmann::json>(
- pathPrefix)];
- bool inputVlanEnabled;
- uint64_t inputVlanId;
-
- json_util::Result inputVlanEnabledState = json_util::getBool(
- "VLANEnable", input, inputVlanEnabled,
- static_cast<int>(json_util::MessageSetting::TYPE_ERROR),
- asyncResp->res.jsonValue, std::string(pathStart + "/VLANEnable"));
- json_util::Result inputVlanIdState = json_util::getUnsigned(
- "VLANId", input, inputVlanId,
- static_cast<int>(json_util::MessageSetting::TYPE_ERROR),
- asyncResp->res.jsonValue, std::string(pathStart + "/VLANId"));
- bool inputInvalid = false;
-
- // Do not proceed if fields in VLAN object were of wrong type
- if (inputVlanEnabledState == json_util::Result::WRONG_TYPE ||
- inputVlanIdState == json_util::Result::WRONG_TYPE) {
- return;
- }
+ // TODO(kkowalsk) Find a suitable class/namespace for this
+ static void handleVlanPatch(const std::string &ifaceId,
+ const nlohmann::json &input,
+ const EthernetInterfaceData &eth_data,
+ const std::string &pathPrefix,
+ const std::shared_ptr<AsyncResp> &asyncResp)
+ {
+ if (!input.is_object())
+ {
+ messages::addMessageToJson(
+ asyncResp->res.jsonValue,
+ messages::propertyValueTypeError(input.dump(), "VLAN"),
+ pathPrefix);
+ return;
+ }
- // Verify input
- if (eth_data.vlanId == nullptr) {
- // This interface is not a VLAN. Cannot do anything with it
- // TODO(kkowalsk) Change this message
- messages::addMessageToJson(asyncResp->res.jsonValue,
- messages::propertyMissing("VLANEnable"),
- pathPrefix);
-
- inputInvalid = true;
- } else {
- // Load actual data into field values if they were not provided
- if (inputVlanEnabledState == json_util::Result::NOT_EXIST) {
- inputVlanEnabled = true;
- }
-
- if (inputVlanIdState == json_util::Result::NOT_EXIST) {
- inputVlanId = *eth_data.vlanId;
- }
- }
+ const std::string pathStart = (pathPrefix == "/") ? "" : pathPrefix;
+ nlohmann::json &paramsJson =
+ (pathPrefix == "/")
+ ? asyncResp->res.jsonValue
+ : asyncResp->res
+ .jsonValue[nlohmann::json_pointer<nlohmann::json>(
+ pathPrefix)];
+ bool inputVlanEnabled;
+ uint64_t inputVlanId;
+
+ json_util::Result inputVlanEnabledState = json_util::getBool(
+ "VLANEnable", input, inputVlanEnabled,
+ static_cast<int>(json_util::MessageSetting::TYPE_ERROR),
+ asyncResp->res.jsonValue, std::string(pathStart + "/VLANEnable"));
+ json_util::Result inputVlanIdState = json_util::getUnsigned(
+ "VLANId", input, inputVlanId,
+ static_cast<int>(json_util::MessageSetting::TYPE_ERROR),
+ asyncResp->res.jsonValue, std::string(pathStart + "/VLANId"));
+ bool inputInvalid = false;
+
+ // Do not proceed if fields in VLAN object were of wrong type
+ if (inputVlanEnabledState == json_util::Result::WRONG_TYPE ||
+ inputVlanIdState == json_util::Result::WRONG_TYPE)
+ {
+ return;
+ }
- // Do not proceed if input has not been valid
- if (inputInvalid) {
- return;
- }
+ // Verify input
+ if (eth_data.vlanId == nullptr)
+ {
+ // This interface is not a VLAN. Cannot do anything with it
+ // TODO(kkowalsk) Change this message
+ messages::addMessageToJson(asyncResp->res.jsonValue,
+ messages::propertyMissing("VLANEnable"),
+ pathPrefix);
- // VLAN is configured on the interface
- if (inputVlanEnabled == true && inputVlanId != *eth_data.vlanId) {
- // Change VLAN Id
- paramsJson["VLANId"] = inputVlanId;
- OnDemandEthernetProvider::changeVlanId(
- ifaceId, static_cast<uint32_t>(inputVlanId),
- [&, asyncResp, pathPrefx{std::move(pathPrefix)} ](
- const boost::system::error_code ec) {
- if (ec) {
- messages::addMessageToJson(asyncResp->res.jsonValue,
- messages::internalError(), pathPrefix);
- } else {
- paramsJson["VLANEnable"] = true;
+ inputInvalid = true;
+ }
+ else
+ {
+ // Load actual data into field values if they were not provided
+ if (inputVlanEnabledState == json_util::Result::NOT_EXIST)
+ {
+ inputVlanEnabled = true;
}
- });
- } else if (inputVlanEnabled == false) {
- // Disable VLAN
- OnDemandEthernetProvider::disableVlan(
- ifaceId, [&, asyncResp, pathPrefx{std::move(pathPrefix)} ](
- const boost::system::error_code ec) {
- if (ec) {
- messages::addMessageToJson(asyncResp->res.jsonValue,
- messages::internalError(), pathPrefix);
- } else {
- paramsJson["VLANEnable"] = false;
+
+ if (inputVlanIdState == json_util::Result::NOT_EXIST)
+ {
+ inputVlanId = *eth_data.vlanId;
}
- });
- }
- }
+ }
- private:
- void handleHostnamePatch(const nlohmann::json &input,
- const EthernetInterfaceData &eth_data,
- const std::shared_ptr<AsyncResp> &asyncResp) {
- if (input.is_string()) {
- std::string newHostname = input.get<std::string>();
-
- if (eth_data.hostname == nullptr || newHostname != *eth_data.hostname) {
- // Change hostname
- ethernetProvider.setHostName(
- newHostname,
- [asyncResp, newHostname](const boost::system::error_code ec) {
- if (ec) {
- messages::addMessageToJson(asyncResp->res.jsonValue,
- messages::internalError(),
- "/HostName");
- } else {
- asyncResp->res.jsonValue["HostName"] = newHostname;
- }
- });
- }
- } else {
- messages::addMessageToJson(
- asyncResp->res.jsonValue,
- messages::propertyValueTypeError(input.dump(), "HostName"),
- "/HostName");
- }
- }
-
- void handleIPv4Patch(const std::string &ifaceId, const nlohmann::json &input,
- const std::vector<IPv4AddressData> &ipv4_data,
- const std::shared_ptr<AsyncResp> &asyncResp) {
- if (!input.is_array()) {
- messages::addMessageToJson(
- asyncResp->res.jsonValue,
- messages::propertyValueTypeError(input.dump(), "IPv4Addresses"),
- "/IPv4Addresses");
- return;
- }
+ // Do not proceed if input has not been valid
+ if (inputInvalid)
+ {
+ return;
+ }
- // According to Redfish PATCH definition, size must be at least equal
- if (input.size() < ipv4_data.size()) {
- // TODO(kkowalsk) This should be a message indicating that not enough
- // data has been provided
- messages::addMessageToJson(asyncResp->res.jsonValue,
- messages::internalError(), "/IPv4Addresses");
- return;
+ // VLAN is configured on the interface
+ if (inputVlanEnabled == true && inputVlanId != *eth_data.vlanId)
+ {
+ // Change VLAN Id
+ paramsJson["VLANId"] = inputVlanId;
+ OnDemandEthernetProvider::changeVlanId(
+ ifaceId, static_cast<uint32_t>(inputVlanId),
+ [&, asyncResp, pathPrefx{std::move(pathPrefix)}](
+ const boost::system::error_code ec) {
+ if (ec)
+ {
+ messages::addMessageToJson(asyncResp->res.jsonValue,
+ messages::internalError(),
+ pathPrefix);
+ }
+ else
+ {
+ paramsJson["VLANEnable"] = true;
+ }
+ });
+ }
+ else if (inputVlanEnabled == false)
+ {
+ // Disable VLAN
+ OnDemandEthernetProvider::disableVlan(
+ ifaceId, [&, asyncResp, pathPrefx{std::move(pathPrefix)}](
+ const boost::system::error_code ec) {
+ if (ec)
+ {
+ messages::addMessageToJson(asyncResp->res.jsonValue,
+ messages::internalError(),
+ pathPrefix);
+ }
+ else
+ {
+ paramsJson["VLANEnable"] = false;
+ }
+ });
+ }
}
- json_util::Result addressFieldState;
- json_util::Result subnetMaskFieldState;
- json_util::Result addressOriginFieldState;
- json_util::Result gatewayFieldState;
- const std::string *addressFieldValue;
- const std::string *subnetMaskFieldValue;
- const std::string *addressOriginFieldValue = nullptr;
- const std::string *gatewayFieldValue;
- uint8_t subnetMaskAsPrefixLength;
- std::string addressOriginInDBusFormat;
-
- bool errorDetected = false;
- for (unsigned int entryIdx = 0; entryIdx < input.size(); entryIdx++) {
- // Check that entry is not of some unexpected type
- if (!input[entryIdx].is_object() && !input[entryIdx].is_null()) {
- // Invalid object type
- messages::addMessageToJson(
- asyncResp->res.jsonValue,
- messages::propertyValueTypeError(input[entryIdx].dump(),
- "IPv4Address"),
- "/IPv4Addresses/" + std::to_string(entryIdx));
-
- continue;
- }
-
- // Try to load fields
- addressFieldState = json_util::getString(
- "Address", input[entryIdx], addressFieldValue,
- static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR),
- asyncResp->res.jsonValue,
- "/IPv4Addresses/" + std::to_string(entryIdx) + "/Address");
- subnetMaskFieldState = json_util::getString(
- "SubnetMask", input[entryIdx], subnetMaskFieldValue,
- static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR),
- asyncResp->res.jsonValue,
- "/IPv4Addresses/" + std::to_string(entryIdx) + "/SubnetMask");
- addressOriginFieldState = json_util::getString(
- "AddressOrigin", input[entryIdx], addressOriginFieldValue,
- static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR),
- asyncResp->res.jsonValue,
- "/IPv4Addresses/" + std::to_string(entryIdx) + "/AddressOrigin");
- gatewayFieldState = json_util::getString(
- "Gateway", input[entryIdx], gatewayFieldValue,
- static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR),
- asyncResp->res.jsonValue,
- "/IPv4Addresses/" + std::to_string(entryIdx) + "/Gateway");
-
- if (addressFieldState == json_util::Result::WRONG_TYPE ||
- subnetMaskFieldState == json_util::Result::WRONG_TYPE ||
- addressOriginFieldState == json_util::Result::WRONG_TYPE ||
- gatewayFieldState == json_util::Result::WRONG_TYPE) {
- return;
- }
-
- if (addressFieldState == json_util::Result::SUCCESS &&
- !ethernetProvider.ipv4VerifyIpAndGetBitcount(*addressFieldValue)) {
- errorDetected = true;
- messages::addMessageToJson(
- asyncResp->res.jsonValue,
- messages::propertyValueFormatError(*addressFieldValue, "Address"),
- "/IPv4Addresses/" + std::to_string(entryIdx) + "/Address");
- }
-
- if (subnetMaskFieldState == json_util::Result::SUCCESS &&
- !ethernetProvider.ipv4VerifyIpAndGetBitcount(
- *subnetMaskFieldValue, &subnetMaskAsPrefixLength)) {
- errorDetected = true;
- messages::addMessageToJson(
- asyncResp->res.jsonValue,
- messages::propertyValueFormatError(*subnetMaskFieldValue,
- "SubnetMask"),
- "/IPv4Addresses/" + std::to_string(entryIdx) + "/SubnetMask");
- }
-
- // get Address origin in proper format
- addressOriginInDBusFormat =
- ethernetProvider.translateAddressOriginBetweenDBusAndRedfish(
- addressOriginFieldValue, true, false);
-
- if (addressOriginFieldState == json_util::Result::SUCCESS &&
- addressOriginInDBusFormat.empty()) {
- errorDetected = true;
- messages::addMessageToJson(
- asyncResp->res.jsonValue,
- messages::propertyValueNotInList(*addressOriginFieldValue,
- "AddressOrigin"),
- "/IPv4Addresses/" + std::to_string(entryIdx) + "/AddressOrigin");
- }
-
- if (gatewayFieldState == json_util::Result::SUCCESS &&
- !ethernetProvider.ipv4VerifyIpAndGetBitcount(*gatewayFieldValue)) {
- errorDetected = true;
- messages::addMessageToJson(
- asyncResp->res.jsonValue,
- messages::propertyValueFormatError(*gatewayFieldValue, "Gateway"),
- "/IPv4Addresses/" + std::to_string(entryIdx) + "/Gateway");
- }
-
- // If any error occured do not proceed with current entry, but do not
- // end loop
- if (errorDetected) {
- errorDetected = false;
- continue;
- }
-
- if (entryIdx >= ipv4_data.size()) {
- asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] = input[entryIdx];
-
- // Verify that all field were provided
- if (addressFieldState == json_util::Result::NOT_EXIST) {
- errorDetected = true;
- messages::addMessageToJson(
- asyncResp->res.jsonValue, messages::propertyMissing("Address"),
- "/IPv4Addresses/" + std::to_string(entryIdx) + "/Address");
+ private:
+ void handleHostnamePatch(const nlohmann::json &input,
+ const EthernetInterfaceData &eth_data,
+ const std::shared_ptr<AsyncResp> &asyncResp)
+ {
+ if (input.is_string())
+ {
+ std::string newHostname = input.get<std::string>();
+
+ if (eth_data.hostname == nullptr ||
+ newHostname != *eth_data.hostname)
+ {
+ // Change hostname
+ ethernetProvider.setHostName(
+ newHostname, [asyncResp, newHostname](
+ const boost::system::error_code ec) {
+ if (ec)
+ {
+ messages::addMessageToJson(
+ asyncResp->res.jsonValue,
+ messages::internalError(), "/HostName");
+ }
+ else
+ {
+ asyncResp->res.jsonValue["HostName"] = newHostname;
+ }
+ });
+ }
}
-
- if (subnetMaskFieldState == json_util::Result::NOT_EXIST) {
- errorDetected = true;
- messages::addMessageToJson(
- asyncResp->res.jsonValue, messages::propertyMissing("SubnetMask"),
- "/IPv4Addresses/" + std::to_string(entryIdx) + "/SubnetMask");
+ else
+ {
+ messages::addMessageToJson(
+ asyncResp->res.jsonValue,
+ messages::propertyValueTypeError(input.dump(), "HostName"),
+ "/HostName");
}
+ }
- if (addressOriginFieldState == json_util::Result::NOT_EXIST) {
- errorDetected = true;
- messages::addMessageToJson(
- asyncResp->res.jsonValue,
- messages::propertyMissing("AddressOrigin"),
- "/IPv4Addresses/" + std::to_string(entryIdx) + "/AddressOrigin");
+ void handleIPv4Patch(const std::string &ifaceId,
+ const nlohmann::json &input,
+ const std::vector<IPv4AddressData> &ipv4_data,
+ const std::shared_ptr<AsyncResp> &asyncResp)
+ {
+ if (!input.is_array())
+ {
+ messages::addMessageToJson(
+ asyncResp->res.jsonValue,
+ messages::propertyValueTypeError(input.dump(), "IPv4Addresses"),
+ "/IPv4Addresses");
+ return;
}
- if (gatewayFieldState == json_util::Result::NOT_EXIST) {
- errorDetected = true;
- messages::addMessageToJson(
- asyncResp->res.jsonValue, messages::propertyMissing("Gateway"),
- "/IPv4Addresses/" + std::to_string(entryIdx) + "/Gateway");
+ // According to Redfish PATCH definition, size must be at least equal
+ if (input.size() < ipv4_data.size())
+ {
+ // TODO(kkowalsk) This should be a message indicating that not
+ // enough data has been provided
+ messages::addMessageToJson(asyncResp->res.jsonValue,
+ messages::internalError(),
+ "/IPv4Addresses");
+ return;
}
- // If any error occured do not proceed with current entry, but do not
- // end loop
- if (errorDetected) {
- errorDetected = false;
- continue;
- }
+ json_util::Result addressFieldState;
+ json_util::Result subnetMaskFieldState;
+ json_util::Result addressOriginFieldState;
+ json_util::Result gatewayFieldState;
+ const std::string *addressFieldValue;
+ const std::string *subnetMaskFieldValue;
+ const std::string *addressOriginFieldValue = nullptr;
+ const std::string *gatewayFieldValue;
+ uint8_t subnetMaskAsPrefixLength;
+ std::string addressOriginInDBusFormat;
+
+ bool errorDetected = false;
+ for (unsigned int entryIdx = 0; entryIdx < input.size(); entryIdx++)
+ {
+ // Check that entry is not of some unexpected type
+ if (!input[entryIdx].is_object() && !input[entryIdx].is_null())
+ {
+ // Invalid object type
+ messages::addMessageToJson(
+ asyncResp->res.jsonValue,
+ messages::propertyValueTypeError(input[entryIdx].dump(),
+ "IPv4Address"),
+ "/IPv4Addresses/" + std::to_string(entryIdx));
+
+ continue;
+ }
- // Create IPv4 with provided data
- ethernetProvider.createIPv4(ifaceId, entryIdx, subnetMaskAsPrefixLength,
- *gatewayFieldValue, *addressFieldValue,
- asyncResp);
- } else {
- // Existing object that should be modified/deleted/remain unchanged
- if (input[entryIdx].is_null()) {
- // Object should be deleted
- ethernetProvider.deleteIPv4(ifaceId, ipv4_data[entryIdx].id, entryIdx,
- asyncResp);
- } else if (input[entryIdx].is_object()) {
- if (input[entryIdx].size() == 0) {
- // Object shall remain unchanged
- continue;
- }
-
- // Apply changes
- if (addressFieldState == json_util::Result::SUCCESS &&
- ipv4_data[entryIdx].address != nullptr &&
- *ipv4_data[entryIdx].address != *addressFieldValue) {
- ethernetProvider.changeIPv4AddressProperty(
- ifaceId, entryIdx, ipv4_data[entryIdx].id, "Address",
- *addressFieldValue, asyncResp);
- }
-
- if (subnetMaskFieldState == json_util::Result::SUCCESS &&
- ipv4_data[entryIdx].netmask != *subnetMaskFieldValue) {
- ethernetProvider.changeIPv4SubnetMaskProperty(
- ifaceId, entryIdx, ipv4_data[entryIdx].id,
- *subnetMaskFieldValue, subnetMaskAsPrefixLength, asyncResp);
- }
-
- if (addressOriginFieldState == json_util::Result::SUCCESS &&
- ipv4_data[entryIdx].origin != *addressFieldValue) {
- ethernetProvider.changeIPv4Origin(
- ifaceId, entryIdx, ipv4_data[entryIdx].id,
- *addressOriginFieldValue, addressOriginInDBusFormat, asyncResp);
- }
-
- if (gatewayFieldState == json_util::Result::SUCCESS &&
- ipv4_data[entryIdx].gateway != nullptr &&
- *ipv4_data[entryIdx].gateway != *gatewayFieldValue) {
- ethernetProvider.changeIPv4AddressProperty(
- ifaceId, entryIdx, ipv4_data[entryIdx].id, "Gateway",
- *gatewayFieldValue, asyncResp);
- }
+ // Try to load fields
+ addressFieldState = json_util::getString(
+ "Address", input[entryIdx], addressFieldValue,
+ static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR),
+ asyncResp->res.jsonValue,
+ "/IPv4Addresses/" + std::to_string(entryIdx) + "/Address");
+ subnetMaskFieldState = json_util::getString(
+ "SubnetMask", input[entryIdx], subnetMaskFieldValue,
+ static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR),
+ asyncResp->res.jsonValue,
+ "/IPv4Addresses/" + std::to_string(entryIdx) + "/SubnetMask");
+ addressOriginFieldState = json_util::getString(
+ "AddressOrigin", input[entryIdx], addressOriginFieldValue,
+ static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR),
+ asyncResp->res.jsonValue,
+ "/IPv4Addresses/" + std::to_string(entryIdx) +
+ "/AddressOrigin");
+ gatewayFieldState = json_util::getString(
+ "Gateway", input[entryIdx], gatewayFieldValue,
+ static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR),
+ asyncResp->res.jsonValue,
+ "/IPv4Addresses/" + std::to_string(entryIdx) + "/Gateway");
+
+ if (addressFieldState == json_util::Result::WRONG_TYPE ||
+ subnetMaskFieldState == json_util::Result::WRONG_TYPE ||
+ addressOriginFieldState == json_util::Result::WRONG_TYPE ||
+ gatewayFieldState == json_util::Result::WRONG_TYPE)
+ {
+ return;
+ }
+
+ if (addressFieldState == json_util::Result::SUCCESS &&
+ !ethernetProvider.ipv4VerifyIpAndGetBitcount(
+ *addressFieldValue))
+ {
+ errorDetected = true;
+ messages::addMessageToJson(
+ asyncResp->res.jsonValue,
+ messages::propertyValueFormatError(*addressFieldValue,
+ "Address"),
+ "/IPv4Addresses/" + std::to_string(entryIdx) + "/Address");
+ }
+
+ if (subnetMaskFieldState == json_util::Result::SUCCESS &&
+ !ethernetProvider.ipv4VerifyIpAndGetBitcount(
+ *subnetMaskFieldValue, &subnetMaskAsPrefixLength))
+ {
+ errorDetected = true;
+ messages::addMessageToJson(
+ asyncResp->res.jsonValue,
+ messages::propertyValueFormatError(*subnetMaskFieldValue,
+ "SubnetMask"),
+ "/IPv4Addresses/" + std::to_string(entryIdx) +
+ "/SubnetMask");
+ }
+
+ // get Address origin in proper format
+ addressOriginInDBusFormat =
+ ethernetProvider.translateAddressOriginBetweenDBusAndRedfish(
+ addressOriginFieldValue, true, false);
+
+ if (addressOriginFieldState == json_util::Result::SUCCESS &&
+ addressOriginInDBusFormat.empty())
+ {
+ errorDetected = true;
+ messages::addMessageToJson(
+ asyncResp->res.jsonValue,
+ messages::propertyValueNotInList(*addressOriginFieldValue,
+ "AddressOrigin"),
+ "/IPv4Addresses/" + std::to_string(entryIdx) +
+ "/AddressOrigin");
+ }
+
+ if (gatewayFieldState == json_util::Result::SUCCESS &&
+ !ethernetProvider.ipv4VerifyIpAndGetBitcount(
+ *gatewayFieldValue))
+ {
+ errorDetected = true;
+ messages::addMessageToJson(
+ asyncResp->res.jsonValue,
+ messages::propertyValueFormatError(*gatewayFieldValue,
+ "Gateway"),
+ "/IPv4Addresses/" + std::to_string(entryIdx) + "/Gateway");
+ }
+
+ // If any error occured do not proceed with current entry, but do
+ // not end loop
+ if (errorDetected)
+ {
+ errorDetected = false;
+ continue;
+ }
+
+ if (entryIdx >= ipv4_data.size())
+ {
+ asyncResp->res.jsonValue["IPv4Addresses"][entryIdx] =
+ input[entryIdx];
+
+ // Verify that all field were provided
+ if (addressFieldState == json_util::Result::NOT_EXIST)
+ {
+ errorDetected = true;
+ messages::addMessageToJson(
+ asyncResp->res.jsonValue,
+ messages::propertyMissing("Address"),
+ "/IPv4Addresses/" + std::to_string(entryIdx) +
+ "/Address");
+ }
+
+ if (subnetMaskFieldState == json_util::Result::NOT_EXIST)
+ {
+ errorDetected = true;
+ messages::addMessageToJson(
+ asyncResp->res.jsonValue,
+ messages::propertyMissing("SubnetMask"),
+ "/IPv4Addresses/" + std::to_string(entryIdx) +
+ "/SubnetMask");
+ }
+
+ if (addressOriginFieldState == json_util::Result::NOT_EXIST)
+ {
+ errorDetected = true;
+ messages::addMessageToJson(
+ asyncResp->res.jsonValue,
+ messages::propertyMissing("AddressOrigin"),
+ "/IPv4Addresses/" + std::to_string(entryIdx) +
+ "/AddressOrigin");
+ }
+
+ if (gatewayFieldState == json_util::Result::NOT_EXIST)
+ {
+ errorDetected = true;
+ messages::addMessageToJson(
+ asyncResp->res.jsonValue,
+ messages::propertyMissing("Gateway"),
+ "/IPv4Addresses/" + std::to_string(entryIdx) +
+ "/Gateway");
+ }
+
+ // If any error occured do not proceed with current entry, but
+ // do not end loop
+ if (errorDetected)
+ {
+ errorDetected = false;
+ continue;
+ }
+
+ // Create IPv4 with provided data
+ ethernetProvider.createIPv4(
+ ifaceId, entryIdx, subnetMaskAsPrefixLength,
+ *gatewayFieldValue, *addressFieldValue, asyncResp);
+ }
+ else
+ {
+ // Existing object that should be modified/deleted/remain
+ // unchanged
+ if (input[entryIdx].is_null())
+ {
+ // Object should be deleted
+ ethernetProvider.deleteIPv4(ifaceId, ipv4_data[entryIdx].id,
+ entryIdx, asyncResp);
+ }
+ else if (input[entryIdx].is_object())
+ {
+ if (input[entryIdx].size() == 0)
+ {
+ // Object shall remain unchanged
+ continue;
+ }
+
+ // Apply changes
+ if (addressFieldState == json_util::Result::SUCCESS &&
+ ipv4_data[entryIdx].address != nullptr &&
+ *ipv4_data[entryIdx].address != *addressFieldValue)
+ {
+ ethernetProvider.changeIPv4AddressProperty(
+ ifaceId, entryIdx, ipv4_data[entryIdx].id,
+ "Address", *addressFieldValue, asyncResp);
+ }
+
+ if (subnetMaskFieldState == json_util::Result::SUCCESS &&
+ ipv4_data[entryIdx].netmask != *subnetMaskFieldValue)
+ {
+ ethernetProvider.changeIPv4SubnetMaskProperty(
+ ifaceId, entryIdx, ipv4_data[entryIdx].id,
+ *subnetMaskFieldValue, subnetMaskAsPrefixLength,
+ asyncResp);
+ }
+
+ if (addressOriginFieldState == json_util::Result::SUCCESS &&
+ ipv4_data[entryIdx].origin != *addressFieldValue)
+ {
+ ethernetProvider.changeIPv4Origin(
+ ifaceId, entryIdx, ipv4_data[entryIdx].id,
+ *addressOriginFieldValue, addressOriginInDBusFormat,
+ asyncResp);
+ }
+
+ if (gatewayFieldState == json_util::Result::SUCCESS &&
+ ipv4_data[entryIdx].gateway != nullptr &&
+ *ipv4_data[entryIdx].gateway != *gatewayFieldValue)
+ {
+ ethernetProvider.changeIPv4AddressProperty(
+ ifaceId, entryIdx, ipv4_data[entryIdx].id,
+ "Gateway", *gatewayFieldValue, asyncResp);
+ }
+ }
+ }
}
- }
- }
- }
-
- nlohmann::json parseInterfaceData(
- const std::string &ifaceId, const EthernetInterfaceData &eth_data,
- const std::vector<IPv4AddressData> &ipv4_data) {
- // Copy JSON object to avoid race condition
- nlohmann::json jsonResponse(Node::json);
-
- // Fill out obvious data...
- jsonResponse["Id"] = ifaceId;
- jsonResponse["@odata.id"] =
- "/redfish/v1/Managers/openbmc/EthernetInterfaces/" + ifaceId;
-
- // ... then the one from DBus, regarding eth iface...
- if (eth_data.speed != nullptr) jsonResponse["SpeedMbps"] = *eth_data.speed;
-
- if (eth_data.macAddress != nullptr)
- jsonResponse["MACAddress"] = *eth_data.macAddress;
-
- if (eth_data.hostname != nullptr)
- jsonResponse["HostName"] = *eth_data.hostname;
-
- if (eth_data.vlanId != nullptr) {
- nlohmann::json &vlanObj = jsonResponse["VLAN"];
- vlanObj["VLANEnable"] = true;
- vlanObj["VLANId"] = *eth_data.vlanId;
- } else {
- nlohmann::json &vlanObj = jsonResponse["VLANs"];
- vlanObj["@odata.id"] =
- "/redfish/v1/Managers/openbmc/EthernetInterfaces/" + ifaceId +
- "/VLANs";
}
- // ... at last, check if there are IPv4 data and prepare appropriate
- // collection
- if (ipv4_data.size() > 0) {
- nlohmann::json ipv4Array = nlohmann::json::array();
- for (auto &ipv4Config : ipv4_data) {
- nlohmann::json jsonIpv4;
- if (ipv4Config.address != nullptr) {
- jsonIpv4["Address"] = *ipv4Config.address;
- if (ipv4Config.gateway != nullptr)
- jsonIpv4["Gateway"] = *ipv4Config.gateway;
-
- jsonIpv4["AddressOrigin"] = ipv4Config.origin;
- jsonIpv4["SubnetMask"] = ipv4Config.netmask;
-
- ipv4Array.push_back(std::move(jsonIpv4));
+ nlohmann::json
+ parseInterfaceData(const std::string &ifaceId,
+ const EthernetInterfaceData &eth_data,
+ const std::vector<IPv4AddressData> &ipv4_data)
+ {
+ // Copy JSON object to avoid race condition
+ nlohmann::json jsonResponse(Node::json);
+
+ // Fill out obvious data...
+ jsonResponse["Id"] = ifaceId;
+ jsonResponse["@odata.id"] =
+ "/redfish/v1/Managers/openbmc/EthernetInterfaces/" + ifaceId;
+
+ // ... then the one from DBus, regarding eth iface...
+ if (eth_data.speed != nullptr)
+ jsonResponse["SpeedMbps"] = *eth_data.speed;
+
+ if (eth_data.macAddress != nullptr)
+ jsonResponse["MACAddress"] = *eth_data.macAddress;
+
+ if (eth_data.hostname != nullptr)
+ jsonResponse["HostName"] = *eth_data.hostname;
+
+ if (eth_data.vlanId != nullptr)
+ {
+ nlohmann::json &vlanObj = jsonResponse["VLAN"];
+ vlanObj["VLANEnable"] = true;
+ vlanObj["VLANId"] = *eth_data.vlanId;
+ }
+ else
+ {
+ nlohmann::json &vlanObj = jsonResponse["VLANs"];
+ vlanObj["@odata.id"] =
+ "/redfish/v1/Managers/openbmc/EthernetInterfaces/" + ifaceId +
+ "/VLANs";
}
- }
- jsonResponse["IPv4Addresses"] = std::move(ipv4Array);
- }
- return jsonResponse;
- }
-
- /**
- * Functions triggers appropriate requests on DBus
- */
- void doGet(crow::Response &res, const crow::Request &req,
- const std::vector<std::string> &params) override {
- // TODO(Pawel) this shall be parametrized call (two params) to get
- // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
- // Check if there is required param, truly entering this shall be
- // impossible.
- if (params.size() != 1) {
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
- return;
- }
+ // ... at last, check if there are IPv4 data and prepare appropriate
+ // collection
+ if (ipv4_data.size() > 0)
+ {
+ nlohmann::json ipv4Array = nlohmann::json::array();
+ for (auto &ipv4Config : ipv4_data)
+ {
+ nlohmann::json jsonIpv4;
+ if (ipv4Config.address != nullptr)
+ {
+ jsonIpv4["Address"] = *ipv4Config.address;
+ if (ipv4Config.gateway != nullptr)
+ jsonIpv4["Gateway"] = *ipv4Config.gateway;
+
+ jsonIpv4["AddressOrigin"] = ipv4Config.origin;
+ jsonIpv4["SubnetMask"] = ipv4Config.netmask;
+
+ ipv4Array.push_back(std::move(jsonIpv4));
+ }
+ }
+ jsonResponse["IPv4Addresses"] = std::move(ipv4Array);
+ }
- const std::string &ifaceId = params[0];
-
- // get single eth interface data, and call the below callback for JSON
- // preparation
- ethernetProvider.getEthernetIfaceData(
- ifaceId,
- [&, ifaceId](const bool &success, const EthernetInterfaceData &eth_data,
- const std::vector<IPv4AddressData> &ipv4_data) {
- if (success) {
- res.jsonValue = parseInterfaceData(ifaceId, eth_data, ipv4_data);
- } else {
- // ... otherwise return error
- // TODO(Pawel)consider distinguish between non existing object, and
- // other errors
- messages::addMessageToErrorJson(
- res.jsonValue,
- messages::resourceNotFound("EthernetInterface", ifaceId));
- res.result(boost::beast::http::status::not_found);
- }
- res.end();
- });
- }
-
- void doPatch(crow::Response &res, const crow::Request &req,
- const std::vector<std::string> &params) override {
- // TODO(Pawel) this shall be parametrized call (two params) to get
- // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
- // Check if there is required param, truly entering this shall be
- // impossible.
- if (params.size() != 1) {
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
- return;
+ return jsonResponse;
}
- const std::string &ifaceId = params[0];
-
- nlohmann::json patchReq;
+ /**
+ * Functions triggers appropriate requests on DBus
+ */
+ void doGet(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> &params) override
+ {
+ // TODO(Pawel) this shall be parametrized call (two params) to get
+ // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
+ // Check if there is required param, truly entering this shall be
+ // impossible.
+ if (params.size() != 1)
+ {
+ res.result(boost::beast::http::status::internal_server_error);
+ res.end();
+ return;
+ }
- if (!json_util::processJsonFromRequest(res, req, patchReq)) {
- return;
+ const std::string &ifaceId = params[0];
+
+ // get single eth interface data, and call the below callback for JSON
+ // preparation
+ ethernetProvider.getEthernetIfaceData(
+ ifaceId,
+ [&, ifaceId](const bool &success,
+ const EthernetInterfaceData &eth_data,
+ const std::vector<IPv4AddressData> &ipv4_data) {
+ if (success)
+ {
+ res.jsonValue =
+ parseInterfaceData(ifaceId, eth_data, ipv4_data);
+ }
+ else
+ {
+ // ... otherwise return error
+ // TODO(Pawel)consider distinguish between non existing
+ // object, and other errors
+ messages::addMessageToErrorJson(
+ res.jsonValue, messages::resourceNotFound(
+ "EthernetInterface", ifaceId));
+ res.result(boost::beast::http::status::not_found);
+ }
+ res.end();
+ });
}
- // get single eth interface data, and call the below callback for JSON
- // preparation
- ethernetProvider.getEthernetIfaceData(
- ifaceId, [&, ifaceId, patchReq = std::move(patchReq) ](
- const bool &success, const EthernetInterfaceData &eth_data,
- const std::vector<IPv4AddressData> &ipv4_data) {
- if (!success) {
- // ... otherwise return error
- // TODO(Pawel)consider distinguish between non existing object, and
- // other errors
- messages::addMessageToErrorJson(
- res.jsonValue,
- messages::resourceNotFound("VLAN Network Interface", ifaceId));
- res.result(boost::beast::http::status::not_found);
+ void doPatch(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> &params) override
+ {
+ // TODO(Pawel) this shall be parametrized call (two params) to get
+ // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
+ // Check if there is required param, truly entering this shall be
+ // impossible.
+ if (params.size() != 1)
+ {
+ res.result(boost::beast::http::status::internal_server_error);
res.end();
+ return;
+ }
+
+ const std::string &ifaceId = params[0];
+ nlohmann::json patchReq;
+
+ if (!json_util::processJsonFromRequest(res, req, patchReq))
+ {
return;
- }
-
- res.jsonValue = parseInterfaceData(ifaceId, eth_data, ipv4_data);
-
- std::shared_ptr<AsyncResp> asyncResp =
- std::make_shared<AsyncResp>(res);
-
- for (auto propertyIt = patchReq.begin(); propertyIt != patchReq.end();
- ++propertyIt) {
- if (propertyIt.key() == "VLAN") {
- handleVlanPatch(ifaceId, propertyIt.value(), eth_data, "/VLAN",
- asyncResp);
- } else if (propertyIt.key() == "HostName") {
- handleHostnamePatch(propertyIt.value(), eth_data, asyncResp);
- } else if (propertyIt.key() == "IPv4Addresses") {
- handleIPv4Patch(ifaceId, propertyIt.value(), ipv4_data,
- asyncResp);
- } else if (propertyIt.key() == "IPv6Addresses") {
- // TODO(kkowalsk) IPv6 Not supported on D-Bus yet
- messages::addMessageToJsonRoot(
- res.jsonValue,
- messages::propertyNotWritable(propertyIt.key()));
- } else {
- auto fieldInJsonIt = res.jsonValue.find(propertyIt.key());
-
- if (fieldInJsonIt == res.jsonValue.end()) {
- // Field not in scope of defined fields
- messages::addMessageToJsonRoot(
- res.jsonValue, messages::propertyUnknown(propertyIt.key()));
- } else if (*fieldInJsonIt != *propertyIt) {
- // User attempted to modify non-writable field
- messages::addMessageToJsonRoot(
- res.jsonValue,
- messages::propertyNotWritable(propertyIt.key()));
- }
- }
- }
- });
- }
+ }
+
+ // get single eth interface data, and call the below callback for JSON
+ // preparation
+ ethernetProvider.getEthernetIfaceData(
+ ifaceId,
+ [&, ifaceId, patchReq = std::move(patchReq)](
+ const bool &success, const EthernetInterfaceData &eth_data,
+ const std::vector<IPv4AddressData> &ipv4_data) {
+ if (!success)
+ {
+ // ... otherwise return error
+ // TODO(Pawel)consider distinguish between non existing
+ // object, and other errors
+ messages::addMessageToErrorJson(
+ res.jsonValue, messages::resourceNotFound(
+ "VLAN Network Interface", ifaceId));
+ res.result(boost::beast::http::status::not_found);
+ res.end();
+
+ return;
+ }
+
+ res.jsonValue =
+ parseInterfaceData(ifaceId, eth_data, ipv4_data);
+
+ std::shared_ptr<AsyncResp> asyncResp =
+ std::make_shared<AsyncResp>(res);
+
+ for (auto propertyIt = patchReq.begin();
+ propertyIt != patchReq.end(); ++propertyIt)
+ {
+ if (propertyIt.key() == "VLAN")
+ {
+ handleVlanPatch(ifaceId, propertyIt.value(), eth_data,
+ "/VLAN", asyncResp);
+ }
+ else if (propertyIt.key() == "HostName")
+ {
+ handleHostnamePatch(propertyIt.value(), eth_data,
+ asyncResp);
+ }
+ else if (propertyIt.key() == "IPv4Addresses")
+ {
+ handleIPv4Patch(ifaceId, propertyIt.value(), ipv4_data,
+ asyncResp);
+ }
+ else if (propertyIt.key() == "IPv6Addresses")
+ {
+ // TODO(kkowalsk) IPv6 Not supported on D-Bus yet
+ messages::addMessageToJsonRoot(
+ res.jsonValue,
+ messages::propertyNotWritable(propertyIt.key()));
+ }
+ else
+ {
+ auto fieldInJsonIt =
+ res.jsonValue.find(propertyIt.key());
+
+ if (fieldInJsonIt == res.jsonValue.end())
+ {
+ // Field not in scope of defined fields
+ messages::addMessageToJsonRoot(
+ res.jsonValue,
+ messages::propertyUnknown(propertyIt.key()));
+ }
+ else if (*fieldInJsonIt != *propertyIt)
+ {
+ // User attempted to modify non-writable field
+ messages::addMessageToJsonRoot(
+ res.jsonValue, messages::propertyNotWritable(
+ propertyIt.key()));
+ }
+ }
+ }
+ });
+ }
- // Ethernet Provider object
- // TODO(Pawel) consider move it to singleton
- OnDemandEthernetProvider ethernetProvider;
+ // Ethernet Provider object
+ // TODO(Pawel) consider move it to singleton
+ OnDemandEthernetProvider ethernetProvider;
};
class VlanNetworkInterfaceCollection;
@@ -1350,422 +1585,499 @@ class VlanNetworkInterfaceCollection;
/**
* VlanNetworkInterface derived class for delivering VLANNetworkInterface Schema
*/
-class VlanNetworkInterface : public Node {
- public:
- /*
- * Default Constructor
- */
- template <typename CrowApp>
- // TODO(Pawel) Remove line from below, where we assume that there is only one
- // manager called openbmc This shall be generic, but requires to update
- // GetSubroutes method
- VlanNetworkInterface(CrowApp &app)
- : Node(
+class VlanNetworkInterface : public Node
+{
+ public:
+ /*
+ * Default Constructor
+ */
+ template <typename CrowApp>
+ // TODO(Pawel) Remove line from below, where we assume that there is only
+ // one manager called openbmc This shall be generic, but requires to update
+ // GetSubroutes method
+ VlanNetworkInterface(CrowApp &app) :
+ Node(
app,
"/redfish/v1/Managers/openbmc/EthernetInterfaces/<str>/VLANs/<str>",
- std::string(), std::string()) {
- Node::json["@odata.type"] =
- "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
- Node::json["@odata.context"] =
- "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
- Node::json["Name"] = "VLAN Network Interface";
-
- entityPrivileges = {
- {boost::beast::http::verb::get, {{"Login"}}},
- {boost::beast::http::verb::head, {{"Login"}}},
- {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
- }
-
- private:
- nlohmann::json parseInterfaceData(
- const std::string &parent_ifaceId, const std::string &ifaceId,
- const EthernetInterfaceData &eth_data,
- const std::vector<IPv4AddressData> &ipv4_data) {
- // Copy JSON object to avoid race condition
- nlohmann::json jsonResponse(Node::json);
-
- // Fill out obvious data...
- jsonResponse["Id"] = ifaceId;
- jsonResponse["@odata.id"] =
- "/redfish/v1/Managers/openbmc/EthernetInterfaces/" + parent_ifaceId +
- "/VLANs/" + ifaceId;
-
- jsonResponse["VLANEnable"] = true;
- jsonResponse["VLANId"] = *eth_data.vlanId;
-
- return jsonResponse;
- }
-
- bool verifyNames(crow::Response &res, const std::string &parent,
- const std::string &iface) {
- if (!boost::starts_with(iface, parent + "_")) {
- messages::addMessageToErrorJson(
- res.jsonValue,
- messages::resourceNotFound("VLAN Network Interface", iface));
- res.result(boost::beast::http::status::not_found);
- res.end();
-
- return false;
- } else {
- return true;
- }
- }
-
- /**
- * Functions triggers appropriate requests on DBus
- */
- void doGet(crow::Response &res, const crow::Request &req,
- const std::vector<std::string> &params) override {
- // TODO(Pawel) this shall be parametrized call (two params) to get
- // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
- // Check if there is required param, truly entering this shall be
- // impossible.
- if (params.size() != 2) {
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
- return;
+ std::string(), std::string())
+ {
+ Node::json["@odata.type"] =
+ "#VLanNetworkInterface.v1_1_0.VLanNetworkInterface";
+ Node::json["@odata.context"] =
+ "/redfish/v1/$metadata#VLanNetworkInterface.VLanNetworkInterface";
+ Node::json["Name"] = "VLAN Network Interface";
+
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
}
- const std::string &parentIfaceId = params[0];
- const std::string &ifaceId = params[1];
+ private:
+ nlohmann::json
+ parseInterfaceData(const std::string &parent_ifaceId,
+ const std::string &ifaceId,
+ const EthernetInterfaceData &eth_data,
+ const std::vector<IPv4AddressData> &ipv4_data)
+ {
+ // Copy JSON object to avoid race condition
+ nlohmann::json jsonResponse(Node::json);
+
+ // Fill out obvious data...
+ jsonResponse["Id"] = ifaceId;
+ jsonResponse["@odata.id"] =
+ "/redfish/v1/Managers/openbmc/EthernetInterfaces/" +
+ parent_ifaceId + "/VLANs/" + ifaceId;
- if (!verifyNames(res, parentIfaceId, ifaceId)) {
- return;
+ jsonResponse["VLANEnable"] = true;
+ jsonResponse["VLANId"] = *eth_data.vlanId;
+
+ return jsonResponse;
}
- // Get single eth interface data, and call the below callback for JSON
- // preparation
- ethernetProvider.getEthernetIfaceData(
- ifaceId, [&, parentIfaceId, ifaceId](
- const bool &success, const EthernetInterfaceData &eth_data,
- const std::vector<IPv4AddressData> &ipv4_data) {
- if (success && eth_data.vlanId != nullptr) {
- res.jsonValue =
- parseInterfaceData(parentIfaceId, ifaceId, eth_data, ipv4_data);
- } else {
- // ... otherwise return error
- // TODO(Pawel)consider distinguish between non existing object, and
- // other errors
+ bool verifyNames(crow::Response &res, const std::string &parent,
+ const std::string &iface)
+ {
+ if (!boost::starts_with(iface, parent + "_"))
+ {
messages::addMessageToErrorJson(
res.jsonValue,
- messages::resourceNotFound("VLAN Network Interface", ifaceId));
+ messages::resourceNotFound("VLAN Network Interface", iface));
res.result(boost::beast::http::status::not_found);
- }
- res.end();
- });
- }
-
- void doPatch(crow::Response &res, const crow::Request &req,
- const std::vector<std::string> &params) override {
- if (params.size() != 2) {
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
- return;
+ res.end();
+
+ return false;
+ }
+ else
+ {
+ return true;
+ }
}
- const std::string &parentIfaceId = params[0];
- const std::string &ifaceId = params[1];
+ /**
+ * Functions triggers appropriate requests on DBus
+ */
+ void doGet(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> &params) override
+ {
+ // TODO(Pawel) this shall be parametrized call (two params) to get
+ // EthernetInterfaces for any Manager, not only hardcoded 'openbmc'.
+ // Check if there is required param, truly entering this shall be
+ // impossible.
+ if (params.size() != 2)
+ {
+ res.result(boost::beast::http::status::internal_server_error);
+ res.end();
+ return;
+ }
- if (!verifyNames(res, parentIfaceId, ifaceId)) {
- return;
- }
+ const std::string &parentIfaceId = params[0];
+ const std::string &ifaceId = params[1];
- nlohmann::json patchReq;
+ if (!verifyNames(res, parentIfaceId, ifaceId))
+ {
+ return;
+ }
- if (!json_util::processJsonFromRequest(res, req, patchReq)) {
- return;
+ // Get single eth interface data, and call the below callback for JSON
+ // preparation
+ ethernetProvider.getEthernetIfaceData(
+ ifaceId, [&, parentIfaceId,
+ ifaceId](const bool &success,
+ const EthernetInterfaceData &eth_data,
+ const std::vector<IPv4AddressData> &ipv4_data) {
+ if (success && eth_data.vlanId != nullptr)
+ {
+ res.jsonValue = parseInterfaceData(parentIfaceId, ifaceId,
+ eth_data, ipv4_data);
+ }
+ else
+ {
+ // ... otherwise return error
+ // TODO(Pawel)consider distinguish between non existing
+ // object, and other errors
+ messages::addMessageToErrorJson(
+ res.jsonValue, messages::resourceNotFound(
+ "VLAN Network Interface", ifaceId));
+ res.result(boost::beast::http::status::not_found);
+ }
+ res.end();
+ });
}
- // Get single eth interface data, and call the below callback for JSON
- // preparation
- ethernetProvider.getEthernetIfaceData(
- ifaceId, [&, parentIfaceId, ifaceId, patchReq = std::move(patchReq) ](
- const bool &success, const EthernetInterfaceData &eth_data,
- const std::vector<IPv4AddressData> &ipv4_data) {
- if (!success) {
- // ... otherwise return error
- // TODO(Pawel)consider distinguish between non existing object,
- // and
- // other errors
- messages::addMessageToErrorJson(
- res.jsonValue,
- messages::resourceNotFound("VLAN Network Interface", ifaceId));
- res.result(boost::beast::http::status::not_found);
+ void doPatch(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> &params) override
+ {
+ if (params.size() != 2)
+ {
+ res.result(boost::beast::http::status::internal_server_error);
res.end();
+ return;
+ }
+ const std::string &parentIfaceId = params[0];
+ const std::string &ifaceId = params[1];
+
+ if (!verifyNames(res, parentIfaceId, ifaceId))
+ {
return;
- }
-
- res.jsonValue =
- parseInterfaceData(parentIfaceId, ifaceId, eth_data, ipv4_data);
-
- std::shared_ptr<AsyncResp> asyncResp =
- std::make_shared<AsyncResp>(res);
-
- for (auto propertyIt = patchReq.begin(); propertyIt != patchReq.end();
- ++propertyIt) {
- if (propertyIt.key() != "VLANEnable" &&
- propertyIt.key() != "VLANId") {
- auto fieldInJsonIt = res.jsonValue.find(propertyIt.key());
-
- if (fieldInJsonIt == res.jsonValue.end()) {
- // Field not in scope of defined fields
- messages::addMessageToJsonRoot(
- res.jsonValue, messages::propertyUnknown(propertyIt.key()));
- } else if (*fieldInJsonIt != *propertyIt) {
- // User attempted to modify non-writable field
- messages::addMessageToJsonRoot(
- res.jsonValue,
- messages::propertyNotWritable(propertyIt.key()));
- }
- }
- }
-
- EthernetInterface::handleVlanPatch(ifaceId, patchReq, eth_data, "/",
- asyncResp);
- });
- }
-
- void doDelete(crow::Response &res, const crow::Request &req,
- const std::vector<std::string> &params) override {
- if (params.size() != 2) {
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
- return;
+ }
+
+ nlohmann::json patchReq;
+
+ if (!json_util::processJsonFromRequest(res, req, patchReq))
+ {
+ return;
+ }
+
+ // Get single eth interface data, and call the below callback for JSON
+ // preparation
+ ethernetProvider.getEthernetIfaceData(
+ ifaceId,
+ [&, parentIfaceId, ifaceId, patchReq = std::move(patchReq)](
+ const bool &success, const EthernetInterfaceData &eth_data,
+ const std::vector<IPv4AddressData> &ipv4_data) {
+ if (!success)
+ {
+ // ... otherwise return error
+ // TODO(Pawel)consider distinguish between non existing
+ // object, and other errors
+ messages::addMessageToErrorJson(
+ res.jsonValue, messages::resourceNotFound(
+ "VLAN Network Interface", ifaceId));
+ res.result(boost::beast::http::status::not_found);
+ res.end();
+
+ return;
+ }
+
+ res.jsonValue = parseInterfaceData(parentIfaceId, ifaceId,
+ eth_data, ipv4_data);
+
+ std::shared_ptr<AsyncResp> asyncResp =
+ std::make_shared<AsyncResp>(res);
+
+ for (auto propertyIt = patchReq.begin();
+ propertyIt != patchReq.end(); ++propertyIt)
+ {
+ if (propertyIt.key() != "VLANEnable" &&
+ propertyIt.key() != "VLANId")
+ {
+ auto fieldInJsonIt =
+ res.jsonValue.find(propertyIt.key());
+
+ if (fieldInJsonIt == res.jsonValue.end())
+ {
+ // Field not in scope of defined fields
+ messages::addMessageToJsonRoot(
+ res.jsonValue,
+ messages::propertyUnknown(propertyIt.key()));
+ }
+ else if (*fieldInJsonIt != *propertyIt)
+ {
+ // User attempted to modify non-writable field
+ messages::addMessageToJsonRoot(
+ res.jsonValue, messages::propertyNotWritable(
+ propertyIt.key()));
+ }
+ }
+ }
+
+ EthernetInterface::handleVlanPatch(ifaceId, patchReq, eth_data,
+ "/", asyncResp);
+ });
}
- const std::string &parentIfaceId = params[0];
- const std::string &ifaceId = params[1];
+ void doDelete(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> &params) override
+ {
+ if (params.size() != 2)
+ {
+ res.result(boost::beast::http::status::internal_server_error);
+ res.end();
+ return;
+ }
+
+ const std::string &parentIfaceId = params[0];
+ const std::string &ifaceId = params[1];
+
+ if (!verifyNames(res, parentIfaceId, ifaceId))
+ {
+ return;
+ }
- if (!verifyNames(res, parentIfaceId, ifaceId)) {
- return;
+ // Get single eth interface data, and call the below callback for JSON
+ // preparation
+ ethernetProvider.getEthernetIfaceData(
+ ifaceId, [&, parentIfaceId,
+ ifaceId](const bool &success,
+ const EthernetInterfaceData &eth_data,
+ const std::vector<IPv4AddressData> &ipv4_data) {
+ if (success && eth_data.vlanId != nullptr)
+ {
+ res.jsonValue = parseInterfaceData(parentIfaceId, ifaceId,
+ eth_data, ipv4_data);
+
+ // Disable VLAN
+ OnDemandEthernetProvider::disableVlan(
+ ifaceId, [&](const boost::system::error_code ec) {
+ if (ec)
+ {
+ res.jsonValue = nlohmann::json::object();
+ messages::addMessageToErrorJson(
+ res.jsonValue, messages::internalError());
+ res.result(boost::beast::http::status::
+ internal_server_error);
+ }
+ res.end();
+ });
+ }
+ else
+ {
+ // ... otherwise return error
+ // TODO(Pawel)consider distinguish between non existing
+ // object, and other errors
+ messages::addMessageToErrorJson(
+ res.jsonValue, messages::resourceNotFound(
+ "VLAN Network Interface", ifaceId));
+ res.result(boost::beast::http::status::not_found);
+ res.end();
+ }
+ });
}
- // Get single eth interface data, and call the below callback for JSON
- // preparation
- ethernetProvider.getEthernetIfaceData(
- ifaceId, [&, parentIfaceId, ifaceId](
- const bool &success, const EthernetInterfaceData &eth_data,
- const std::vector<IPv4AddressData> &ipv4_data) {
- if (success && eth_data.vlanId != nullptr) {
- res.jsonValue =
- parseInterfaceData(parentIfaceId, ifaceId, eth_data, ipv4_data);
+ /**
+ * This allows VlanNetworkInterfaceCollection to reuse this class' doGet
+ * method, to maintain consistency of returned data, as Collection's doPost
+ * should return data for created member which should match member's doGet
+ * result in 100%.
+ */
+ friend VlanNetworkInterfaceCollection;
- // Disable VLAN
- OnDemandEthernetProvider::disableVlan(
- ifaceId, [&](const boost::system::error_code ec) {
- if (ec) {
- res.jsonValue = nlohmann::json::object();
- messages::addMessageToErrorJson(res.jsonValue,
- messages::internalError());
- res.result(
- boost::beast::http::status::internal_server_error);
- }
- res.end();
- });
- } else {
- // ... otherwise return error
- // TODO(Pawel)consider distinguish between non existing object,
- // and
- // other errors
- messages::addMessageToErrorJson(
- res.jsonValue,
- messages::resourceNotFound("VLAN Network Interface", ifaceId));
- res.result(boost::beast::http::status::not_found);
- res.end();
- }
- });
- }
-
- /**
- * This allows VlanNetworkInterfaceCollection to reuse this class' doGet
- * method, to maintain consistency of returned data, as Collection's doPost
- * should return data for created member which should match member's doGet
- * result in 100%.
- */
- friend VlanNetworkInterfaceCollection;
-
- // Ethernet Provider object
- // TODO(Pawel) consider move it to singleton
- OnDemandEthernetProvider ethernetProvider;
+ // Ethernet Provider object
+ // TODO(Pawel) consider move it to singleton
+ OnDemandEthernetProvider ethernetProvider;
};
/**
* VlanNetworkInterfaceCollection derived class for delivering
* VLANNetworkInterface Collection Schema
*/
-class VlanNetworkInterfaceCollection : public Node {
- public:
- template <typename CrowApp>
- // TODO(Pawel) Remove line from below, where we assume that there is only one
- // manager called openbmc This shall be generic, but requires to update
- // GetSubroutes method
- VlanNetworkInterfaceCollection(CrowApp &app)
- : Node(app,
+class VlanNetworkInterfaceCollection : public Node
+{
+ public:
+ template <typename CrowApp>
+ // TODO(Pawel) Remove line from below, where we assume that there is only
+ // one manager called openbmc This shall be generic, but requires to update
+ // GetSubroutes method
+ VlanNetworkInterfaceCollection(CrowApp &app) :
+ Node(app,
"/redfish/v1/Managers/openbmc/EthernetInterfaces/<str>/VLANs/",
std::string()),
- memberVlan(app) {
- Node::json["@odata.type"] =
- "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection";
- Node::json["@odata.context"] =
- "/redfish/v1/$metadata"
- "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection";
- Node::json["Name"] = "VLAN Network Interface Collection";
-
- entityPrivileges = {
- {boost::beast::http::verb::get, {{"Login"}}},
- {boost::beast::http::verb::head, {{"Login"}}},
- {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
- }
-
- private:
- /**
- * Functions triggers appropriate requests on DBus
- */
- void doGet(crow::Response &res, const crow::Request &req,
- const std::vector<std::string> &params) override {
- if (params.size() != 1) {
- // This means there is a problem with the router
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
-
- return;
+ memberVlan(app)
+ {
+ Node::json["@odata.type"] =
+ "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection";
+ Node::json["@odata.context"] =
+ "/redfish/v1/$metadata"
+ "#VLanNetworkInterfaceCollection.VLanNetworkInterfaceCollection";
+ Node::json["Name"] = "VLAN Network Interface Collection";
+
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
}
- // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces for
- // any Manager, not only hardcoded 'openbmc'.
- std::string managerId = "openbmc";
- std::string rootInterfaceName = params[0];
-
- // get eth interface list, and call the below callback for JSON preparation
- ethernetProvider.getEthernetIfaceList([
- &, managerId{std::move(managerId)},
- rootInterfaceName{std::move(rootInterfaceName)}
- ](const bool &success, const std::vector<std::string> &iface_list) {
- if (success) {
- bool rootInterfaceFound = false;
- nlohmann::json ifaceArray = nlohmann::json::array();
-
- for (const std::string &ifaceItem : iface_list) {
- if (ifaceItem == rootInterfaceName) {
- rootInterfaceFound = true;
- } else if (boost::starts_with(ifaceItem, rootInterfaceName + "_")) {
- ifaceArray.push_back(
- {{"@odata.id", "/redfish/v1/Managers/" + managerId +
- "/EthernetInterfaces/" + rootInterfaceName +
- "/VLANs/" + ifaceItem}});
- }
- }
+ private:
+ /**
+ * Functions triggers appropriate requests on DBus
+ */
+ void doGet(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> &params) override
+ {
+ if (params.size() != 1)
+ {
+ // This means there is a problem with the router
+ res.result(boost::beast::http::status::internal_server_error);
+ res.end();
- if (rootInterfaceFound) {
- Node::json["Members"] = ifaceArray;
- Node::json["Members@odata.count"] = ifaceArray.size();
- Node::json["@odata.id"] = "/redfish/v1/Managers/" + managerId +
- "/EthernetInterfaces/" + rootInterfaceName +
- "/VLANs";
- res.jsonValue = Node::json;
- } else {
- messages::addMessageToErrorJson(
- res.jsonValue, messages::resourceNotFound("EthernetInterface",
- rootInterfaceName));
- res.result(boost::beast::http::status::not_found);
- res.end();
+ return;
}
- } else {
- // No success, best what we can do is return INTERNALL ERROR
- res.result(boost::beast::http::status::internal_server_error);
- }
- res.end();
- });
- }
-
- void doPost(crow::Response &res, const crow::Request &req,
- const std::vector<std::string> &params) override {
- if (params.size() != 1) {
- // This means there is a problem with the router
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
- return;
- }
-
- nlohmann::json postReq;
- if (!json_util::processJsonFromRequest(res, req, postReq)) {
- return;
+ // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces
+ // for any Manager, not only hardcoded 'openbmc'.
+ std::string managerId = "openbmc";
+ std::string rootInterfaceName = params[0];
+
+ // get eth interface list, and call the below callback for JSON
+ // preparation
+ ethernetProvider.getEthernetIfaceList(
+ [&, managerId{std::move(managerId)},
+ rootInterfaceName{std::move(rootInterfaceName)}](
+ const bool &success,
+ const std::vector<std::string> &iface_list) {
+ if (success)
+ {
+ bool rootInterfaceFound = false;
+ nlohmann::json ifaceArray = nlohmann::json::array();
+
+ for (const std::string &ifaceItem : iface_list)
+ {
+ if (ifaceItem == rootInterfaceName)
+ {
+ rootInterfaceFound = true;
+ }
+ else if (boost::starts_with(ifaceItem,
+ rootInterfaceName + "_"))
+ {
+ ifaceArray.push_back(
+ {{"@odata.id", "/redfish/v1/Managers/" +
+ managerId +
+ "/EthernetInterfaces/" +
+ rootInterfaceName +
+ "/VLANs/" + ifaceItem}});
+ }
+ }
+
+ if (rootInterfaceFound)
+ {
+ Node::json["Members"] = ifaceArray;
+ Node::json["Members@odata.count"] = ifaceArray.size();
+ Node::json["@odata.id"] = "/redfish/v1/Managers/" +
+ managerId +
+ "/EthernetInterfaces/" +
+ rootInterfaceName + "/VLANs";
+ res.jsonValue = Node::json;
+ }
+ else
+ {
+ messages::addMessageToErrorJson(
+ res.jsonValue,
+ messages::resourceNotFound("EthernetInterface",
+ rootInterfaceName));
+ res.result(boost::beast::http::status::not_found);
+ res.end();
+ }
+ }
+ else
+ {
+ // No success, best what we can do is return INTERNALL ERROR
+ res.result(
+ boost::beast::http::status::internal_server_error);
+ }
+ res.end();
+ });
}
- // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces for
- // any Manager, not only hardcoded 'openbmc'.
- std::string managerId = "openbmc";
- std::string rootInterfaceName = params[0];
- uint64_t vlanId;
- bool errorDetected;
+ void doPost(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> &params) override
+ {
+ if (params.size() != 1)
+ {
+ // This means there is a problem with the router
+ res.result(boost::beast::http::status::internal_server_error);
+ res.end();
+ return;
+ }
- if (json_util::getUnsigned(
- "VLANId", postReq, vlanId,
- static_cast<uint8_t>(json_util::MessageSetting::MISSING) |
- static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR),
- res.jsonValue, "/VLANId") != json_util::Result::SUCCESS) {
- res.end();
- return;
- }
+ nlohmann::json postReq;
- // get eth interface list, and call the below callback for JSON preparation
- ethernetProvider.getEthernetIfaceList([
- &, managerId{std::move(managerId)},
- rootInterfaceName{std::move(rootInterfaceName)}
- ](const bool &success, const std::vector<std::string> &iface_list) {
- if (success) {
- bool rootInterfaceFound = false;
-
- for (const std::string &ifaceItem : iface_list) {
- if (ifaceItem == rootInterfaceName) {
- rootInterfaceFound = true;
- break;
- }
+ if (!json_util::processJsonFromRequest(res, req, postReq))
+ {
+ return;
}
- if (rootInterfaceFound) {
- ethernetProvider.createVlan(
- rootInterfaceName, vlanId,
- [&, vlanId, rootInterfaceName,
- req{std::move(req)} ](const boost::system::error_code ec) {
- if (ec) {
- messages::addMessageToErrorJson(res.jsonValue,
- messages::internalError());
- res.end();
- } else {
- memberVlan.doGet(
- res, req,
- {rootInterfaceName,
- rootInterfaceName + "_" + std::to_string(vlanId)});
- }
- });
- } else {
- messages::addMessageToErrorJson(
- res.jsonValue, messages::resourceNotFound("EthernetInterface",
- rootInterfaceName));
- res.result(boost::beast::http::status::not_found);
- res.end();
+ // TODO(Pawel) this shall be parametrized call to get EthernetInterfaces
+ // for any Manager, not only hardcoded 'openbmc'.
+ std::string managerId = "openbmc";
+ std::string rootInterfaceName = params[0];
+ uint64_t vlanId;
+ bool errorDetected;
+
+ if (json_util::getUnsigned(
+ "VLANId", postReq, vlanId,
+ static_cast<uint8_t>(json_util::MessageSetting::MISSING) |
+ static_cast<uint8_t>(json_util::MessageSetting::TYPE_ERROR),
+ res.jsonValue, "/VLANId") != json_util::Result::SUCCESS)
+ {
+ res.end();
+ return;
}
- } else {
- // No success, best what we can do is return INTERNALL ERROR
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
- }
- });
- }
-
- // Ethernet Provider object
- // TODO(Pawel) consider move it to singleton
- OnDemandEthernetProvider ethernetProvider;
- VlanNetworkInterface memberVlan;
+
+ // get eth interface list, and call the below callback for JSON
+ // preparation
+ ethernetProvider.getEthernetIfaceList(
+ [&, managerId{std::move(managerId)},
+ rootInterfaceName{std::move(rootInterfaceName)}](
+ const bool &success,
+ const std::vector<std::string> &iface_list) {
+ if (success)
+ {
+ bool rootInterfaceFound = false;
+
+ for (const std::string &ifaceItem : iface_list)
+ {
+ if (ifaceItem == rootInterfaceName)
+ {
+ rootInterfaceFound = true;
+ break;
+ }
+ }
+
+ if (rootInterfaceFound)
+ {
+ ethernetProvider.createVlan(
+ rootInterfaceName, vlanId,
+ [&, vlanId, rootInterfaceName, req{std::move(req)}](
+ const boost::system::error_code ec) {
+ if (ec)
+ {
+ messages::addMessageToErrorJson(
+ res.jsonValue,
+ messages::internalError());
+ res.end();
+ }
+ else
+ {
+ memberVlan.doGet(
+ res, req,
+ {rootInterfaceName,
+ rootInterfaceName + "_" +
+ std::to_string(vlanId)});
+ }
+ });
+ }
+ else
+ {
+ messages::addMessageToErrorJson(
+ res.jsonValue,
+ messages::resourceNotFound("EthernetInterface",
+ rootInterfaceName));
+ res.result(boost::beast::http::status::not_found);
+ res.end();
+ }
+ }
+ else
+ {
+ // No success, best what we can do is return INTERNALL ERROR
+ res.result(
+ boost::beast::http::status::internal_server_error);
+ res.end();
+ }
+ });
+ }
+
+ // Ethernet Provider object
+ // TODO(Pawel) consider move it to singleton
+ OnDemandEthernetProvider ethernetProvider;
+ VlanNetworkInterface memberVlan;
};
-} // namespace redfish
+} // namespace redfish
diff --git a/redfish-core/lib/managers.hpp b/redfish-core/lib/managers.hpp
index 7a861b4a3d..86fe567f3a 100644
--- a/redfish-core/lib/managers.hpp
+++ b/redfish-core/lib/managers.hpp
@@ -17,101 +17,111 @@
#include "node.hpp"
-namespace redfish {
+namespace redfish
+{
-class Manager : public Node {
- public:
- Manager(CrowApp& app) : Node(app, "/redfish/v1/Managers/openbmc/") {
- Node::json["@odata.id"] = "/redfish/v1/Managers/openbmc";
- Node::json["@odata.type"] = "#Manager.v1_3_0.Manager";
- Node::json["@odata.context"] = "/redfish/v1/$metadata#Manager.Manager";
- Node::json["Id"] = "openbmc";
- Node::json["Name"] = "OpenBmc Manager";
- Node::json["Description"] = "Baseboard Management Controller";
- Node::json["PowerState"] = "On";
- Node::json["UUID"] =
- app.template getMiddleware<crow::persistent_data::Middleware>()
- .systemUuid;
- Node::json["Model"] = "OpenBmc"; // TODO(ed), get model
- Node::json["FirmwareVersion"] = "1234456789"; // TODO(ed), get fwversion
- Node::json["EthernetInterfaces"] = nlohmann::json(
- {{"@odata.id",
- "/redfish/v1/Managers/openbmc/EthernetInterfaces"}}); // TODO(Pawel),
- // remove this
- // when
- // subroutes
- // will work
- // correctly
+class Manager : public Node
+{
+ public:
+ Manager(CrowApp& app) : Node(app, "/redfish/v1/Managers/openbmc/")
+ {
+ Node::json["@odata.id"] = "/redfish/v1/Managers/openbmc";
+ Node::json["@odata.type"] = "#Manager.v1_3_0.Manager";
+ Node::json["@odata.context"] = "/redfish/v1/$metadata#Manager.Manager";
+ Node::json["Id"] = "openbmc";
+ Node::json["Name"] = "OpenBmc Manager";
+ Node::json["Description"] = "Baseboard Management Controller";
+ Node::json["PowerState"] = "On";
+ Node::json["UUID"] =
+ app.template getMiddleware<crow::persistent_data::Middleware>()
+ .systemUuid;
+ Node::json["Model"] = "OpenBmc"; // TODO(ed), get model
+ Node::json["FirmwareVersion"] = "1234456789"; // TODO(ed), get fwversion
+ Node::json["EthernetInterfaces"] = nlohmann::json(
+ {{"@odata.id", "/redfish/v1/Managers/openbmc/"
+ "EthernetInterfaces"}}); // TODO(Pawel),
+ // remove this
+ // when
+ // subroutes
+ // will work
+ // correctly
- entityPrivileges = {
- {boost::beast::http::verb::get, {{"Login"}}},
- {boost::beast::http::verb::head, {{"Login"}}},
- {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
- {boost::beast::http::verb::put, {{"ConfigureManager"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
- {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
- }
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::put, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
+ }
- private:
- void doGet(crow::Response& res, const crow::Request& req,
- const std::vector<std::string>& params) override {
- Node::json["DateTime"] = getDateTime();
- // Copy over the static data to include the entries added by SubRoute
- res.jsonValue = Node::json;
- res.end();
- }
+ private:
+ void doGet(crow::Response& res, const crow::Request& req,
+ const std::vector<std::string>& params) override
+ {
+ Node::json["DateTime"] = getDateTime();
+ // Copy over the static data to include the entries added by SubRoute
+ res.jsonValue = Node::json;
+ res.end();
+ }
- std::string getDateTime() const {
- std::array<char, 128> dateTime;
- std::string redfishDateTime("0000-00-00T00:00:00Z00:00");
- std::time_t time = std::time(nullptr);
+ std::string getDateTime() const
+ {
+ std::array<char, 128> dateTime;
+ std::string redfishDateTime("0000-00-00T00:00:00Z00:00");
+ std::time_t time = std::time(nullptr);
- if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z",
- std::localtime(&time))) {
- // insert the colon required by the ISO 8601 standard
- redfishDateTime = std::string(dateTime.data());
- redfishDateTime.insert(redfishDateTime.end() - 2, ':');
- }
+ if (std::strftime(dateTime.begin(), dateTime.size(), "%FT%T%z",
+ std::localtime(&time)))
+ {
+ // insert the colon required by the ISO 8601 standard
+ redfishDateTime = std::string(dateTime.data());
+ redfishDateTime.insert(redfishDateTime.end() - 2, ':');
+ }
- return redfishDateTime;
- }
+ return redfishDateTime;
+ }
};
-class ManagerCollection : public Node {
- public:
- ManagerCollection(CrowApp& app) : Node(app, "/redfish/v1/Managers/") {
- Node::json["@odata.id"] = "/redfish/v1/Managers";
- Node::json["@odata.type"] = "#ManagerCollection.ManagerCollection";
- Node::json["@odata.context"] =
- "/redfish/v1/$metadata#ManagerCollection.ManagerCollection";
- Node::json["Name"] = "Manager Collection";
- Node::json["Members@odata.count"] = 1;
- Node::json["Members"] = {{{"@odata.id", "/redfish/v1/Managers/openbmc"}}};
+class ManagerCollection : public Node
+{
+ public:
+ ManagerCollection(CrowApp& app) : Node(app, "/redfish/v1/Managers/")
+ {
+ Node::json["@odata.id"] = "/redfish/v1/Managers";
+ Node::json["@odata.type"] = "#ManagerCollection.ManagerCollection";
+ Node::json["@odata.context"] =
+ "/redfish/v1/$metadata#ManagerCollection.ManagerCollection";
+ Node::json["Name"] = "Manager Collection";
+ Node::json["Members@odata.count"] = 1;
+ Node::json["Members"] = {
+ {{"@odata.id", "/redfish/v1/Managers/openbmc"}}};
- entityPrivileges = {
- {boost::beast::http::verb::get, {{"Login"}}},
- {boost::beast::http::verb::head, {{"Login"}}},
- {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
- {boost::beast::http::verb::put, {{"ConfigureManager"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
- {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
- }
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::put, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
+ }
- private:
- void doGet(crow::Response& res, const crow::Request& req,
- const std::vector<std::string>& params) override {
- // Collections don't include the static data added by SubRoute because it
- // has a duplicate entry for members
- res.jsonValue["@odata.id"] = "/redfish/v1/Managers";
- res.jsonValue["@odata.type"] = "#ManagerCollection.ManagerCollection";
- res.jsonValue["@odata.context"] =
- "/redfish/v1/$metadata#ManagerCollection.ManagerCollection";
- res.jsonValue["Name"] = "Manager Collection";
- res.jsonValue["Members@odata.count"] = 1;
- res.jsonValue["Members"] = {
- {{"@odata.id", "/redfish/v1/Managers/openbmc"}}};
- res.end();
- }
+ private:
+ void doGet(crow::Response& res, const crow::Request& req,
+ const std::vector<std::string>& params) override
+ {
+ // Collections don't include the static data added by SubRoute because
+ // it has a duplicate entry for members
+ res.jsonValue["@odata.id"] = "/redfish/v1/Managers";
+ res.jsonValue["@odata.type"] = "#ManagerCollection.ManagerCollection";
+ res.jsonValue["@odata.context"] =
+ "/redfish/v1/$metadata#ManagerCollection.ManagerCollection";
+ res.jsonValue["Name"] = "Manager Collection";
+ res.jsonValue["Members@odata.count"] = 1;
+ res.jsonValue["Members"] = {
+ {{"@odata.id", "/redfish/v1/Managers/openbmc"}}};
+ res.end();
+ }
};
-} // namespace redfish
+} // namespace redfish
diff --git a/redfish-core/lib/network_protocol.hpp b/redfish-core/lib/network_protocol.hpp
index ae29df05f6..bb021f5297 100644
--- a/redfish-core/lib/network_protocol.hpp
+++ b/redfish-core/lib/network_protocol.hpp
@@ -18,24 +18,27 @@
#include "error_messages.hpp"
#include "node.hpp"
-namespace redfish {
-
-enum NetworkProtocolUnitStructFields {
- NET_PROTO_UNIT_NAME,
- NET_PROTO_UNIT_DESC,
- NET_PROTO_UNIT_LOAD_STATE,
- NET_PROTO_UNIT_ACTIVE_STATE,
- NET_PROTO_UNIT_SUB_STATE,
- NET_PROTO_UNIT_DEVICE,
- NET_PROTO_UNIT_OBJ_PATH,
- NET_PROTO_UNIT_ALWAYS_0,
- NET_PROTO_UNIT_ALWAYS_EMPTY,
- NET_PROTO_UNIT_ALWAYS_ROOT_PATH
+namespace redfish
+{
+
+enum NetworkProtocolUnitStructFields
+{
+ NET_PROTO_UNIT_NAME,
+ NET_PROTO_UNIT_DESC,
+ NET_PROTO_UNIT_LOAD_STATE,
+ NET_PROTO_UNIT_ACTIVE_STATE,
+ NET_PROTO_UNIT_SUB_STATE,
+ NET_PROTO_UNIT_DEVICE,
+ NET_PROTO_UNIT_OBJ_PATH,
+ NET_PROTO_UNIT_ALWAYS_0,
+ NET_PROTO_UNIT_ALWAYS_EMPTY,
+ NET_PROTO_UNIT_ALWAYS_ROOT_PATH
};
-enum NetworkProtocolListenResponseElements {
- NET_PROTO_LISTEN_TYPE,
- NET_PROTO_LISTEN_STREAM
+enum NetworkProtocolListenResponseElements
+{
+ NET_PROTO_LISTEN_TYPE,
+ NET_PROTO_LISTEN_STREAM
};
/**
@@ -46,9 +49,10 @@ using UnitStruct =
std::string, sdbusplus::message::object_path, uint32_t,
std::string, sdbusplus::message::object_path>;
-struct ServiceConfiguration {
- const char* serviceName;
- const char* socketPath;
+struct ServiceConfiguration
+{
+ const char* serviceName;
+ const char* socketPath;
};
const static boost::container::flat_map<const char*, ServiceConfiguration>
@@ -63,128 +67,161 @@ const static boost::container::flat_map<const char*, ServiceConfiguration>
{"phosphor-ipmi-net.service",
"/org/freedesktop/systemd1/unit/phosphor_2dipmi_2dnet_2esocket"}}};
-class NetworkProtocol : public Node {
- public:
- NetworkProtocol(CrowApp& app)
- : Node(app, "/redfish/v1/Managers/openbmc/NetworkProtocol") {
- Node::json["@odata.type"] =
- "#ManagerNetworkProtocol.v1_1_0.ManagerNetworkProtocol";
- Node::json["@odata.id"] = "/redfish/v1/Managers/openbmc/NetworkProtocol";
- Node::json["@odata.context"] =
- "/redfish/v1/$metadata#ManagerNetworkProtocol.ManagerNetworkProtocol";
- Node::json["Id"] = "NetworkProtocol";
- Node::json["Name"] = "Manager Network Protocol";
- Node::json["Description"] = "Manager Network Service";
- Node::json["Status"]["Health"] = "OK";
- Node::json["Status"]["HealthRollup"] = "OK";
- Node::json["Status"]["State"] = "Enabled";
-
- for (auto& protocol : protocolToDBus) {
- Node::json[protocol.first]["ProtocolEnabled"] = false;
+class NetworkProtocol : public Node
+{
+ public:
+ NetworkProtocol(CrowApp& app) :
+ Node(app, "/redfish/v1/Managers/openbmc/NetworkProtocol")
+ {
+ Node::json["@odata.type"] =
+ "#ManagerNetworkProtocol.v1_1_0.ManagerNetworkProtocol";
+ Node::json["@odata.id"] =
+ "/redfish/v1/Managers/openbmc/NetworkProtocol";
+ Node::json["@odata.context"] =
+ "/redfish/v1/"
+ "$metadata#ManagerNetworkProtocol.ManagerNetworkProtocol";
+ Node::json["Id"] = "NetworkProtocol";
+ Node::json["Name"] = "Manager Network Protocol";
+ Node::json["Description"] = "Manager Network Service";
+ Node::json["Status"]["Health"] = "OK";
+ Node::json["Status"]["HealthRollup"] = "OK";
+ Node::json["Status"]["State"] = "Enabled";
+
+ for (auto& protocol : protocolToDBus)
+ {
+ Node::json[protocol.first]["ProtocolEnabled"] = false;
+ }
+
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::put, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
}
- entityPrivileges = {
- {boost::beast::http::verb::get, {{"Login"}}},
- {boost::beast::http::verb::head, {{"Login"}}},
- {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
- {boost::beast::http::verb::put, {{"ConfigureManager"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
- {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
- }
-
- private:
- void doGet(crow::Response& res, const crow::Request& req,
- const std::vector<std::string>& params) override {
- std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
-
- getData(asyncResp);
- }
-
- std::string getHostName() const {
- std::string hostName;
-
- std::array<char, HOST_NAME_MAX> hostNameCStr;
- if (gethostname(hostNameCStr.data(), hostNameCStr.size()) == 0) {
- hostName = hostNameCStr.data();
+ private:
+ void doGet(crow::Response& res, const crow::Request& req,
+ const std::vector<std::string>& params) override
+ {
+ std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
+
+ getData(asyncResp);
}
- return hostName;
- }
-
- void getData(const std::shared_ptr<AsyncResp>& asyncResp) {
- Node::json["HostName"] = getHostName();
- asyncResp->res.jsonValue = Node::json;
-
- crow::connections::systemBus->async_method_call(
- [asyncResp](const boost::system::error_code ec,
- const std::vector<UnitStruct>& resp) {
- if (ec) {
- asyncResp->res.jsonValue = nlohmann::json::object();
- messages::addMessageToErrorJson(asyncResp->res.jsonValue,
- messages::internalError());
- asyncResp->res.result(
- boost::beast::http::status::internal_server_error);
- return;
- }
-
- for (auto& unit : resp) {
- for (auto& kv : protocolToDBus) {
- if (kv.second.serviceName ==
- std::get<NET_PROTO_UNIT_NAME>(unit)) {
- continue;
- }
- const char* service = kv.first;
- const char* socketPath = kv.second.socketPath;
-
- asyncResp->res.jsonValue[service]["ProtocolEnabled"] =
- std::get<NET_PROTO_UNIT_SUB_STATE>(unit) == "running";
-
- crow::connections::systemBus->async_method_call(
- [ asyncResp, service{std::string(service)}, socketPath ](
- const boost::system::error_code ec,
- const sdbusplus::message::variant<std::vector<
- std::tuple<std::string, std::string>>>& resp) {
- if (ec) {
- messages::addMessageToJson(asyncResp->res.jsonValue,
- messages::internalError(),
- "/" + service);
- return;
- }
- const std::vector<std::tuple<std::string, std::string>>*
- responsePtr = mapbox::getPtr<const std::vector<
- std::tuple<std::string, std::string>>>(resp);
- if (responsePtr == nullptr || responsePtr->size() < 1) {
- return;
- }
- const std::string& listenStream =
- std::get<NET_PROTO_LISTEN_STREAM>((*responsePtr)[0]);
- std::size_t lastColonPos = listenStream.rfind(":");
- if (lastColonPos == std::string::npos) {
- // Not a port
- return;
- }
- std::string portStr = listenStream.substr(lastColonPos + 1);
- char* endPtr = nullptr;
- // Use strtol instead of stroi to avoid exceptions
- long port = std::strtol(portStr.c_str(), &endPtr, 10);
-
- if (*endPtr != '\0' || portStr.empty()) {
- // Invalid value
- asyncResp->res.jsonValue[service]["Port"] = nullptr;
- } else {
- // Everything OK
- asyncResp->res.jsonValue[service]["Port"] = port;
+ std::string getHostName() const
+ {
+ std::string hostName;
+
+ std::array<char, HOST_NAME_MAX> hostNameCStr;
+ if (gethostname(hostNameCStr.data(), hostNameCStr.size()) == 0)
+ {
+ hostName = hostNameCStr.data();
+ }
+ return hostName;
+ }
+
+ void getData(const std::shared_ptr<AsyncResp>& asyncResp)
+ {
+ Node::json["HostName"] = getHostName();
+ asyncResp->res.jsonValue = Node::json;
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](const boost::system::error_code ec,
+ const std::vector<UnitStruct>& resp) {
+ if (ec)
+ {
+ asyncResp->res.jsonValue = nlohmann::json::object();
+ messages::addMessageToErrorJson(asyncResp->res.jsonValue,
+ messages::internalError());
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
+ return;
+ }
+
+ for (auto& unit : resp)
+ {
+ for (auto& kv : protocolToDBus)
+ {
+ if (kv.second.serviceName ==
+ std::get<NET_PROTO_UNIT_NAME>(unit))
+ {
+ continue;
+ }
+ const char* service = kv.first;
+ const char* socketPath = kv.second.socketPath;
+
+ asyncResp->res.jsonValue[service]["ProtocolEnabled"] =
+ std::get<NET_PROTO_UNIT_SUB_STATE>(unit) ==
+ "running";
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, service{std::string(service)},
+ socketPath](
+ const boost::system::error_code ec,
+ const sdbusplus::message::variant<std::vector<
+ std::tuple<std::string, std::string>>>&
+ resp) {
+ if (ec)
+ {
+ messages::addMessageToJson(
+ asyncResp->res.jsonValue,
+ messages::internalError(),
+ "/" + service);
+ return;
+ }
+ const std::vector<std::tuple<
+ std::string, std::string>>* responsePtr =
+ mapbox::getPtr<const std::vector<
+ std::tuple<std::string, std::string>>>(
+ resp);
+ if (responsePtr == nullptr ||
+ responsePtr->size() < 1)
+ {
+ return;
+ }
+
+ const std::string& listenStream =
+ std::get<NET_PROTO_LISTEN_STREAM>(
+ (*responsePtr)[0]);
+ std::size_t lastColonPos =
+ listenStream.rfind(":");
+ if (lastColonPos == std::string::npos)
+ {
+ // Not a port
+ return;
+ }
+ std::string portStr =
+ listenStream.substr(lastColonPos + 1);
+ char* endPtr = nullptr;
+ // Use strtol instead of stroi to avoid
+ // exceptions
+ long port =
+ std::strtol(portStr.c_str(), &endPtr, 10);
+
+ if (*endPtr != '\0' || portStr.empty())
+ {
+ // Invalid value
+ asyncResp->res.jsonValue[service]["Port"] =
+ nullptr;
+ }
+ else
+ {
+ // Everything OK
+ asyncResp->res.jsonValue[service]["Port"] =
+ port;
+ }
+ },
+ "org.freedesktop.systemd1", socketPath,
+ "org.freedesktop.DBus.Properties", "Get",
+ "org.freedesktop.systemd1.Socket", "Listen");
}
- },
- "org.freedesktop.systemd1", socketPath,
- "org.freedesktop.DBus.Properties", "Get",
- "org.freedesktop.systemd1.Socket", "Listen");
- }
- }
- },
- "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
- "org.freedesktop.systemd1.Manager", "ListUnits");
- }
+ }
+ },
+ "org.freedesktop.systemd1", "/org/freedesktop/systemd1",
+ "org.freedesktop.systemd1.Manager", "ListUnits");
+ }
};
-} // namespace redfish
+} // namespace redfish
diff --git a/redfish-core/lib/redfish_sessions.hpp b/redfish-core/lib/redfish_sessions.hpp
index ca1c3757da..2406250fa3 100644
--- a/redfish-core/lib/redfish_sessions.hpp
+++ b/redfish-core/lib/redfish_sessions.hpp
@@ -19,312 +19,348 @@
#include "node.hpp"
#include "persistent_data_middleware.hpp"
-namespace redfish {
+namespace redfish
+{
class SessionCollection;
-class Sessions : public Node {
- public:
- Sessions(CrowApp& app)
- : Node(app, "/redfish/v1/SessionService/Sessions/<str>/", std::string()) {
- Node::json["@odata.type"] = "#Session.v1_0_2.Session";
- Node::json["@odata.context"] = "/redfish/v1/$metadata#Session.Session";
- Node::json["Name"] = "User Session";
- Node::json["Description"] = "Manager User Session";
-
- entityPrivileges = {
- {boost::beast::http::verb::get, {{"Login"}}},
- {boost::beast::http::verb::head, {{"Login"}}},
- {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
- {boost::beast::http::verb::put, {{"ConfigureManager"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
- {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
- }
-
- private:
- void doGet(crow::Response& res, const crow::Request& req,
- const std::vector<std::string>& params) override {
- auto session =
- crow::persistent_data::SessionStore::getInstance().getSessionByUid(
- params[0]);
-
- if (session == nullptr) {
- messages::addMessageToErrorJson(
- res.jsonValue, messages::resourceNotFound("Session", params[0]));
-
- res.result(boost::beast::http::status::not_found);
- res.end();
- return;
+class Sessions : public Node
+{
+ public:
+ Sessions(CrowApp& app) :
+ Node(app, "/redfish/v1/SessionService/Sessions/<str>/", std::string())
+ {
+ Node::json["@odata.type"] = "#Session.v1_0_2.Session";
+ Node::json["@odata.context"] = "/redfish/v1/$metadata#Session.Session";
+ Node::json["Name"] = "User Session";
+ Node::json["Description"] = "Manager User Session";
+
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::put, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
}
- Node::json["Id"] = session->uniqueId;
- Node::json["UserName"] = session->username;
- Node::json["@odata.id"] =
- "/redfish/v1/SessionService/Sessions/" + session->uniqueId;
-
- res.jsonValue = Node::json;
- res.end();
- }
-
- void doDelete(crow::Response& res, const crow::Request& req,
- const std::vector<std::string>& params) override {
- // Need only 1 param which should be id of session to be deleted
- if (params.size() != 1) {
- // This should be handled by crow and never happen
- BMCWEB_LOG_ERROR
- << "Session DELETE has been called with invalid number of params";
-
- res.result(boost::beast::http::status::bad_request);
- messages::addMessageToErrorJson(res.jsonValue, messages::generalError());
-
- res.end();
- return;
+ private:
+ void doGet(crow::Response& res, const crow::Request& req,
+ const std::vector<std::string>& params) override
+ {
+ auto session =
+ crow::persistent_data::SessionStore::getInstance().getSessionByUid(
+ params[0]);
+
+ if (session == nullptr)
+ {
+ messages::addMessageToErrorJson(
+ res.jsonValue,
+ messages::resourceNotFound("Session", params[0]));
+
+ res.result(boost::beast::http::status::not_found);
+ res.end();
+ return;
+ }
+
+ Node::json["Id"] = session->uniqueId;
+ Node::json["UserName"] = session->username;
+ Node::json["@odata.id"] =
+ "/redfish/v1/SessionService/Sessions/" + session->uniqueId;
+
+ res.jsonValue = Node::json;
+ res.end();
}
- auto session =
- crow::persistent_data::SessionStore::getInstance().getSessionByUid(
- params[0]);
-
- if (session == nullptr) {
- messages::addMessageToErrorJson(
- res.jsonValue, messages::resourceNotFound("Session", params[0]));
-
- res.result(boost::beast::http::status::not_found);
- res.end();
- return;
+ void doDelete(crow::Response& res, const crow::Request& req,
+ const std::vector<std::string>& params) override
+ {
+ // Need only 1 param which should be id of session to be deleted
+ if (params.size() != 1)
+ {
+ // This should be handled by crow and never happen
+ BMCWEB_LOG_ERROR << "Session DELETE has been called with invalid "
+ "number of params";
+
+ res.result(boost::beast::http::status::bad_request);
+ messages::addMessageToErrorJson(res.jsonValue,
+ messages::generalError());
+
+ res.end();
+ return;
+ }
+
+ auto session =
+ crow::persistent_data::SessionStore::getInstance().getSessionByUid(
+ params[0]);
+
+ if (session == nullptr)
+ {
+ messages::addMessageToErrorJson(
+ res.jsonValue,
+ messages::resourceNotFound("Session", params[0]));
+
+ res.result(boost::beast::http::status::not_found);
+ res.end();
+ return;
+ }
+
+ // DELETE should return representation of object that will be removed
+ doGet(res, req, params);
+
+ crow::persistent_data::SessionStore::getInstance().removeSession(
+ session);
}
- // DELETE should return representation of object that will be removed
- doGet(res, req, params);
-
- crow::persistent_data::SessionStore::getInstance().removeSession(session);
- }
-
- /**
- * This allows SessionCollection to reuse this class' doGet method, to
- * maintain consistency of returned data, as Collection's doPost should return
- * data for created member which should match member's doGet result in 100%
- */
- friend SessionCollection;
+ /**
+ * This allows SessionCollection to reuse this class' doGet method, to
+ * maintain consistency of returned data, as Collection's doPost should
+ * return data for created member which should match member's doGet result
+ * in 100%
+ */
+ friend SessionCollection;
};
-class SessionCollection : public Node {
- public:
- SessionCollection(CrowApp& app)
- : Node(app, "/redfish/v1/SessionService/Sessions/"), memberSession(app) {
- Node::json["@odata.type"] = "#SessionCollection.SessionCollection";
- Node::json["@odata.id"] = "/redfish/v1/SessionService/Sessions/";
- Node::json["@odata.context"] =
- "/redfish/v1/$metadata#SessionCollection.SessionCollection";
- Node::json["Name"] = "Session Collection";
- Node::json["Description"] = "Session Collection";
- Node::json["Members@odata.count"] = 0;
- Node::json["Members"] = nlohmann::json::array();
-
- entityPrivileges = {
- {boost::beast::http::verb::get, {{"Login"}}},
- {boost::beast::http::verb::head, {{"Login"}}},
- {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
- {boost::beast::http::verb::put, {{"ConfigureManager"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
- {boost::beast::http::verb::post, {}}};
- }
-
- private:
- void doGet(crow::Response& res, const crow::Request& req,
- const std::vector<std::string>& params) override {
- std::vector<const std::string*> sessionIds =
- crow::persistent_data::SessionStore::getInstance().getUniqueIds(
- false, crow::persistent_data::PersistenceType::TIMEOUT);
-
- Node::json["Members@odata.count"] = sessionIds.size();
- Node::json["Members"] = nlohmann::json::array();
- for (const std::string* uid : sessionIds) {
- Node::json["Members"].push_back(
- {{"@odata.id", "/redfish/v1/SessionService/Sessions/" + *uid}});
+class SessionCollection : public Node
+{
+ public:
+ SessionCollection(CrowApp& app) :
+ Node(app, "/redfish/v1/SessionService/Sessions/"), memberSession(app)
+ {
+ Node::json["@odata.type"] = "#SessionCollection.SessionCollection";
+ Node::json["@odata.id"] = "/redfish/v1/SessionService/Sessions/";
+ Node::json["@odata.context"] =
+ "/redfish/v1/$metadata#SessionCollection.SessionCollection";
+ Node::json["Name"] = "Session Collection";
+ Node::json["Description"] = "Session Collection";
+ Node::json["Members@odata.count"] = 0;
+ Node::json["Members"] = nlohmann::json::array();
+
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::put, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::post, {}}};
}
- res.jsonValue = Node::json;
- res.end();
- }
-
- void doPost(crow::Response& res, const crow::Request& req,
- const std::vector<std::string>& params) override {
- boost::beast::http::status status;
- std::string username;
- bool userAuthSuccessful =
- authenticateUser(req, status, username, res.jsonValue);
- res.result(status);
-
- if (!userAuthSuccessful) {
- res.end();
- return;
+ private:
+ void doGet(crow::Response& res, const crow::Request& req,
+ const std::vector<std::string>& params) override
+ {
+ std::vector<const std::string*> sessionIds =
+ crow::persistent_data::SessionStore::getInstance().getUniqueIds(
+ false, crow::persistent_data::PersistenceType::TIMEOUT);
+
+ Node::json["Members@odata.count"] = sessionIds.size();
+ Node::json["Members"] = nlohmann::json::array();
+ for (const std::string* uid : sessionIds)
+ {
+ Node::json["Members"].push_back(
+ {{"@odata.id", "/redfish/v1/SessionService/Sessions/" + *uid}});
+ }
+
+ res.jsonValue = Node::json;
+ res.end();
}
- // User is authenticated - create session for him
- auto session =
- crow::persistent_data::SessionStore::getInstance().generateUserSession(
- username);
- res.addHeader("X-Auth-Token", session->sessionToken);
-
- res.addHeader("Location",
- "/redfish/v1/SessionService/Sessions/" + session->uniqueId);
-
- // Return data for created session
- memberSession.doGet(res, req, {session->uniqueId});
-
- // No need for res.end(), as it is called by doGet()
- }
-
- /**
- * @brief Verifies data provided in request and tries to authenticate user
- *
- * @param[in] req Crow request containing authentication data
- * @param[out] httpRespCode HTTP Code that should be returned in response
- * @param[out] user Retrieved username - not filled on failure
- * @param[out] errJson JSON to which error messages will be written
- *
- * @return true if authentication was successful, false otherwise
- */
- bool authenticateUser(const crow::Request& req,
- boost::beast::http::status& httpRespCode,
- std::string& user, nlohmann::json& errJson) {
- // We need only UserName and Password - nothing more, nothing less
- static constexpr const unsigned int numberOfRequiredFieldsInReq = 2;
-
- // call with exceptions disabled
- auto loginCredentials = nlohmann::json::parse(req.body, nullptr, false);
- if (loginCredentials.is_discarded()) {
- httpRespCode = boost::beast::http::status::bad_request;
-
- messages::addMessageToErrorJson(errJson, messages::malformedJSON());
-
- return false;
+ void doPost(crow::Response& res, const crow::Request& req,
+ const std::vector<std::string>& params) override
+ {
+ boost::beast::http::status status;
+ std::string username;
+ bool userAuthSuccessful =
+ authenticateUser(req, status, username, res.jsonValue);
+ res.result(status);
+
+ if (!userAuthSuccessful)
+ {
+ res.end();
+ return;
+ }
+
+ // User is authenticated - create session for him
+ auto session = crow::persistent_data::SessionStore::getInstance()
+ .generateUserSession(username);
+ res.addHeader("X-Auth-Token", session->sessionToken);
+
+ res.addHeader("Location", "/redfish/v1/SessionService/Sessions/" +
+ session->uniqueId);
+
+ // Return data for created session
+ memberSession.doGet(res, req, {session->uniqueId});
+
+ // No need for res.end(), as it is called by doGet()
}
- // Check that there are only as many fields as there should be
- if (loginCredentials.size() != numberOfRequiredFieldsInReq) {
- httpRespCode = boost::beast::http::status::bad_request;
-
- messages::addMessageToErrorJson(errJson, messages::malformedJSON());
-
- return false;
- }
-
- // Find fields that we need - UserName and Password
- auto userIt = loginCredentials.find("UserName");
- auto passIt = loginCredentials.find("Password");
- if (userIt == loginCredentials.end() || passIt == loginCredentials.end()) {
- httpRespCode = boost::beast::http::status::bad_request;
-
- if (userIt == loginCredentials.end()) {
- messages::addMessageToErrorJson(errJson,
- messages::propertyMissing("UserName"));
- }
-
- if (passIt == loginCredentials.end()) {
- messages::addMessageToErrorJson(errJson,
- messages::propertyMissing("Password"));
- }
-
- return false;
+ /**
+ * @brief Verifies data provided in request and tries to authenticate user
+ *
+ * @param[in] req Crow request containing authentication data
+ * @param[out] httpRespCode HTTP Code that should be returned in response
+ * @param[out] user Retrieved username - not filled on failure
+ * @param[out] errJson JSON to which error messages will be written
+ *
+ * @return true if authentication was successful, false otherwise
+ */
+ bool authenticateUser(const crow::Request& req,
+ boost::beast::http::status& httpRespCode,
+ std::string& user, nlohmann::json& errJson)
+ {
+ // We need only UserName and Password - nothing more, nothing less
+ static constexpr const unsigned int numberOfRequiredFieldsInReq = 2;
+
+ // call with exceptions disabled
+ auto loginCredentials = nlohmann::json::parse(req.body, nullptr, false);
+ if (loginCredentials.is_discarded())
+ {
+ httpRespCode = boost::beast::http::status::bad_request;
+
+ messages::addMessageToErrorJson(errJson, messages::malformedJSON());
+
+ return false;
+ }
+
+ // Check that there are only as many fields as there should be
+ if (loginCredentials.size() != numberOfRequiredFieldsInReq)
+ {
+ httpRespCode = boost::beast::http::status::bad_request;
+
+ messages::addMessageToErrorJson(errJson, messages::malformedJSON());
+
+ return false;
+ }
+
+ // Find fields that we need - UserName and Password
+ auto userIt = loginCredentials.find("UserName");
+ auto passIt = loginCredentials.find("Password");
+ if (userIt == loginCredentials.end() ||
+ passIt == loginCredentials.end())
+ {
+ httpRespCode = boost::beast::http::status::bad_request;
+
+ if (userIt == loginCredentials.end())
+ {
+ messages::addMessageToErrorJson(
+ errJson, messages::propertyMissing("UserName"));
+ }
+
+ if (passIt == loginCredentials.end())
+ {
+ messages::addMessageToErrorJson(
+ errJson, messages::propertyMissing("Password"));
+ }
+
+ return false;
+ }
+
+ // Check that given data is of valid type (string)
+ if (!userIt->is_string() || !passIt->is_string())
+ {
+ httpRespCode = boost::beast::http::status::bad_request;
+
+ if (!userIt->is_string())
+ {
+ messages::addMessageToErrorJson(
+ errJson, messages::propertyValueTypeError(userIt->dump(),
+ "UserName"));
+ }
+
+ if (!passIt->is_string())
+ {
+ messages::addMessageToErrorJson(
+ errJson, messages::propertyValueTypeError(userIt->dump(),
+ "Password"));
+ }
+
+ return false;
+ }
+
+ // Extract username and password
+ std::string username = userIt->get<const std::string>();
+ std::string password = passIt->get<const std::string>();
+
+ // Verify that required fields are not empty
+ if (username.empty() || password.empty())
+ {
+ httpRespCode = boost::beast::http::status::bad_request;
+
+ if (username.empty())
+ {
+ messages::addMessageToErrorJson(
+ errJson, messages::propertyMissing("UserName"));
+ }
+
+ if (password.empty())
+ {
+ messages::addMessageToErrorJson(
+ errJson, messages::propertyMissing("Password"));
+ }
+
+ return false;
+ }
+
+ // Finally - try to authenticate user
+ if (!pamAuthenticateUser(username, password))
+ {
+ httpRespCode = boost::beast::http::status::unauthorized;
+
+ messages::addMessageToErrorJson(
+ errJson,
+ messages::resourceAtUriUnauthorized(
+ std::string(req.url), "Invalid username or password"));
+
+ return false;
+ }
+
+ // User authenticated successfully
+ httpRespCode = boost::beast::http::status::ok;
+ user = username;
+
+ return true;
}
- // Check that given data is of valid type (string)
- if (!userIt->is_string() || !passIt->is_string()) {
- httpRespCode = boost::beast::http::status::bad_request;
-
- if (!userIt->is_string()) {
- messages::addMessageToErrorJson(
- errJson,
- messages::propertyValueTypeError(userIt->dump(), "UserName"));
- }
-
- if (!passIt->is_string()) {
- messages::addMessageToErrorJson(
- errJson,
- messages::propertyValueTypeError(userIt->dump(), "Password"));
- }
+ /**
+ * Member session to ensure consistency between collection's doPost and
+ * member's doGet, as they should return 100% matching data
+ */
+ Sessions memberSession;
+};
- return false;
+class SessionService : public Node
+{
+ public:
+ SessionService(CrowApp& app) : Node(app, "/redfish/v1/SessionService/")
+ {
+ Node::json["@odata.type"] = "#SessionService.v1_0_2.SessionService";
+ Node::json["@odata.id"] = "/redfish/v1/SessionService/";
+ Node::json["@odata.context"] =
+ "/redfish/v1/$metadata#SessionService.SessionService";
+ Node::json["Name"] = "Session Service";
+ Node::json["Id"] = "SessionService";
+ Node::json["Description"] = "Session Service";
+ Node::json["SessionTimeout"] =
+ crow::persistent_data::SessionStore::getInstance()
+ .getTimeoutInSeconds();
+ Node::json["ServiceEnabled"] = true;
+
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::put, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
}
- // Extract username and password
- std::string username = userIt->get<const std::string>();
- std::string password = passIt->get<const std::string>();
-
- // Verify that required fields are not empty
- if (username.empty() || password.empty()) {
- httpRespCode = boost::beast::http::status::bad_request;
-
- if (username.empty()) {
- messages::addMessageToErrorJson(errJson,
- messages::propertyMissing("UserName"));
- }
-
- if (password.empty()) {
- messages::addMessageToErrorJson(errJson,
- messages::propertyMissing("Password"));
- }
-
- return false;
+ private:
+ void doGet(crow::Response& res, const crow::Request& req,
+ const std::vector<std::string>& params) override
+ {
+ res.jsonValue = Node::json;
+ res.end();
}
-
- // Finally - try to authenticate user
- if (!pamAuthenticateUser(username, password)) {
- httpRespCode = boost::beast::http::status::unauthorized;
-
- messages::addMessageToErrorJson(
- errJson, messages::resourceAtUriUnauthorized(
- std::string(req.url), "Invalid username or password"));
-
- return false;
- }
-
- // User authenticated successfully
- httpRespCode = boost::beast::http::status::ok;
- user = username;
-
- return true;
- }
-
- /**
- * Member session to ensure consistency between collection's doPost and
- * member's doGet, as they should return 100% matching data
- */
- Sessions memberSession;
-};
-
-class SessionService : public Node {
- public:
- SessionService(CrowApp& app) : Node(app, "/redfish/v1/SessionService/") {
- Node::json["@odata.type"] = "#SessionService.v1_0_2.SessionService";
- Node::json["@odata.id"] = "/redfish/v1/SessionService/";
- Node::json["@odata.context"] =
- "/redfish/v1/$metadata#SessionService.SessionService";
- Node::json["Name"] = "Session Service";
- Node::json["Id"] = "SessionService";
- Node::json["Description"] = "Session Service";
- Node::json["SessionTimeout"] =
- crow::persistent_data::SessionStore::getInstance()
- .getTimeoutInSeconds();
- Node::json["ServiceEnabled"] = true;
-
- entityPrivileges = {
- {boost::beast::http::verb::get, {{"Login"}}},
- {boost::beast::http::verb::head, {{"Login"}}},
- {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
- {boost::beast::http::verb::put, {{"ConfigureManager"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
- {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
- }
-
- private:
- void doGet(crow::Response& res, const crow::Request& req,
- const std::vector<std::string>& params) override {
- res.jsonValue = Node::json;
- res.end();
- }
};
-} // namespace redfish
+} // namespace redfish
diff --git a/redfish-core/lib/roles.hpp b/redfish-core/lib/roles.hpp
index 72d79486bb..258eed31b2 100644
--- a/redfish-core/lib/roles.hpp
+++ b/redfish-core/lib/roles.hpp
@@ -17,74 +17,82 @@
#include "node.hpp"
-namespace redfish {
+namespace redfish
+{
-class Roles : public Node {
- public:
- Roles(CrowApp& app)
- : Node(app, "/redfish/v1/AccountService/Roles/Administrator/") {
- Node::json["@odata.id"] = "/redfish/v1/AccountService/Roles/Administrator";
- Node::json["@odata.type"] = "#Role.v1_0_2.Role";
- Node::json["@odata.context"] = "/redfish/v1/$metadata#Role.Role";
- Node::json["Id"] = "Administrator";
- Node::json["Name"] = "User Role";
- Node::json["Description"] = "Administrator User Role";
- Node::json["IsPredefined"] = true;
- Node::json["AssignedPrivileges"] = {"Login", "ConfigureManager",
- "ConfigureUsers", "ConfigureSelf",
- "ConfigureComponents"};
- Node::json["OemPrivileges"] = nlohmann::json::array();
- entityPrivileges = {
- {boost::beast::http::verb::get, {{"Login"}}},
- {boost::beast::http::verb::head, {{"Login"}}},
- {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
- {boost::beast::http::verb::put, {{"ConfigureManager"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
- {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
- }
+class Roles : public Node
+{
+ public:
+ Roles(CrowApp& app) :
+ Node(app, "/redfish/v1/AccountService/Roles/Administrator/")
+ {
+ Node::json["@odata.id"] =
+ "/redfish/v1/AccountService/Roles/Administrator";
+ Node::json["@odata.type"] = "#Role.v1_0_2.Role";
+ Node::json["@odata.context"] = "/redfish/v1/$metadata#Role.Role";
+ Node::json["Id"] = "Administrator";
+ Node::json["Name"] = "User Role";
+ Node::json["Description"] = "Administrator User Role";
+ Node::json["IsPredefined"] = true;
+ Node::json["AssignedPrivileges"] = {"Login", "ConfigureManager",
+ "ConfigureUsers", "ConfigureSelf",
+ "ConfigureComponents"};
+ Node::json["OemPrivileges"] = nlohmann::json::array();
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::put, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
+ }
- private:
- void doGet(crow::Response& res, const crow::Request& req,
- const std::vector<std::string>& params) override {
- res.jsonValue = Node::json;
- res.end();
- }
+ private:
+ void doGet(crow::Response& res, const crow::Request& req,
+ const std::vector<std::string>& params) override
+ {
+ res.jsonValue = Node::json;
+ res.end();
+ }
};
-class RoleCollection : public Node {
- public:
- RoleCollection(CrowApp& app)
- : Node(app, "/redfish/v1/AccountService/Roles/") {
- Node::json["@odata.id"] = "/redfish/v1/AccountService/Roles";
- Node::json["@odata.type"] = "#RoleCollection.RoleCollection";
- Node::json["@odata.context"] =
- "/redfish/v1/$metadata#RoleCollection.RoleCollection";
- Node::json["Name"] = "Roles Collection";
- Node::json["Description"] = "BMC User Roles";
- Node::json["Members@odata.count"] = 1;
- Node::json["Members"] = {
- {{"@odata.id", "/redfish/v1/AccountService/Roles/Administrator"}}};
+class RoleCollection : public Node
+{
+ public:
+ RoleCollection(CrowApp& app) :
+ Node(app, "/redfish/v1/AccountService/Roles/")
+ {
+ Node::json["@odata.id"] = "/redfish/v1/AccountService/Roles";
+ Node::json["@odata.type"] = "#RoleCollection.RoleCollection";
+ Node::json["@odata.context"] =
+ "/redfish/v1/$metadata#RoleCollection.RoleCollection";
+ Node::json["Name"] = "Roles Collection";
+ Node::json["Description"] = "BMC User Roles";
+ Node::json["Members@odata.count"] = 1;
+ Node::json["Members"] = {
+ {{"@odata.id", "/redfish/v1/AccountService/Roles/Administrator"}}};
- entityPrivileges = {
- {boost::beast::http::verb::get, {{"Login"}}},
- {boost::beast::http::verb::head, {{"Login"}}},
- {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
- {boost::beast::http::verb::put, {{"ConfigureManager"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
- {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
- }
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::put, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
+ }
- private:
- void doGet(crow::Response& res, const crow::Request& req,
- const std::vector<std::string>& params) override {
- res.jsonValue = Node::json;
- // This is a short term solution to work around a bug. GetSubroutes
- // accidentally recognizes the Roles/Administrator route as a subroute
- // (because it's hardcoded to a single entity). Remove this line when that
- // is resolved
- res.jsonValue.erase("Administrator");
- res.end();
- }
+ private:
+ void doGet(crow::Response& res, const crow::Request& req,
+ const std::vector<std::string>& params) override
+ {
+ res.jsonValue = Node::json;
+ // This is a short term solution to work around a bug. GetSubroutes
+ // accidentally recognizes the Roles/Administrator route as a subroute
+ // (because it's hardcoded to a single entity). Remove this line when
+ // that is resolved
+ res.jsonValue.erase("Administrator");
+ res.end();
+ }
};
-} // namespace redfish
+} // namespace redfish
diff --git a/redfish-core/lib/sensors.hpp b/redfish-core/lib/sensors.hpp
index 7f9fa684bc..c390cd7908 100644
--- a/redfish-core/lib/sensors.hpp
+++ b/redfish-core/lib/sensors.hpp
@@ -16,13 +16,15 @@
#pragma once
#include <math.h>
-#include <dbus_singleton.hpp>
+
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/split.hpp>
#include <boost/container/flat_map.hpp>
#include <boost/range/algorithm/replace_copy_if.hpp>
+#include <dbus_singleton.hpp>
-namespace redfish {
+namespace redfish
+{
constexpr const char* dbusSensorPrefix = "/xyz/openbmc_project/sensors/";
@@ -41,32 +43,38 @@ using ManagedObjectsVectorType = std::vector<std::pair<
* SensorsAsyncResp
* Gathers data needed for response processing after async calls are done
*/
-class SensorsAsyncResp {
- public:
- SensorsAsyncResp(crow::Response& response, const std::string& chassisId,
- const std::initializer_list<const char*> types)
- : res(response), chassisId(chassisId), types(types) {
- res.jsonValue["@odata.id"] =
- "/redfish/v1/Chassis/" + chassisId + "/Thermal";
- }
-
- ~SensorsAsyncResp() {
- if (res.result() == boost::beast::http::status::internal_server_error) {
- // Reset the json object to clear out any data that made it in before the
- // error happened
- // todo(ed) handle error condition with proper code
- res.jsonValue = nlohmann::json::object();
+class SensorsAsyncResp
+{
+ public:
+ SensorsAsyncResp(crow::Response& response, const std::string& chassisId,
+ const std::initializer_list<const char*> types) :
+ res(response),
+ chassisId(chassisId), types(types)
+ {
+ res.jsonValue["@odata.id"] =
+ "/redfish/v1/Chassis/" + chassisId + "/Thermal";
}
- res.end();
- }
- void setErrorStatus() {
- res.result(boost::beast::http::status::internal_server_error);
- }
+ ~SensorsAsyncResp()
+ {
+ if (res.result() == boost::beast::http::status::internal_server_error)
+ {
+ // Reset the json object to clear out any data that made it in
+ // before the error happened todo(ed) handle error condition with
+ // proper code
+ res.jsonValue = nlohmann::json::object();
+ }
+ res.end();
+ }
+
+ void setErrorStatus()
+ {
+ res.result(boost::beast::http::status::internal_server_error);
+ }
- crow::Response& res;
- std::string chassisId{};
- const std::vector<const char*> types;
+ crow::Response& res;
+ std::string chassisId{};
+ const std::vector<const char*> types;
};
/**
@@ -78,70 +86,84 @@ class SensorsAsyncResp {
template <typename Callback>
void getConnections(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
const boost::container::flat_set<std::string>& sensorNames,
- Callback&& callback) {
- BMCWEB_LOG_DEBUG << "getConnections enter";
- const std::string path = "/xyz/openbmc_project/sensors";
- const std::array<std::string, 1> interfaces = {
- "xyz.openbmc_project.Sensor.Value"};
-
- // Response handler for parsing objects subtree
- auto respHandler =
- [ callback{std::move(callback)}, SensorsAsyncResp, sensorNames ](
- const boost::system::error_code ec, const GetSubTreeType& subtree) {
- BMCWEB_LOG_DEBUG << "getConnections resp_handler enter";
- if (ec) {
- SensorsAsyncResp->setErrorStatus();
- BMCWEB_LOG_ERROR << "getConnections resp_handler: Dbus error " << ec;
- return;
- }
+ Callback&& callback)
+{
+ BMCWEB_LOG_DEBUG << "getConnections enter";
+ const std::string path = "/xyz/openbmc_project/sensors";
+ const std::array<std::string, 1> interfaces = {
+ "xyz.openbmc_project.Sensor.Value"};
+
+ // Response handler for parsing objects subtree
+ auto respHandler = [callback{std::move(callback)}, SensorsAsyncResp,
+ sensorNames](const boost::system::error_code ec,
+ const GetSubTreeType& subtree) {
+ BMCWEB_LOG_DEBUG << "getConnections resp_handler enter";
+ if (ec)
+ {
+ SensorsAsyncResp->setErrorStatus();
+ BMCWEB_LOG_ERROR << "getConnections resp_handler: Dbus error "
+ << ec;
+ return;
+ }
- BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " subtrees";
+ BMCWEB_LOG_DEBUG << "Found " << subtree.size() << " subtrees";
- // Make unique list of connections only for requested sensor types and
- // found in the chassis
- boost::container::flat_set<std::string> connections;
- // Intrinsic to avoid malloc. Most systems will have < 8 sensor producers
- connections.reserve(8);
+ // Make unique list of connections only for requested sensor types and
+ // found in the chassis
+ boost::container::flat_set<std::string> connections;
+ // Intrinsic to avoid malloc. Most systems will have < 8 sensor
+ // producers
+ connections.reserve(8);
- BMCWEB_LOG_DEBUG << "sensorNames list count: " << sensorNames.size();
- for (const std::string& tsensor : sensorNames) {
- BMCWEB_LOG_DEBUG << "Sensor to find: " << tsensor;
- }
+ BMCWEB_LOG_DEBUG << "sensorNames list count: " << sensorNames.size();
+ for (const std::string& tsensor : sensorNames)
+ {
+ BMCWEB_LOG_DEBUG << "Sensor to find: " << tsensor;
+ }
- for (const std::pair<
- std::string,
- std::vector<std::pair<std::string, std::vector<std::string>>>>&
- object : subtree) {
- for (const char* type : SensorsAsyncResp->types) {
- if (boost::starts_with(object.first, type)) {
- auto lastPos = object.first.rfind('/');
- if (lastPos != std::string::npos) {
- std::string sensorName = object.first.substr(lastPos + 1);
-
- if (sensorNames.find(sensorName) != sensorNames.end()) {
- // For each Connection name
- for (const std::pair<std::string, std::vector<std::string>>&
- objData : object.second) {
- BMCWEB_LOG_DEBUG << "Adding connection: " << objData.first;
- connections.insert(objData.first);
- }
+ for (const std::pair<
+ std::string,
+ std::vector<std::pair<std::string, std::vector<std::string>>>>&
+ object : subtree)
+ {
+ for (const char* type : SensorsAsyncResp->types)
+ {
+ if (boost::starts_with(object.first, type))
+ {
+ auto lastPos = object.first.rfind('/');
+ if (lastPos != std::string::npos)
+ {
+ std::string sensorName =
+ object.first.substr(lastPos + 1);
+
+ if (sensorNames.find(sensorName) != sensorNames.end())
+ {
+ // For each Connection name
+ for (const std::pair<std::string,
+ std::vector<std::string>>&
+ objData : object.second)
+ {
+ BMCWEB_LOG_DEBUG << "Adding connection: "
+ << objData.first;
+ connections.insert(objData.first);
+ }
+ }
+ }
+ break;
+ }
}
- }
- break;
}
- }
- }
- BMCWEB_LOG_DEBUG << "Found " << connections.size() << " connections";
- callback(std::move(connections));
- BMCWEB_LOG_DEBUG << "getConnections resp_handler exit";
- };
-
- // Make call to ObjectMapper to find all sensors objects
- crow::connections::systemBus->async_method_call(
- std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
- "/xyz/openbmc_project/object_mapper", "xyz.openbmc_project.ObjectMapper",
- "GetSubTree", path, 2, interfaces);
- BMCWEB_LOG_DEBUG << "getConnections exit";
+ BMCWEB_LOG_DEBUG << "Found " << connections.size() << " connections";
+ callback(std::move(connections));
+ BMCWEB_LOG_DEBUG << "getConnections resp_handler exit";
+ };
+
+ // Make call to ObjectMapper to find all sensors objects
+ crow::connections::systemBus->async_method_call(
+ std::move(respHandler), "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree", path, 2, interfaces);
+ BMCWEB_LOG_DEBUG << "getConnections exit";
}
/**
@@ -151,64 +173,74 @@ void getConnections(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
*/
template <typename Callback>
void getChassis(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp,
- Callback&& callback) {
- BMCWEB_LOG_DEBUG << "getChassis enter";
- // Process response from EntityManager and extract chassis data
- auto respHandler = [ callback{std::move(callback)}, SensorsAsyncResp ](
- const boost::system::error_code ec, ManagedObjectsVectorType& resp) {
- BMCWEB_LOG_DEBUG << "getChassis respHandler enter";
- if (ec) {
- BMCWEB_LOG_ERROR << "getChassis respHandler DBUS error: " << ec;
- SensorsAsyncResp->setErrorStatus();
- return;
- }
- boost::container::flat_set<std::string> sensorNames;
-
- // SensorsAsyncResp->chassisId
- bool foundChassis = false;
- std::vector<std::string> split;
- // Reserve space for
- // /xyz/openbmc_project/inventory/<name>/<subname> + 3 subnames
- split.reserve(8);
-
- for (const auto& objDictEntry : resp) {
- const std::string& objectPath =
- static_cast<const std::string&>(objDictEntry.first);
- boost::algorithm::split(split, objectPath, boost::is_any_of("/"));
- if (split.size() < 2) {
- BMCWEB_LOG_ERROR << "Got path that isn't long enough " << objectPath;
- split.clear();
- continue;
- }
- const std::string& sensorName = split.end()[-1];
- const std::string& chassisName = split.end()[-2];
-
- if (chassisName != SensorsAsyncResp->chassisId) {
- split.clear();
- continue;
- }
- BMCWEB_LOG_DEBUG << "New sensor: " << sensorName;
- foundChassis = true;
- sensorNames.emplace(sensorName);
- split.clear();
+ Callback&& callback)
+{
+ BMCWEB_LOG_DEBUG << "getChassis enter";
+ // Process response from EntityManager and extract chassis data
+ auto respHandler = [callback{std::move(callback)},
+ SensorsAsyncResp](const boost::system::error_code ec,
+ ManagedObjectsVectorType& resp) {
+ BMCWEB_LOG_DEBUG << "getChassis respHandler enter";
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "getChassis respHandler DBUS error: " << ec;
+ SensorsAsyncResp->setErrorStatus();
+ return;
+ }
+ boost::container::flat_set<std::string> sensorNames;
+
+ // SensorsAsyncResp->chassisId
+ bool foundChassis = false;
+ std::vector<std::string> split;
+ // Reserve space for
+ // /xyz/openbmc_project/inventory/<name>/<subname> + 3 subnames
+ split.reserve(8);
+
+ for (const auto& objDictEntry : resp)
+ {
+ const std::string& objectPath =
+ static_cast<const std::string&>(objDictEntry.first);
+ boost::algorithm::split(split, objectPath, boost::is_any_of("/"));
+ if (split.size() < 2)
+ {
+ BMCWEB_LOG_ERROR << "Got path that isn't long enough "
+ << objectPath;
+ split.clear();
+ continue;
+ }
+ const std::string& sensorName = split.end()[-1];
+ const std::string& chassisName = split.end()[-2];
+
+ if (chassisName != SensorsAsyncResp->chassisId)
+ {
+ split.clear();
+ continue;
+ }
+ BMCWEB_LOG_DEBUG << "New sensor: " << sensorName;
+ foundChassis = true;
+ sensorNames.emplace(sensorName);
+ split.clear();
+ };
+ BMCWEB_LOG_DEBUG << "Found " << sensorNames.size() << " Sensor names";
+
+ if (!foundChassis)
+ {
+ BMCWEB_LOG_INFO << "Unable to find chassis named "
+ << SensorsAsyncResp->chassisId;
+ SensorsAsyncResp->res.result(boost::beast::http::status::not_found);
+ }
+ else
+ {
+ callback(sensorNames);
+ }
+ BMCWEB_LOG_DEBUG << "getChassis respHandler exit";
};
- BMCWEB_LOG_DEBUG << "Found " << sensorNames.size() << " Sensor names";
-
- if (!foundChassis) {
- BMCWEB_LOG_INFO << "Unable to find chassis named "
- << SensorsAsyncResp->chassisId;
- SensorsAsyncResp->res.result(boost::beast::http::status::not_found);
- } else {
- callback(sensorNames);
- }
- BMCWEB_LOG_DEBUG << "getChassis respHandler exit";
- };
-
- // Make call to EntityManager to find all chassis objects
- crow::connections::systemBus->async_method_call(
- respHandler, "xyz.openbmc_project.EntityManager", "/",
- "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
- BMCWEB_LOG_DEBUG << "getChassis exit";
+
+ // Make call to EntityManager to find all chassis objects
+ crow::connections::systemBus->async_method_call(
+ respHandler, "xyz.openbmc_project.EntityManager", "/",
+ "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
+ BMCWEB_LOG_DEBUG << "getChassis exit";
}
/**
@@ -225,116 +257,146 @@ void objectInterfacesToJson(
const boost::container::flat_map<
std::string, boost::container::flat_map<std::string, SensorVariant>>&
interfacesDict,
- nlohmann::json& sensor_json) {
- // We need a value interface before we can do anything with it
- auto valueIt = interfacesDict.find("xyz.openbmc_project.Sensor.Value");
- if (valueIt == interfacesDict.end()) {
- BMCWEB_LOG_ERROR << "Sensor doesn't have a value interface";
- return;
- }
-
- // Assume values exist as is (10^0 == 1) if no scale exists
- int64_t scaleMultiplier = 0;
-
- auto scaleIt = valueIt->second.find("Scale");
- // If a scale exists, pull value as int64, and use the scaling.
- if (scaleIt != valueIt->second.end()) {
- const int64_t* int64Value = mapbox::getPtr<const int64_t>(scaleIt->second);
- if (int64Value != nullptr) {
- scaleMultiplier = *int64Value;
+ nlohmann::json& sensor_json)
+{
+ // We need a value interface before we can do anything with it
+ auto valueIt = interfacesDict.find("xyz.openbmc_project.Sensor.Value");
+ if (valueIt == interfacesDict.end())
+ {
+ BMCWEB_LOG_ERROR << "Sensor doesn't have a value interface";
+ return;
}
- }
-
- sensor_json["MemberId"] = sensorName;
- sensor_json["Name"] = sensorName;
- sensor_json["Status"]["State"] = "Enabled";
- sensor_json["Status"]["Health"] = "OK";
-
- // Parameter to set to override the type we get from dbus, and force it to
- // int, regardless of what is available. This is used for schemas like fan,
- // that require integers, not floats.
- bool forceToInt = false;
-
- const char* unit = "Reading";
- if (sensorType == "temperature") {
- unit = "ReadingCelsius";
- sensor_json["@odata.type"] = "#Thermal.v1_3_0.Temperature";
- // TODO(ed) Documentation says that path should be type fan_tach,
- // implementation seems to implement fan
- } else if (sensorType == "fan" || sensorType == "fan_tach") {
- unit = "Reading";
- sensor_json["ReadingUnits"] = "RPM";
- sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
- forceToInt = true;
- } else if (sensorType == "voltage") {
- unit = "ReadingVolts";
- sensor_json["@odata.type"] = "#Power.v1_0_0.Voltage";
- } else {
- BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName;
- return;
- }
- // Map of dbus interface name, dbus property name and redfish property_name
- std::vector<std::tuple<const char*, const char*, const char*>> properties;
- properties.reserve(7);
-
- properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
- properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
- "WarningHigh", "UpperThresholdNonCritical");
- properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
- "WarningLow", "LowerThresholdNonCritical");
- properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
- "CriticalHigh", "UpperThresholdCritical");
- properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
- "CriticalLow", "LowerThresholdCritical");
-
- if (sensorType == "temperature") {
- properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
- "MinReadingRangeTemp");
- properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
- "MaxReadingRangeTemp");
- } else {
- properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
- "MinReadingRange");
- properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
- "MaxReadingRange");
- }
-
- for (const std::tuple<const char*, const char*, const char*>& p :
- properties) {
- auto interfaceProperties = interfacesDict.find(std::get<0>(p));
- if (interfaceProperties != interfacesDict.end()) {
- auto valueIt = interfaceProperties->second.find(std::get<1>(p));
- if (valueIt != interfaceProperties->second.end()) {
- const SensorVariant& valueVariant = valueIt->second;
- nlohmann::json& valueIt = sensor_json[std::get<2>(p)];
-
- // Attempt to pull the int64 directly
- const int64_t* int64Value = mapbox::getPtr<const int64_t>(valueVariant);
-
- if (int64Value != nullptr) {
- if (forceToInt || scaleMultiplier >= 0) {
- valueIt = *int64Value * std::pow(10, scaleMultiplier);
- } else {
- valueIt = *int64Value *
- std::pow(10, static_cast<double>(scaleMultiplier));
- }
+
+ // Assume values exist as is (10^0 == 1) if no scale exists
+ int64_t scaleMultiplier = 0;
+
+ auto scaleIt = valueIt->second.find("Scale");
+ // If a scale exists, pull value as int64, and use the scaling.
+ if (scaleIt != valueIt->second.end())
+ {
+ const int64_t* int64Value =
+ mapbox::getPtr<const int64_t>(scaleIt->second);
+ if (int64Value != nullptr)
+ {
+ scaleMultiplier = *int64Value;
}
- // Attempt to pull the float directly
- const double* doubleValue = mapbox::getPtr<const double>(valueVariant);
-
- if (doubleValue != nullptr) {
- if (!forceToInt) {
- valueIt = *doubleValue *
- std::pow(10, static_cast<double>(scaleMultiplier));
- } else {
- valueIt = static_cast<int64_t>(*doubleValue *
- std::pow(10, scaleMultiplier));
- }
+ }
+
+ sensor_json["MemberId"] = sensorName;
+ sensor_json["Name"] = sensorName;
+ sensor_json["Status"]["State"] = "Enabled";
+ sensor_json["Status"]["Health"] = "OK";
+
+ // Parameter to set to override the type we get from dbus, and force it to
+ // int, regardless of what is available. This is used for schemas like fan,
+ // that require integers, not floats.
+ bool forceToInt = false;
+
+ const char* unit = "Reading";
+ if (sensorType == "temperature")
+ {
+ unit = "ReadingCelsius";
+ sensor_json["@odata.type"] = "#Thermal.v1_3_0.Temperature";
+ // TODO(ed) Documentation says that path should be type fan_tach,
+ // implementation seems to implement fan
+ }
+ else if (sensorType == "fan" || sensorType == "fan_tach")
+ {
+ unit = "Reading";
+ sensor_json["ReadingUnits"] = "RPM";
+ sensor_json["@odata.type"] = "#Thermal.v1_3_0.Fan";
+ forceToInt = true;
+ }
+ else if (sensorType == "voltage")
+ {
+ unit = "ReadingVolts";
+ sensor_json["@odata.type"] = "#Power.v1_0_0.Voltage";
+ }
+ else
+ {
+ BMCWEB_LOG_ERROR << "Redfish cannot map object type for " << sensorName;
+ return;
+ }
+ // Map of dbus interface name, dbus property name and redfish property_name
+ std::vector<std::tuple<const char*, const char*, const char*>> properties;
+ properties.reserve(7);
+
+ properties.emplace_back("xyz.openbmc_project.Sensor.Value", "Value", unit);
+ properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
+ "WarningHigh", "UpperThresholdNonCritical");
+ properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Warning",
+ "WarningLow", "LowerThresholdNonCritical");
+ properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
+ "CriticalHigh", "UpperThresholdCritical");
+ properties.emplace_back("xyz.openbmc_project.Sensor.Threshold.Critical",
+ "CriticalLow", "LowerThresholdCritical");
+
+ if (sensorType == "temperature")
+ {
+ properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
+ "MinReadingRangeTemp");
+ properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
+ "MaxReadingRangeTemp");
+ }
+ else
+ {
+ properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MinValue",
+ "MinReadingRange");
+ properties.emplace_back("xyz.openbmc_project.Sensor.Value", "MaxValue",
+ "MaxReadingRange");
+ }
+
+ for (const std::tuple<const char*, const char*, const char*>& p :
+ properties)
+ {
+ auto interfaceProperties = interfacesDict.find(std::get<0>(p));
+ if (interfaceProperties != interfacesDict.end())
+ {
+ auto valueIt = interfaceProperties->second.find(std::get<1>(p));
+ if (valueIt != interfaceProperties->second.end())
+ {
+ const SensorVariant& valueVariant = valueIt->second;
+ nlohmann::json& valueIt = sensor_json[std::get<2>(p)];
+
+ // Attempt to pull the int64 directly
+ const int64_t* int64Value =
+ mapbox::getPtr<const int64_t>(valueVariant);
+
+ if (int64Value != nullptr)
+ {
+ if (forceToInt || scaleMultiplier >= 0)
+ {
+ valueIt = *int64Value * std::pow(10, scaleMultiplier);
+ }
+ else
+ {
+ valueIt =
+ *int64Value *
+ std::pow(10, static_cast<double>(scaleMultiplier));
+ }
+ }
+ // Attempt to pull the float directly
+ const double* doubleValue =
+ mapbox::getPtr<const double>(valueVariant);
+
+ if (doubleValue != nullptr)
+ {
+ if (!forceToInt)
+ {
+ valueIt =
+ *doubleValue *
+ std::pow(10, static_cast<double>(scaleMultiplier));
+ }
+ else
+ {
+ valueIt = static_cast<int64_t>(
+ *doubleValue * std::pow(10, scaleMultiplier));
+ }
+ }
+ }
}
- }
}
- }
- BMCWEB_LOG_DEBUG << "Added sensor " << sensorName;
+ BMCWEB_LOG_DEBUG << "Added sensor " << sensorName;
}
/**
@@ -342,106 +404,140 @@ void objectInterfacesToJson(
* chassis.
* @param SensorsAsyncResp Pointer to object holding response data
*/
-void getChassisData(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp) {
- BMCWEB_LOG_DEBUG << "getChassisData enter";
- auto getChassisCb = [&, SensorsAsyncResp](
- boost::container::flat_set<std::string>&
- sensorNames) {
- BMCWEB_LOG_DEBUG << "getChassisCb enter";
- auto getConnectionCb =
- [&, SensorsAsyncResp, sensorNames](
- const boost::container::flat_set<std::string>& connections) {
- BMCWEB_LOG_DEBUG << "getConnectionCb enter";
- // Get managed objects from all services exposing sensors
- for (const std::string& connection : connections) {
- // Response handler to process managed objects
- auto getManagedObjectsCb = [&, SensorsAsyncResp, sensorNames](
- const boost::system::error_code ec,
- ManagedObjectsVectorType& resp) {
- BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter";
- if (ec) {
- BMCWEB_LOG_ERROR << "getManagedObjectsCb DBUS error: " << ec;
- SensorsAsyncResp->setErrorStatus();
- return;
- }
- // Go through all objects and update response with
- // sensor data
- for (const auto& objDictEntry : resp) {
- const std::string& objPath =
- static_cast<const std::string&>(objDictEntry.first);
- BMCWEB_LOG_DEBUG << "getManagedObjectsCb parsing object "
- << objPath;
-
- std::vector<std::string> split;
- // Reserve space for
- // /xyz/openbmc_project/sensors/<name>/<subname>
- split.reserve(6);
- boost::algorithm::split(split, objPath, boost::is_any_of("/"));
- if (split.size() < 6) {
- BMCWEB_LOG_ERROR << "Got path that isn't long enough "
- << objPath;
- continue;
- }
- // These indexes aren't intuitive, as boost::split puts an empty
- // string at the beggining
- const std::string& sensorType = split[4];
- const std::string& sensorName = split[5];
- BMCWEB_LOG_DEBUG << "sensorName " << sensorName
- << " sensorType " << sensorType;
- if (sensorNames.find(sensorName) == sensorNames.end()) {
- BMCWEB_LOG_ERROR << sensorName << " not in sensor list ";
- continue;
- }
-
- const char* fieldName = nullptr;
- if (sensorType == "temperature") {
- fieldName = "Temperatures";
- } else if (sensorType == "fan" || sensorType == "fan_tach") {
- fieldName = "Fans";
- } else if (sensorType == "voltage") {
- fieldName = "Voltages";
- } else if (sensorType == "current") {
- fieldName = "PowerSupply";
- } else if (sensorType == "power") {
- fieldName = "PowerSupply";
- } else {
- BMCWEB_LOG_ERROR << "Unsure how to handle sensorType "
- << sensorType;
- continue;
- }
-
- nlohmann::json& tempArray =
- SensorsAsyncResp->res.jsonValue[fieldName];
-
- // Create the array if it doesn't yet exist
- if (tempArray.is_array() == false) {
- tempArray = nlohmann::json::array();
- }
-
- tempArray.push_back(
- {{"@odata.id", "/redfish/v1/Chassis/" +
- SensorsAsyncResp->chassisId +
- "/Thermal#/" + sensorName}});
- nlohmann::json& sensorJson = tempArray.back();
- objectInterfacesToJson(sensorName, sensorType,
- objDictEntry.second, sensorJson);
- }
- BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit";
+void getChassisData(std::shared_ptr<SensorsAsyncResp> SensorsAsyncResp)
+{
+ BMCWEB_LOG_DEBUG << "getChassisData enter";
+ auto getChassisCb = [&, SensorsAsyncResp](
+ boost::container::flat_set<std::string>&
+ sensorNames) {
+ BMCWEB_LOG_DEBUG << "getChassisCb enter";
+ auto getConnectionCb =
+ [&, SensorsAsyncResp, sensorNames](
+ const boost::container::flat_set<std::string>& connections) {
+ BMCWEB_LOG_DEBUG << "getConnectionCb enter";
+ // Get managed objects from all services exposing sensors
+ for (const std::string& connection : connections)
+ {
+ // Response handler to process managed objects
+ auto getManagedObjectsCb =
+ [&, SensorsAsyncResp,
+ sensorNames](const boost::system::error_code ec,
+ ManagedObjectsVectorType& resp) {
+ BMCWEB_LOG_DEBUG << "getManagedObjectsCb enter";
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR
+ << "getManagedObjectsCb DBUS error: " << ec;
+ SensorsAsyncResp->setErrorStatus();
+ return;
+ }
+ // Go through all objects and update response with
+ // sensor data
+ for (const auto& objDictEntry : resp)
+ {
+ const std::string& objPath =
+ static_cast<const std::string&>(
+ objDictEntry.first);
+ BMCWEB_LOG_DEBUG
+ << "getManagedObjectsCb parsing object "
+ << objPath;
+
+ std::vector<std::string> split;
+ // Reserve space for
+ // /xyz/openbmc_project/sensors/<name>/<subname>
+ split.reserve(6);
+ boost::algorithm::split(split, objPath,
+ boost::is_any_of("/"));
+ if (split.size() < 6)
+ {
+ BMCWEB_LOG_ERROR
+ << "Got path that isn't long enough "
+ << objPath;
+ continue;
+ }
+ // These indexes aren't intuitive, as
+ // boost::split puts an empty string at the
+ // beggining
+ const std::string& sensorType = split[4];
+ const std::string& sensorName = split[5];
+ BMCWEB_LOG_DEBUG << "sensorName " << sensorName
+ << " sensorType "
+ << sensorType;
+ if (sensorNames.find(sensorName) ==
+ sensorNames.end())
+ {
+ BMCWEB_LOG_ERROR << sensorName
+ << " not in sensor list ";
+ continue;
+ }
+
+ const char* fieldName = nullptr;
+ if (sensorType == "temperature")
+ {
+ fieldName = "Temperatures";
+ }
+ else if (sensorType == "fan" ||
+ sensorType == "fan_tach")
+ {
+ fieldName = "Fans";
+ }
+ else if (sensorType == "voltage")
+ {
+ fieldName = "Voltages";
+ }
+ else if (sensorType == "current")
+ {
+ fieldName = "PowerSupply";
+ }
+ else if (sensorType == "power")
+ {
+ fieldName = "PowerSupply";
+ }
+ else
+ {
+ BMCWEB_LOG_ERROR
+ << "Unsure how to handle sensorType "
+ << sensorType;
+ continue;
+ }
+
+ nlohmann::json& tempArray =
+ SensorsAsyncResp->res.jsonValue[fieldName];
+
+ // Create the array if it doesn't yet exist
+ if (tempArray.is_array() == false)
+ {
+ tempArray = nlohmann::json::array();
+ }
+
+ tempArray.push_back(
+ {{"@odata.id",
+ "/redfish/v1/Chassis/" +
+ SensorsAsyncResp->chassisId +
+ "/Thermal#/" + sensorName}});
+ nlohmann::json& sensorJson = tempArray.back();
+ objectInterfacesToJson(sensorName, sensorType,
+ objDictEntry.second,
+ sensorJson);
+ }
+ BMCWEB_LOG_DEBUG << "getManagedObjectsCb exit";
+ };
+ crow::connections::systemBus->async_method_call(
+ getManagedObjectsCb, connection, "/",
+ "org.freedesktop.DBus.ObjectManager",
+ "GetManagedObjects");
+ };
+ BMCWEB_LOG_DEBUG << "getConnectionCb exit";
};
- crow::connections::systemBus->async_method_call(
- getManagedObjectsCb, connection, "/",
- "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
- };
- BMCWEB_LOG_DEBUG << "getConnectionCb exit";
- };
- // get connections and then pass it to get sensors
- getConnections(SensorsAsyncResp, sensorNames, std::move(getConnectionCb));
- BMCWEB_LOG_DEBUG << "getChassisCb exit";
- };
-
- // get chassis information related to sensors
- getChassis(SensorsAsyncResp, std::move(getChassisCb));
- BMCWEB_LOG_DEBUG << "getChassisData exit";
+ // get connections and then pass it to get sensors
+ getConnections(SensorsAsyncResp, sensorNames,
+ std::move(getConnectionCb));
+ BMCWEB_LOG_DEBUG << "getChassisCb exit";
+ };
+
+ // get chassis information related to sensors
+ getChassis(SensorsAsyncResp, std::move(getChassisCb));
+ BMCWEB_LOG_DEBUG << "getChassisData exit";
};
-} // namespace redfish
+} // namespace redfish
diff --git a/redfish-core/lib/service_root.hpp b/redfish-core/lib/service_root.hpp
index 6fa9632c9b..d2c5163a8a 100644
--- a/redfish-core/lib/service_root.hpp
+++ b/redfish-core/lib/service_root.hpp
@@ -15,62 +15,69 @@
*/
#pragma once
-#include <systemd/sd-id128.h>
#include "node.hpp"
-namespace redfish {
+#include <systemd/sd-id128.h>
-class ServiceRoot : public Node {
- public:
- ServiceRoot(CrowApp& app) : Node(app, "/redfish/v1/") {
- Node::json["@odata.type"] = "#ServiceRoot.v1_1_1.ServiceRoot";
- Node::json["@odata.id"] = "/redfish/v1/";
- Node::json["@odata.context"] =
- "/redfish/v1/$metadata#ServiceRoot.ServiceRoot";
- Node::json["Id"] = "RootService";
- Node::json["Name"] = "Root Service";
- Node::json["RedfishVersion"] = "1.1.0";
- Node::json["Links"]["Sessions"] = {
- {"@odata.id", "/redfish/v1/SessionService/Sessions"}};
+namespace redfish
+{
- Node::json["UUID"] = getUuid();
+class ServiceRoot : public Node
+{
+ public:
+ ServiceRoot(CrowApp& app) : Node(app, "/redfish/v1/")
+ {
+ Node::json["@odata.type"] = "#ServiceRoot.v1_1_1.ServiceRoot";
+ Node::json["@odata.id"] = "/redfish/v1/";
+ Node::json["@odata.context"] =
+ "/redfish/v1/$metadata#ServiceRoot.ServiceRoot";
+ Node::json["Id"] = "RootService";
+ Node::json["Name"] = "Root Service";
+ Node::json["RedfishVersion"] = "1.1.0";
+ Node::json["Links"]["Sessions"] = {
+ {"@odata.id", "/redfish/v1/SessionService/Sessions"}};
- entityPrivileges = {
- {boost::beast::http::verb::get, {}},
- {boost::beast::http::verb::head, {}},
- {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
- }
+ Node::json["UUID"] = getUuid();
- private:
- void doGet(crow::Response& res, const crow::Request& req,
- const std::vector<std::string>& params) override {
- res.jsonValue = Node::json;
- res.end();
- }
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {}},
+ {boost::beast::http::verb::head, {}},
+ {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
+ }
- const std::string getUuid() {
- // If we are using a version of systemd that can get the app specific uuid,
- // use that
+ private:
+ void doGet(crow::Response& res, const crow::Request& req,
+ const std::vector<std::string>& params) override
+ {
+ res.jsonValue = Node::json;
+ res.end();
+ }
+
+ const std::string getUuid()
+ {
+ // If we are using a version of systemd that can get the app specific
+ // uuid, use that
#ifdef sd_id128_get_machine_app_specific
- std::array<char, SD_ID128_STRING_MAX> string;
- sd_id128_t id = SD_ID128_NULL;
+ std::array<char, SD_ID128_STRING_MAX> string;
+ sd_id128_t id = SD_ID128_NULL;
- // This ID needs to match the one in ipmid
- int r = sd_id128_get_machine_app_specific(
- SD_ID128_MAKE(e0, e1, 73, 76, 64, 61, 47, da, a5, 0c, d0, cc, 64, 12,
- 45, 78),
- &id);
- if (r < 0) {
- return "00000000-0000-0000-0000-000000000000";
- }
- return string.data();
+ // This ID needs to match the one in ipmid
+ int r = sd_id128_get_machine_app_specific(
+ SD_ID128_MAKE(e0, e1, 73, 76, 64, 61, 47, da, a5, 0c, d0, cc, 64,
+ 12, 45, 78),
+ &id);
+ if (r < 0)
+ {
+ return "00000000-0000-0000-0000-000000000000";
+ }
+ return string.data();
#else
- return "00000000-0000-0000-0000-000000000000";
+ return "00000000-0000-0000-0000-000000000000";
#endif
- }
+ }
};
-} // namespace redfish
+} // namespace redfish
diff --git a/redfish-core/lib/systems.hpp b/redfish-core/lib/systems.hpp
index b7f91b9916..cd49883859 100644
--- a/redfish-core/lib/systems.hpp
+++ b/redfish-core/lib/systems.hpp
@@ -15,36 +15,44 @@
*/
#pragma once
+#include "boost/container/flat_map.hpp"
+#include "node.hpp"
+
#include <error_messages.hpp>
#include <utils/json_utils.hpp>
-#include "node.hpp"
-#include "boost/container/flat_map.hpp"
-namespace redfish {
+namespace redfish
+{
/**
* SystemAsyncResp
* Gathers data needed for response processing after async calls are done
*/
-class SystemAsyncResp {
- public:
- SystemAsyncResp(crow::Response &response) : res(response) {}
+class SystemAsyncResp
+{
+ public:
+ SystemAsyncResp(crow::Response &response) : res(response)
+ {
+ }
- ~SystemAsyncResp() {
- if (res.result() != (boost::beast::http::status::ok)) {
- // Reset the json object to clear out any data that made it in before the
- // error happened
- // todo(ed) handle error condition with proper code
- res.jsonValue = messages::internalError();
+ ~SystemAsyncResp()
+ {
+ if (res.result() != (boost::beast::http::status::ok))
+ {
+ // Reset the json object to clear out any data that made it in
+ // before the error happened todo(ed) handle error condition with
+ // proper code
+ res.jsonValue = messages::internalError();
+ }
+ res.end();
}
- res.end();
- }
- void setErrorStatus() {
- res.result(boost::beast::http::status::internal_server_error);
- }
+ void setErrorStatus()
+ {
+ res.result(boost::beast::http::status::internal_server_error);
+ }
- crow::Response &res;
+ crow::Response &res;
};
/**
@@ -59,628 +67,853 @@ class SystemAsyncResp {
* This perhaps shall be different file, which has to be chosen on compile time
* depending on OEM needs
*/
-class OnDemandSystemsProvider {
- public:
- template <typename CallbackFunc>
- void getBaseboardList(CallbackFunc &&callback) {
- BMCWEB_LOG_DEBUG << "Get list of available boards.";
- crow::connections::systemBus->async_method_call(
- [callback{std::move(callback)}](const boost::system::error_code ec,
- const std::vector<std::string> &resp) {
- // Callback requires vector<string> to retrieve all available board
- // list.
- std::vector<std::string> boardList;
- if (ec) {
- // Something wrong on DBus, the error_code is not important at this
- // moment, just return success=false, and empty output. Since size
- // of vector may vary depending on information from Entity Manager,
- // and empty output could not be treated same way as error.
- callback(false, boardList);
- return;
- }
- BMCWEB_LOG_DEBUG << "Got " << resp.size() << " boards.";
- // Iterate over all retrieved ObjectPaths.
- for (const std::string &objpath : resp) {
- std::size_t lastPos = objpath.rfind("/");
- if (lastPos != std::string::npos) {
- boardList.emplace_back(objpath.substr(lastPos + 1));
- }
- }
- // Finally make a callback with useful data
- callback(true, boardList);
- },
- "xyz.openbmc_project.ObjectMapper",
- "/xyz/openbmc_project/object_mapper",
- "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
- "/xyz/openbmc_project/inventory", int32_t(0),
- std::array<const char *, 1>{
- "xyz.openbmc_project.Inventory.Item.Board"});
- };
-
- /**
- * @brief Retrieves computer system properties over dbus
- *
- * @param[in] aResp Shared pointer for completing asynchronous calls
- * @param[in] name Computer system name from request
- *
- * @return None.
- */
- void getComputerSystem(std::shared_ptr<SystemAsyncResp> aResp,
- const std::string &name) {
- const std::array<const char *, 5> interfaces = {
- "xyz.openbmc_project.Inventory.Decorator.Asset",
- "xyz.openbmc_project.Inventory.Item.Cpu",
- "xyz.openbmc_project.Inventory.Item.Dimm",
- "xyz.openbmc_project.Inventory.Item.System",
- "xyz.openbmc_project.Common.UUID",
- };
- BMCWEB_LOG_DEBUG << "Get available system components.";
- crow::connections::systemBus->async_method_call(
- [ name, aResp{std::move(aResp)} ](
- const boost::system::error_code ec,
- const std::vector<std::pair<
- std::string,
- std::vector<std::pair<std::string, std::vector<std::string>>>>>
- &subtree) {
- if (ec) {
- BMCWEB_LOG_DEBUG << "DBUS response error";
- aResp->setErrorStatus();
- return;
- }
- bool foundName = false;
- // Iterate over all retrieved ObjectPaths.
- for (const std::pair<std::string,
- std::vector<std::pair<std::string,
- std::vector<std::string>>>>
- &object : subtree) {
- const std::string &path = object.first;
- BMCWEB_LOG_DEBUG << "Got path: " << path;
- const std::vector<std::pair<std::string, std::vector<std::string>>>
- &connectionNames = object.second;
- if (connectionNames.size() < 1) {
- continue;
- }
- // Check if computer system exist
- if (boost::ends_with(path, name)) {
- foundName = true;
- BMCWEB_LOG_DEBUG << "Found name: " << name;
- const std::string connectionName = connectionNames[0].first;
- crow::connections::systemBus->async_method_call(
- [ aResp, name(std::string(name)) ](
- const boost::system::error_code ec,
- const std::vector<std::pair<std::string, VariantType>>
- &propertiesList) {
- if (ec) {
- BMCWEB_LOG_ERROR << "DBUS response error: " << ec;
- aResp->setErrorStatus();
- return;
+class OnDemandSystemsProvider
+{
+ public:
+ template <typename CallbackFunc>
+ void getBaseboardList(CallbackFunc &&callback)
+ {
+ BMCWEB_LOG_DEBUG << "Get list of available boards.";
+ crow::connections::systemBus->async_method_call(
+ [callback{std::move(callback)}](
+ const boost::system::error_code ec,
+ const std::vector<std::string> &resp) {
+ // Callback requires vector<string> to retrieve all available
+ // board list.
+ std::vector<std::string> boardList;
+ if (ec)
+ {
+ // Something wrong on DBus, the error_code is not important
+ // at this moment, just return success=false, and empty
+ // output. Since size of vector may vary depending on
+ // information from Entity Manager, and empty output could
+ // not be treated same way as error.
+ callback(false, boardList);
+ return;
+ }
+ BMCWEB_LOG_DEBUG << "Got " << resp.size() << " boards.";
+ // Iterate over all retrieved ObjectPaths.
+ for (const std::string &objpath : resp)
+ {
+ std::size_t lastPos = objpath.rfind("/");
+ if (lastPos != std::string::npos)
+ {
+ boardList.emplace_back(objpath.substr(lastPos + 1));
}
- BMCWEB_LOG_DEBUG << "Got " << propertiesList.size()
- << "properties for system";
- for (const std::pair<std::string, VariantType> &property :
- propertiesList) {
- const std::string *value =
- mapbox::getPtr<const std::string>(property.second);
- if (value != nullptr) {
- aResp->res.jsonValue[property.first] = *value;
- }
+ }
+ // Finally make a callback with useful data
+ callback(true, boardList);
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTreePaths",
+ "/xyz/openbmc_project/inventory", int32_t(0),
+ std::array<const char *, 1>{
+ "xyz.openbmc_project.Inventory.Item.Board"});
+ };
+
+ /**
+ * @brief Retrieves computer system properties over dbus
+ *
+ * @param[in] aResp Shared pointer for completing asynchronous calls
+ * @param[in] name Computer system name from request
+ *
+ * @return None.
+ */
+ void getComputerSystem(std::shared_ptr<SystemAsyncResp> aResp,
+ const std::string &name)
+ {
+ const std::array<const char *, 5> interfaces = {
+ "xyz.openbmc_project.Inventory.Decorator.Asset",
+ "xyz.openbmc_project.Inventory.Item.Cpu",
+ "xyz.openbmc_project.Inventory.Item.Dimm",
+ "xyz.openbmc_project.Inventory.Item.System",
+ "xyz.openbmc_project.Common.UUID",
+ };
+ BMCWEB_LOG_DEBUG << "Get available system components.";
+ crow::connections::systemBus->async_method_call(
+ [name, aResp{std::move(aResp)}](
+ const boost::system::error_code ec,
+ const std::vector<std::pair<
+ std::string, std::vector<std::pair<
+ std::string, std::vector<std::string>>>>>
+ &subtree) {
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG << "DBUS response error";
+ aResp->setErrorStatus();
+ return;
+ }
+ bool foundName = false;
+ // Iterate over all retrieved ObjectPaths.
+ for (const std::pair<
+ std::string,
+ std::vector<
+ std::pair<std::string, std::vector<std::string>>>>
+ &object : subtree)
+ {
+ const std::string &path = object.first;
+ BMCWEB_LOG_DEBUG << "Got path: " << path;
+ const std::vector<
+ std::pair<std::string, std::vector<std::string>>>
+ &connectionNames = object.second;
+ if (connectionNames.size() < 1)
+ {
+ continue;
}
- aResp->res.jsonValue["Name"] = name;
- aResp->res.jsonValue["Id"] =
- aResp->res.jsonValue["SerialNumber"];
- },
- connectionName, path, "org.freedesktop.DBus.Properties",
- "GetAll", "xyz.openbmc_project.Inventory.Decorator.Asset");
- } else {
- // This is not system, so check if it's cpu, dimm, UUID or BiosVer
- for (auto const &s : connectionNames) {
- for (auto const &i : s.second) {
- if (boost::ends_with(i, "Dimm")) {
- BMCWEB_LOG_DEBUG << "Found Dimm, now get it properties.";
- crow::connections::systemBus->async_method_call(
- [&, aResp](const boost::system::error_code ec,
- const std::vector<std::pair<
- std::string, VariantType>> &properties) {
- if (ec) {
- BMCWEB_LOG_ERROR << "DBUS response error " << ec;
- aResp->setErrorStatus();
- return;
- }
- BMCWEB_LOG_DEBUG << "Got " << properties.size()
- << "Dimm properties.";
- for (const auto &p : properties) {
- if (p.first == "MemorySize") {
- const std::string *value =
- mapbox::getPtr<const std::string>(p.second);
- if ((value != nullptr) && (*value != "NULL")) {
- // Remove units char
- int32_t unitCoeff;
- if (boost::ends_with(*value, "MB")) {
- unitCoeff = 1000;
- } else if (boost::ends_with(*value, "KB")) {
- unitCoeff = 1000000;
- } else {
- BMCWEB_LOG_ERROR
- << "Unsupported memory units";
- aResp->setErrorStatus();
- return;
+ // Check if computer system exist
+ if (boost::ends_with(path, name))
+ {
+ foundName = true;
+ BMCWEB_LOG_DEBUG << "Found name: " << name;
+ const std::string connectionName =
+ connectionNames[0].first;
+ crow::connections::systemBus->async_method_call(
+ [aResp, name(std::string(name))](
+ const boost::system::error_code ec,
+ const std::vector<
+ std::pair<std::string, VariantType>>
+ &propertiesList) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "DBUS response error: "
+ << ec;
+ aResp->setErrorStatus();
+ return;
+ }
+ BMCWEB_LOG_DEBUG << "Got "
+ << propertiesList.size()
+ << "properties for system";
+ for (const std::pair<std::string, VariantType>
+ &property : propertiesList)
+ {
+ const std::string *value =
+ mapbox::getPtr<const std::string>(
+ property.second);
+ if (value != nullptr)
+ {
+ aResp->res.jsonValue[property.first] =
+ *value;
+ }
}
+ aResp->res.jsonValue["Name"] = name;
+ aResp->res.jsonValue["Id"] =
+ aResp->res.jsonValue["SerialNumber"];
+ },
+ connectionName, path,
+ "org.freedesktop.DBus.Properties", "GetAll",
+ "xyz.openbmc_project.Inventory.Decorator.Asset");
+ }
+ else
+ {
+ // This is not system, so check if it's cpu, dimm, UUID
+ // or BiosVer
+ for (auto const &s : connectionNames)
+ {
+ for (auto const &i : s.second)
+ {
+ if (boost::ends_with(i, "Dimm"))
+ {
+ BMCWEB_LOG_DEBUG
+ << "Found Dimm, now get it properties.";
+ crow::connections::systemBus->async_method_call(
+ [&, aResp](
+ const boost::system::error_code ec,
+ const std::vector<std::pair<
+ std::string, VariantType>>
+ &properties) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR
+ << "DBUS response error "
+ << ec;
+ aResp->setErrorStatus();
+ return;
+ }
+ BMCWEB_LOG_DEBUG
+ << "Got " << properties.size()
+ << "Dimm properties.";
+ for (const auto &p : properties)
+ {
+ if (p.first == "MemorySize")
+ {
+ const std::string *value =
+ mapbox::getPtr<
+ const std::string>(
+ p.second);
+ if ((value != nullptr) &&
+ (*value != "NULL"))
+ {
+ // Remove units char
+ int32_t unitCoeff;
+ if (boost::ends_with(
+ *value, "MB"))
+ {
+ unitCoeff = 1000;
+ }
+ else if (boost::
+ ends_with(
+ *value,
+ "KB"))
+ {
+ unitCoeff = 1000000;
+ }
+ else
+ {
+ BMCWEB_LOG_ERROR
+ << "Unsupported"
+ " memory "
+ "units";
+ aResp
+ ->setErrorStatus();
+ return;
+ }
- auto memSize = boost::lexical_cast<int>(
- value->substr(0, value->length() - 2));
- aResp->res.jsonValue["TotalSystemMemoryGiB"] +=
- memSize * unitCoeff;
- aResp->res.jsonValue["MemorySummary"]["Status"]
- ["State"] = "Enabled";
- }
- }
- }
- },
- s.first, path, "org.freedesktop.DBus.Properties",
- "GetAll", "xyz.openbmc_project.Inventory.Item.Dimm");
- } else if (boost::ends_with(i, "Cpu")) {
- BMCWEB_LOG_DEBUG << "Found Cpu, now get it properties.";
- crow::connections::systemBus->async_method_call(
- [&, aResp](const boost::system::error_code ec,
- const std::vector<std::pair<
- std::string, VariantType>> &properties) {
- if (ec) {
- BMCWEB_LOG_ERROR << "DBUS response error " << ec;
- aResp->setErrorStatus();
- return;
- }
- BMCWEB_LOG_DEBUG << "Got " << properties.size()
- << "Cpu properties.";
- for (const auto &p : properties) {
- if (p.first == "ProcessorFamily") {
- const std::string *value =
- mapbox::getPtr<const std::string>(p.second);
- if (value != nullptr) {
- aResp->res
- .jsonValue["ProcessorSummary"]["Count"] =
- aResp->res
- .jsonValue["ProcessorSummary"]["Count"]
- .get<int>() +
- 1;
- aResp->res.jsonValue["ProcessorSummary"]
- ["Status"]["State"] =
- "Enabled";
- aResp->res
- .jsonValue["ProcessorSummary"]["Model"] =
- *value;
- }
- }
- }
- },
- s.first, path, "org.freedesktop.DBus.Properties",
- "GetAll", "xyz.openbmc_project.Inventory.Item.Cpu");
- } else if (boost::ends_with(i, "UUID")) {
- BMCWEB_LOG_DEBUG << "Found UUID, now get it properties.";
- crow::connections::systemBus->async_method_call(
- [aResp](const boost::system::error_code ec,
- const std::vector<std::pair<
- std::string, VariantType>> &properties) {
- if (ec) {
- BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
- aResp->setErrorStatus();
- return;
- }
- BMCWEB_LOG_DEBUG << "Got " << properties.size()
- << "UUID properties.";
- for (const std::pair<std::string, VariantType> &p :
- properties) {
- if (p.first == "BIOSVer") {
- const std::string *value =
- mapbox::getPtr<const std::string>(p.second);
- if (value != nullptr) {
- aResp->res.jsonValue["BiosVersion"] = *value;
- }
- }
- if (p.first == "UUID") {
- const std::string *value =
- mapbox::getPtr<const std::string>(p.second);
- BMCWEB_LOG_DEBUG << "UUID = " << *value
- << " length " << value->length();
- if (value != nullptr) {
- // Workaround for to short return str in smbios
- // demo app, 32 bytes are described by spec
- if (value->length() > 0 &&
- value->length() < 32) {
- std::string correctedValue = *value;
- correctedValue.append(32 - value->length(),
- '0');
- value = &correctedValue;
- } else if (value->length() == 32) {
- aResp->res.jsonValue["UUID"] =
- value->substr(0, 8) + "-" +
- value->substr(8, 4) + "-" +
- value->substr(12, 4) + "-" +
- value->substr(16, 4) + "-" +
- value->substr(20, 12);
+ auto memSize =
+ boost::lexical_cast<
+ int>(value->substr(
+ 0,
+ value->length() -
+ 2));
+ aResp->res.jsonValue
+ ["TotalSystemMemory"
+ "GiB"] +=
+ memSize * unitCoeff;
+ aResp->res.jsonValue
+ ["MemorySummary"]
+ ["Status"]
+ ["State"] =
+ "Enabled";
+ }
+ }
+ }
+ },
+ s.first, path,
+ "org.freedesktop.DBus.Properties",
+ "GetAll",
+ "xyz.openbmc_project.Inventory.Item."
+ "Dimm");
+ }
+ else if (boost::ends_with(i, "Cpu"))
+ {
+ BMCWEB_LOG_DEBUG
+ << "Found Cpu, now get it properties.";
+ crow::connections::systemBus
+ ->async_method_call(
+ [&, aResp](
+ const boost::system::error_code
+ ec,
+ const std::vector<std::pair<
+ std::string, VariantType>>
+ &properties) {
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR
+ << "DBUS response "
+ "error "
+ << ec;
+ aResp->setErrorStatus();
+ return;
+ }
+ BMCWEB_LOG_DEBUG
+ << "Got "
+ << properties.size()
+ << "Cpu properties.";
+ for (const auto &p : properties)
+ {
+ if (p.first ==
+ "ProcessorFamily")
+ {
+ const std::string
+ *value =
+ mapbox::getPtr<
+ const std::
+ string>(
+ p.second);
+ if (value != nullptr)
+ {
+ aResp->res.jsonValue
+ ["ProcessorSumm"
+ "ary"]
+ ["Count"] =
+ aResp->res
+ .jsonValue
+ ["Proce"
+ "ssorS"
+ "ummar"
+ "y"]
+ ["Coun"
+ "t"]
+ .get<
+ int>() +
+ 1;
+ aResp->res.jsonValue
+ ["ProcessorSumm"
+ "ary"]
+ ["Status"]
+ ["State"] =
+ "Enabled";
+ aResp->res.jsonValue
+ ["ProcessorSumm"
+ "ary"]
+ ["Model"] =
+ *value;
+ }
+ }
+ }
+ },
+ s.first, path,
+ "org.freedesktop.DBus.Properties",
+ "GetAll",
+ "xyz.openbmc_project.Inventory."
+ "Item.Cpu");
+ }
+ else if (boost::ends_with(i, "UUID"))
+ {
+ BMCWEB_LOG_DEBUG
+ << "Found UUID, now get it properties.";
+ crow::connections::systemBus->async_method_call(
+ [aResp](
+ const boost::system::error_code ec,
+ const std::vector<std::pair<
+ std::string, VariantType>>
+ &properties) {
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG
+ << "DBUS response error "
+ << ec;
+ aResp->setErrorStatus();
+ return;
+ }
+ BMCWEB_LOG_DEBUG
+ << "Got " << properties.size()
+ << "UUID properties.";
+ for (const std::pair<std::string,
+ VariantType>
+ &p : properties)
+ {
+ if (p.first == "BIOSVer")
+ {
+ const std::string *value =
+ mapbox::getPtr<
+ const std::string>(
+ p.second);
+ if (value != nullptr)
+ {
+ aResp->res.jsonValue
+ ["BiosVersion"] =
+ *value;
+ }
+ }
+ if (p.first == "UUID")
+ {
+ const std::string *value =
+ mapbox::getPtr<
+ const std::string>(
+ p.second);
+ BMCWEB_LOG_DEBUG
+ << "UUID = " << *value
+ << " length "
+ << value->length();
+ if (value != nullptr)
+ {
+ // Workaround for to
+ // short return str in
+ // smbios demo app, 32
+ // bytes are described
+ // by spec
+ if (value->length() >
+ 0 &&
+ value->length() <
+ 32)
+ {
+ std::string
+ correctedValue =
+ *value;
+ correctedValue.append(
+ 32 -
+ value
+ ->length(),
+ '0');
+ value =
+ &correctedValue;
+ }
+ else if (
+ value->length() ==
+ 32)
+ {
+ aResp->res.jsonValue
+ ["UUID"] =
+ value->substr(
+ 0, 8) +
+ "-" +
+ value->substr(
+ 8, 4) +
+ "-" +
+ value->substr(
+ 12, 4) +
+ "-" +
+ value->substr(
+ 16, 4) +
+ "-" +
+ value->substr(
+ 20, 12);
+ }
+ }
+ }
+ }
+ },
+ s.first, path,
+ "org.freedesktop.DBus.Properties",
+ "GetAll",
+ "xyz.openbmc_project.Common.UUID");
}
- }
}
- }
- },
- s.first, path, "org.freedesktop.DBus.Properties",
- "GetAll", "xyz.openbmc_project.Common.UUID");
- }
+ }
+ }
}
- }
- }
- }
- if (foundName == false) {
- aResp->setErrorStatus();
- }
- },
- "xyz.openbmc_project.ObjectMapper",
- "/xyz/openbmc_project/object_mapper",
- "xyz.openbmc_project.ObjectMapper", "GetSubTree",
- "/xyz/openbmc_project/inventory", int32_t(0), interfaces);
- }
+ if (foundName == false)
+ {
+ aResp->setErrorStatus();
+ }
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
+ "/xyz/openbmc_project/inventory", int32_t(0), interfaces);
+ }
- /**
- * @brief Retrieves identify led group properties over dbus
- *
- * @param[in] aResp Shared pointer for completing asynchronous calls.
- * @param[in] callback Callback for process retrieved data.
- *
- * @return None.
- */
- template <typename CallbackFunc>
- void getLedGroupIdentify(std::shared_ptr<SystemAsyncResp> aResp,
- CallbackFunc &&callback) {
- BMCWEB_LOG_DEBUG << "Get led groups";
- crow::connections::systemBus->async_method_call(
- [
- aResp{std::move(aResp)}, &callback
- ](const boost::system::error_code &ec, const ManagedObjectsType &resp) {
- if (ec) {
- BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
- aResp->setErrorStatus();
- return;
- }
- BMCWEB_LOG_DEBUG << "Got " << resp.size() << "led group objects.";
- for (const auto &objPath : resp) {
- const std::string &path = objPath.first;
- if (path.rfind("enclosure_identify") != std::string::npos) {
- for (const auto &interface : objPath.second) {
- if (interface.first == "xyz.openbmc_project.Led.Group") {
- for (const auto &property : interface.second) {
- if (property.first == "Asserted") {
- const bool *asserted =
- mapbox::getPtr<const bool>(property.second);
- if (nullptr != asserted) {
- callback(*asserted, aResp);
- } else {
- callback(false, aResp);
- }
+ /**
+ * @brief Retrieves identify led group properties over dbus
+ *
+ * @param[in] aResp Shared pointer for completing asynchronous calls.
+ * @param[in] callback Callback for process retrieved data.
+ *
+ * @return None.
+ */
+ template <typename CallbackFunc>
+ void getLedGroupIdentify(std::shared_ptr<SystemAsyncResp> aResp,
+ CallbackFunc &&callback)
+ {
+ BMCWEB_LOG_DEBUG << "Get led groups";
+ crow::connections::systemBus->async_method_call(
+ [aResp{std::move(aResp)},
+ &callback](const boost::system::error_code &ec,
+ const ManagedObjectsType &resp) {
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
+ aResp->setErrorStatus();
+ return;
+ }
+ BMCWEB_LOG_DEBUG << "Got " << resp.size()
+ << "led group objects.";
+ for (const auto &objPath : resp)
+ {
+ const std::string &path = objPath.first;
+ if (path.rfind("enclosure_identify") != std::string::npos)
+ {
+ for (const auto &interface : objPath.second)
+ {
+ if (interface.first ==
+ "xyz.openbmc_project.Led.Group")
+ {
+ for (const auto &property : interface.second)
+ {
+ if (property.first == "Asserted")
+ {
+ const bool *asserted =
+ mapbox::getPtr<const bool>(
+ property.second);
+ if (nullptr != asserted)
+ {
+ callback(*asserted, aResp);
+ }
+ else
+ {
+ callback(false, aResp);
+ }
+ }
+ }
+ }
+ }
}
- }
}
- }
- }
- }
- },
- "xyz.openbmc_project.LED.GroupManager",
- "/xyz/openbmc_project/led/groups", "org.freedesktop.DBus.ObjectManager",
- "GetManagedObjects");
- }
+ },
+ "xyz.openbmc_project.LED.GroupManager",
+ "/xyz/openbmc_project/led/groups",
+ "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
+ }
- template <typename CallbackFunc>
- void getLedIdentify(std::shared_ptr<SystemAsyncResp> aResp,
- CallbackFunc &&callback) {
- BMCWEB_LOG_DEBUG << "Get identify led properties";
- crow::connections::systemBus->async_method_call(
- [ aResp{std::move(aResp)}, &callback ](
- const boost::system::error_code ec,
- const PropertiesType &properties) {
- if (ec) {
- BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
- aResp->setErrorStatus();
- return;
- }
- BMCWEB_LOG_DEBUG << "Got " << properties.size() << "led properties.";
- std::string output;
- for (const auto &property : properties) {
- if (property.first == "State") {
- const std::string *s =
- mapbox::getPtr<std::string>(property.second);
- if (nullptr != s) {
- BMCWEB_LOG_DEBUG << "Identify Led State: " << *s;
- const auto pos = s->rfind('.');
- if (pos != std::string::npos) {
- auto led = s->substr(pos + 1);
- for (const std::pair<const char *, const char *> &p :
- std::array<std::pair<const char *, const char *>, 3>{
- {{"On", "Lit"},
- {"Blink", "Blinking"},
- {"Off", "Off"}}}) {
- if (led == p.first) {
- output = p.second;
+ template <typename CallbackFunc>
+ void getLedIdentify(std::shared_ptr<SystemAsyncResp> aResp,
+ CallbackFunc &&callback)
+ {
+ BMCWEB_LOG_DEBUG << "Get identify led properties";
+ crow::connections::systemBus->async_method_call(
+ [aResp{std::move(aResp)},
+ &callback](const boost::system::error_code ec,
+ const PropertiesType &properties) {
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
+ aResp->setErrorStatus();
+ return;
+ }
+ BMCWEB_LOG_DEBUG << "Got " << properties.size()
+ << "led properties.";
+ std::string output;
+ for (const auto &property : properties)
+ {
+ if (property.first == "State")
+ {
+ const std::string *s =
+ mapbox::getPtr<std::string>(property.second);
+ if (nullptr != s)
+ {
+ BMCWEB_LOG_DEBUG << "Identify Led State: " << *s;
+ const auto pos = s->rfind('.');
+ if (pos != std::string::npos)
+ {
+ auto led = s->substr(pos + 1);
+ for (const std::pair<const char *, const char *>
+ &p :
+ std::array<
+ std::pair<const char *, const char *>,
+ 3>{{{"On", "Lit"},
+ {"Blink", "Blinking"},
+ {"Off", "Off"}}})
+ {
+ if (led == p.first)
+ {
+ output = p.second;
+ }
+ }
+ }
+ }
}
- }
}
- }
- }
- }
- callback(output, aResp);
- },
- "xyz.openbmc_project.LED.Controller.identify",
- "/xyz/openbmc_project/led/physical/identify",
- "org.freedesktop.DBus.Properties", "GetAll",
- "xyz.openbmc_project.Led.Physical");
- }
+ callback(output, aResp);
+ },
+ "xyz.openbmc_project.LED.Controller.identify",
+ "/xyz/openbmc_project/led/physical/identify",
+ "org.freedesktop.DBus.Properties", "GetAll",
+ "xyz.openbmc_project.Led.Physical");
+ }
- /**
- * @brief Retrieves host state properties over dbus
- *
- * @param[in] aResp Shared pointer for completing asynchronous calls.
- *
- * @return None.
- */
- void getHostState(std::shared_ptr<SystemAsyncResp> aResp) {
- BMCWEB_LOG_DEBUG << "Get host information.";
- crow::connections::systemBus->async_method_call(
- [aResp{std::move(aResp)}](const boost::system::error_code ec,
- const PropertiesType &properties) {
- if (ec) {
- BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
- aResp->setErrorStatus();
- return;
- }
- BMCWEB_LOG_DEBUG << "Got " << properties.size() << "host properties.";
- for (const auto &property : properties) {
- if (property.first == "CurrentHostState") {
- const std::string *s =
- mapbox::getPtr<const std::string>(property.second);
- BMCWEB_LOG_DEBUG << "Host state: " << *s;
- if (nullptr != s) {
- const auto pos = s->rfind('.');
- if (pos != std::string::npos) {
- // Verify Host State
- if (s->substr(pos + 1) == "Running") {
- aResp->res.jsonValue["PowerState"] = "On";
- aResp->res.jsonValue["Status"]["State"] = "Enabled";
- } else {
- aResp->res.jsonValue["PowerState"] = "Off";
- aResp->res.jsonValue["Status"]["State"] = "Disabled";
- }
+ /**
+ * @brief Retrieves host state properties over dbus
+ *
+ * @param[in] aResp Shared pointer for completing asynchronous calls.
+ *
+ * @return None.
+ */
+ void getHostState(std::shared_ptr<SystemAsyncResp> aResp)
+ {
+ BMCWEB_LOG_DEBUG << "Get host information.";
+ crow::connections::systemBus->async_method_call(
+ [aResp{std::move(aResp)}](const boost::system::error_code ec,
+ const PropertiesType &properties) {
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
+ aResp->setErrorStatus();
+ return;
}
- }
- }
- }
- },
- "xyz.openbmc_project.State.Host", "/xyz/openbmc_project/state/host0",
- "org.freedesktop.DBus.Properties", "GetAll",
- "xyz.openbmc_project.State.Host");
- }
+ BMCWEB_LOG_DEBUG << "Got " << properties.size()
+ << "host properties.";
+ for (const auto &property : properties)
+ {
+ if (property.first == "CurrentHostState")
+ {
+ const std::string *s =
+ mapbox::getPtr<const std::string>(property.second);
+ BMCWEB_LOG_DEBUG << "Host state: " << *s;
+ if (nullptr != s)
+ {
+ const auto pos = s->rfind('.');
+ if (pos != std::string::npos)
+ {
+ // Verify Host State
+ if (s->substr(pos + 1) == "Running")
+ {
+ aResp->res.jsonValue["PowerState"] = "On";
+ aResp->res.jsonValue["Status"]["State"] =
+ "Enabled";
+ }
+ else
+ {
+ aResp->res.jsonValue["PowerState"] = "Off";
+ aResp->res.jsonValue["Status"]["State"] =
+ "Disabled";
+ }
+ }
+ }
+ }
+ }
+ },
+ "xyz.openbmc_project.State.Host",
+ "/xyz/openbmc_project/state/host0",
+ "org.freedesktop.DBus.Properties", "GetAll",
+ "xyz.openbmc_project.State.Host");
+ }
};
/**
* SystemsCollection derived class for delivering ComputerSystems Collection
* Schema
*/
-class SystemsCollection : public Node {
- public:
- SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/") {
- Node::json["@odata.type"] =
- "#ComputerSystemCollection.ComputerSystemCollection";
- Node::json["@odata.id"] = "/redfish/v1/Systems";
- Node::json["@odata.context"] =
- "/redfish/v1/"
- "$metadata#ComputerSystemCollection.ComputerSystemCollection";
- Node::json["Name"] = "Computer System Collection";
+class SystemsCollection : public Node
+{
+ public:
+ SystemsCollection(CrowApp &app) : Node(app, "/redfish/v1/Systems/")
+ {
+ Node::json["@odata.type"] =
+ "#ComputerSystemCollection.ComputerSystemCollection";
+ Node::json["@odata.id"] = "/redfish/v1/Systems";
+ Node::json["@odata.context"] =
+ "/redfish/v1/"
+ "$metadata#ComputerSystemCollection.ComputerSystemCollection";
+ Node::json["Name"] = "Computer System Collection";
- entityPrivileges = {
- {boost::beast::http::verb::get, {{"Login"}}},
- {boost::beast::http::verb::head, {{"Login"}}},
- {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
- }
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
+ }
- private:
- /**
- * Functions triggers appropriate requests on DBus
- */
- void doGet(crow::Response &res, const crow::Request &req,
- const std::vector<std::string> &params) override {
- // Get board list, and call the below callback for JSON preparation
- provider.getBaseboardList(
- [&](const bool &success, const std::vector<std::string> &output) {
- if (success) {
- // ... prepare json array with appropriate @odata.id links
- nlohmann::json boardArray = nlohmann::json::array();
- for (const std::string &boardItem : output) {
- boardArray.push_back(
- {{"@odata.id", "/redfish/v1/Systems/" + boardItem}});
+ private:
+ /**
+ * Functions triggers appropriate requests on DBus
+ */
+ void doGet(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> &params) override
+ {
+ // Get board list, and call the below callback for JSON preparation
+ provider.getBaseboardList([&](const bool &success,
+ const std::vector<std::string> &output) {
+ if (success)
+ {
+ // ... prepare json array with appropriate @odata.id links
+ nlohmann::json boardArray = nlohmann::json::array();
+ for (const std::string &boardItem : output)
+ {
+ boardArray.push_back(
+ {{"@odata.id", "/redfish/v1/Systems/" + boardItem}});
+ }
+ // Then attach members, count size and return,
+ Node::json["Members"] = boardArray;
+ Node::json["Members@odata.count"] = boardArray.size();
+ res.jsonValue = Node::json;
}
- // Then attach members, count size and return,
- Node::json["Members"] = boardArray;
- Node::json["Members@odata.count"] = boardArray.size();
- res.jsonValue = Node::json;
- } else {
- // ... otherwise, return INTERNALL ERROR
- res.result(boost::beast::http::status::internal_server_error);
- }
- res.end();
+ else
+ {
+ // ... otherwise, return INTERNALL ERROR
+ res.result(boost::beast::http::status::internal_server_error);
+ }
+ res.end();
});
- }
+ }
- OnDemandSystemsProvider provider;
+ OnDemandSystemsProvider provider;
};
/**
* Systems override class for delivering ComputerSystems Schema
*/
-class Systems : public Node {
- public:
- /*
- * Default Constructor
- */
- Systems(CrowApp &app)
- : Node(app, "/redfish/v1/Systems/<str>/", std::string()) {
- Node::json["@odata.type"] = "#ComputerSystem.v1_3_0.ComputerSystem";
- Node::json["@odata.context"] =
- "/redfish/v1/$metadata#ComputerSystem.ComputerSystem";
- Node::json["SystemType"] = "Physical";
- Node::json["Description"] = "Computer System";
- Node::json["Boot"]["BootSourceOverrideEnabled"] =
- "Disabled"; // TODO(Dawid), get real boot data
- Node::json["Boot"]["BootSourceOverrideTarget"] =
- "None"; // TODO(Dawid), get real boot data
- Node::json["Boot"]["BootSourceOverrideMode"] =
- "Legacy"; // TODO(Dawid), get real boot data
- Node::json["Boot"]["BootSourceOverrideTarget@Redfish.AllowableValues"] = {
- "None", "Pxe", "Hdd", "Cd",
- "BiosSetup", "UefiShell", "Usb"}; // TODO(Dawid), get real boot data
- Node::json["ProcessorSummary"]["Count"] = int(0);
- Node::json["ProcessorSummary"]["Status"]["State"] = "Disabled";
- Node::json["MemorySummary"]["TotalSystemMemoryGiB"] = int(0);
- Node::json["MemorySummary"]["Status"]["State"] = "Disabled";
-
- entityPrivileges = {
- {boost::beast::http::verb::get, {{"Login"}}},
- {boost::beast::http::verb::head, {{"Login"}}},
- {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
- }
+class Systems : public Node
+{
+ public:
+ /*
+ * Default Constructor
+ */
+ Systems(CrowApp &app) :
+ Node(app, "/redfish/v1/Systems/<str>/", std::string())
+ {
+ Node::json["@odata.type"] = "#ComputerSystem.v1_3_0.ComputerSystem";
+ Node::json["@odata.context"] =
+ "/redfish/v1/$metadata#ComputerSystem.ComputerSystem";
+ Node::json["SystemType"] = "Physical";
+ Node::json["Description"] = "Computer System";
+ Node::json["Boot"]["BootSourceOverrideEnabled"] =
+ "Disabled"; // TODO(Dawid), get real boot data
+ Node::json["Boot"]["BootSourceOverrideTarget"] =
+ "None"; // TODO(Dawid), get real boot data
+ Node::json["Boot"]["BootSourceOverrideMode"] =
+ "Legacy"; // TODO(Dawid), get real boot data
+ Node::json["Boot"]["BootSourceOverrideTarget@Redfish.AllowableValues"] =
+ {"None", "Pxe", "Hdd", "Cd",
+ "BiosSetup", "UefiShell", "Usb"}; // TODO(Dawid), get real boot
+ // data
+ Node::json["ProcessorSummary"]["Count"] = int(0);
+ Node::json["ProcessorSummary"]["Status"]["State"] = "Disabled";
+ Node::json["MemorySummary"]["TotalSystemMemoryGiB"] = int(0);
+ Node::json["MemorySummary"]["Status"]["State"] = "Disabled";
- private:
- OnDemandSystemsProvider provider;
-
- /**
- * Functions triggers appropriate requests on DBus
- */
- void doGet(crow::Response &res, const crow::Request &req,
- const std::vector<std::string> &params) override {
- // Check if there is required param, truly entering this shall be
- // impossible
- if (params.size() != 1) {
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
- return;
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
}
- const std::string &name = params[0];
+ private:
+ OnDemandSystemsProvider provider;
+
+ /**
+ * Functions triggers appropriate requests on DBus
+ */
+ void doGet(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> &params) override
+ {
+ // Check if there is required param, truly entering this shall be
+ // impossible
+ if (params.size() != 1)
+ {
+ res.result(boost::beast::http::status::internal_server_error);
+ res.end();
+ return;
+ }
- res.jsonValue = Node::json;
- res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name;
+ const std::string &name = params[0];
- auto asyncResp = std::make_shared<SystemAsyncResp>(res);
+ res.jsonValue = Node::json;
+ res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name;
- provider.getLedGroupIdentify(
- asyncResp, [&](const bool &asserted,
- const std::shared_ptr<SystemAsyncResp> &aResp) {
- if (asserted) {
- // If led group is asserted, then another call is needed to
- // get led status
- provider.getLedIdentify(
- aResp, [](const std::string &ledStatus,
- const std::shared_ptr<SystemAsyncResp> &aResp) {
- if (!ledStatus.empty()) {
- aResp->res.jsonValue["IndicatorLED"] = ledStatus;
- }
- });
- } else {
- aResp->res.jsonValue["IndicatorLED"] = "Off";
- }
- });
- provider.getComputerSystem(asyncResp, name);
- provider.getHostState(asyncResp);
- }
+ auto asyncResp = std::make_shared<SystemAsyncResp>(res);
- void doPatch(crow::Response &res, const crow::Request &req,
- const std::vector<std::string> &params) override {
- // Check if there is required param, truly entering this shall be
- // impossible
- if (params.size() != 1) {
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
- return;
- }
- // Parse JSON request body
- nlohmann::json patch;
- if (!json_util::processJsonFromRequest(res, req, patch)) {
- return;
- }
- // Find key with new led value
- const std::string &name = params[0];
- const std::string *reqLedState = nullptr;
- json_util::Result r = json_util::getString(
- "IndicatorLED", patch, reqLedState,
- static_cast<int>(json_util::MessageSetting::TYPE_ERROR) |
- static_cast<int>(json_util::MessageSetting::MISSING),
- res.jsonValue, std::string("/" + name + "/IndicatorLED"));
- if ((r != json_util::Result::SUCCESS) || (reqLedState == nullptr)) {
- res.result(boost::beast::http::status::bad_request);
- res.end();
- return;
- }
- // Verify key value
- std::string dbusLedState;
- for (const auto &p : boost::container::flat_map<const char *, const char *>{
- {"On", "Lit"}, {"Blink", "Blinking"}, {"Off", "Off"}}) {
- if (*reqLedState == p.second) {
- dbusLedState = p.first;
- }
+ provider.getLedGroupIdentify(
+ asyncResp, [&](const bool &asserted,
+ const std::shared_ptr<SystemAsyncResp> &aResp) {
+ if (asserted)
+ {
+ // If led group is asserted, then another call is needed to
+ // get led status
+ provider.getLedIdentify(
+ aResp,
+ [](const std::string &ledStatus,
+ const std::shared_ptr<SystemAsyncResp> &aResp) {
+ if (!ledStatus.empty())
+ {
+ aResp->res.jsonValue["IndicatorLED"] =
+ ledStatus;
+ }
+ });
+ }
+ else
+ {
+ aResp->res.jsonValue["IndicatorLED"] = "Off";
+ }
+ });
+ provider.getComputerSystem(asyncResp, name);
+ provider.getHostState(asyncResp);
}
- // Update led status
- auto asyncResp = std::make_shared<SystemAsyncResp>(res);
- res.jsonValue = Node::json;
- res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name;
+ void doPatch(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> &params) override
+ {
+ // Check if there is required param, truly entering this shall be
+ // impossible
+ if (params.size() != 1)
+ {
+ res.result(boost::beast::http::status::internal_server_error);
+ res.end();
+ return;
+ }
+ // Parse JSON request body
+ nlohmann::json patch;
+ if (!json_util::processJsonFromRequest(res, req, patch))
+ {
+ return;
+ }
+ // Find key with new led value
+ const std::string &name = params[0];
+ const std::string *reqLedState = nullptr;
+ json_util::Result r = json_util::getString(
+ "IndicatorLED", patch, reqLedState,
+ static_cast<int>(json_util::MessageSetting::TYPE_ERROR) |
+ static_cast<int>(json_util::MessageSetting::MISSING),
+ res.jsonValue, std::string("/" + name + "/IndicatorLED"));
+ if ((r != json_util::Result::SUCCESS) || (reqLedState == nullptr))
+ {
+ res.result(boost::beast::http::status::bad_request);
+ res.end();
+ return;
+ }
+ // Verify key value
+ std::string dbusLedState;
+ for (const auto &p :
+ boost::container::flat_map<const char *, const char *>{
+ {"On", "Lit"}, {"Blink", "Blinking"}, {"Off", "Off"}})
+ {
+ if (*reqLedState == p.second)
+ {
+ dbusLedState = p.first;
+ }
+ }
- provider.getHostState(asyncResp);
- provider.getComputerSystem(asyncResp, name);
+ // Update led status
+ auto asyncResp = std::make_shared<SystemAsyncResp>(res);
+ res.jsonValue = Node::json;
+ res.jsonValue["@odata.id"] = "/redfish/v1/Systems/" + name;
- if (dbusLedState.empty()) {
- messages::addMessageToJsonRoot(
- res.jsonValue,
- messages::propertyValueNotInList(*reqLedState, "IndicatorLED"));
- } else {
- // Update led group
- BMCWEB_LOG_DEBUG << "Update led group.";
- crow::connections::systemBus->async_method_call(
- [&, asyncResp{std::move(asyncResp)} ](
- const boost::system::error_code ec) {
- if (ec) {
- BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
- asyncResp->setErrorStatus();
- return;
- }
- BMCWEB_LOG_DEBUG << "Led group update done.";
- },
- "xyz.openbmc_project.LED.GroupManager",
- "/xyz/openbmc_project/led/groups/enclosure_identify",
- "org.freedesktop.DBus.Properties", "Set",
- "xyz.openbmc_project.Led.Group", "Asserted",
- sdbusplus::message::variant<bool>(
- (dbusLedState == "Off" ? false : true)));
- // Update identify led status
- BMCWEB_LOG_DEBUG << "Update led SoftwareInventoryCollection.";
- crow::connections::systemBus->async_method_call(
- [&, asyncResp{std::move(asyncResp)} ](
- const boost::system::error_code ec) {
- if (ec) {
- BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
- asyncResp->setErrorStatus();
- return;
- }
- BMCWEB_LOG_DEBUG << "Led state update done.";
- res.jsonValue["IndicatorLED"] = *reqLedState;
- },
- "xyz.openbmc_project.LED.Controller.identify",
- "/xyz/openbmc_project/led/physical/identify",
- "org.freedesktop.DBus.Properties", "Set",
- "xyz.openbmc_project.Led.Physical", "State",
- sdbusplus::message::variant<std::string>(
- "xyz.openbmc_project.Led.Physical.Action." + dbusLedState));
+ provider.getHostState(asyncResp);
+ provider.getComputerSystem(asyncResp, name);
+
+ if (dbusLedState.empty())
+ {
+ messages::addMessageToJsonRoot(
+ res.jsonValue,
+ messages::propertyValueNotInList(*reqLedState, "IndicatorLED"));
+ }
+ else
+ {
+ // Update led group
+ BMCWEB_LOG_DEBUG << "Update led group.";
+ crow::connections::systemBus->async_method_call(
+ [&, asyncResp{std::move(asyncResp)}](
+ const boost::system::error_code ec) {
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
+ asyncResp->setErrorStatus();
+ return;
+ }
+ BMCWEB_LOG_DEBUG << "Led group update done.";
+ },
+ "xyz.openbmc_project.LED.GroupManager",
+ "/xyz/openbmc_project/led/groups/enclosure_identify",
+ "org.freedesktop.DBus.Properties", "Set",
+ "xyz.openbmc_project.Led.Group", "Asserted",
+ sdbusplus::message::variant<bool>(
+ (dbusLedState == "Off" ? false : true)));
+ // Update identify led status
+ BMCWEB_LOG_DEBUG << "Update led SoftwareInventoryCollection.";
+ crow::connections::systemBus->async_method_call(
+ [&, asyncResp{std::move(asyncResp)}](
+ const boost::system::error_code ec) {
+ if (ec)
+ {
+ BMCWEB_LOG_DEBUG << "DBUS response error " << ec;
+ asyncResp->setErrorStatus();
+ return;
+ }
+ BMCWEB_LOG_DEBUG << "Led state update done.";
+ res.jsonValue["IndicatorLED"] = *reqLedState;
+ },
+ "xyz.openbmc_project.LED.Controller.identify",
+ "/xyz/openbmc_project/led/physical/identify",
+ "org.freedesktop.DBus.Properties", "Set",
+ "xyz.openbmc_project.Led.Physical", "State",
+ sdbusplus::message::variant<std::string>(
+ "xyz.openbmc_project.Led.Physical.Action." + dbusLedState));
+ }
}
- }
};
-} // namespace redfish
+} // namespace redfish
diff --git a/redfish-core/lib/thermal.hpp b/redfish-core/lib/thermal.hpp
index 8fb291b9bb..37b0f43f3a 100644
--- a/redfish-core/lib/thermal.hpp
+++ b/redfish-core/lib/thermal.hpp
@@ -18,44 +18,49 @@
#include "node.hpp"
#include "sensors.hpp"
-namespace redfish {
+namespace redfish
+{
-class Thermal : public Node {
- public:
- Thermal(CrowApp& app)
- : Node((app), "/redfish/v1/Chassis/<str>/Thermal/", std::string()) {
- Node::json["@odata.type"] = "#Thermal.v1_4_0.Thermal";
- Node::json["@odata.context"] = "/redfish/v1/$metadata#Thermal.Thermal";
- Node::json["Id"] = "Thermal";
- Node::json["Name"] = "Thermal";
+class Thermal : public Node
+{
+ public:
+ Thermal(CrowApp& app) :
+ Node((app), "/redfish/v1/Chassis/<str>/Thermal/", std::string())
+ {
+ Node::json["@odata.type"] = "#Thermal.v1_4_0.Thermal";
+ Node::json["@odata.context"] = "/redfish/v1/$metadata#Thermal.Thermal";
+ Node::json["Id"] = "Thermal";
+ Node::json["Name"] = "Thermal";
- entityPrivileges = {
- {boost::beast::http::verb::get, {{"Login"}}},
- {boost::beast::http::verb::head, {{"Login"}}},
- {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
- {boost::beast::http::verb::put, {{"ConfigureManager"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
- {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
- }
-
- private:
- void doGet(crow::Response& res, const crow::Request& req,
- const std::vector<std::string>& params) override {
- if (params.size() != 1) {
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
- return;
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::put, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureManager"}}},
+ {boost::beast::http::verb::post, {{"ConfigureManager"}}}};
}
- const std::string& chassisName = params[0];
- res.jsonValue = Node::json;
- auto asyncResp = std::make_shared<SensorsAsyncResp>(
- res, chassisName,
- std::initializer_list<const char*>{
- "/xyz/openbmc_project/sensors/fan",
- "/xyz/openbmc_project/sensors/temperature"});
- getChassisData(asyncResp);
- }
+ private:
+ void doGet(crow::Response& res, const crow::Request& req,
+ const std::vector<std::string>& params) override
+ {
+ if (params.size() != 1)
+ {
+ res.result(boost::beast::http::status::internal_server_error);
+ res.end();
+ return;
+ }
+ const std::string& chassisName = params[0];
+
+ res.jsonValue = Node::json;
+ auto asyncResp = std::make_shared<SensorsAsyncResp>(
+ res, chassisName,
+ std::initializer_list<const char*>{
+ "/xyz/openbmc_project/sensors/fan",
+ "/xyz/openbmc_project/sensors/temperature"});
+ getChassisData(asyncResp);
+ }
};
-} // namespace redfish
+} // namespace redfish
diff --git a/redfish-core/lib/update_service.hpp b/redfish-core/lib/update_service.hpp
index 677b6d1741..658937d9a5 100644
--- a/redfish-core/lib/update_service.hpp
+++ b/redfish-core/lib/update_service.hpp
@@ -16,381 +16,450 @@
#pragma once
#include "node.hpp"
+
#include <boost/container/flat_map.hpp>
-namespace redfish {
+namespace redfish
+{
static std::unique_ptr<sdbusplus::bus::match::match> fwUpdateMatcher;
-class UpdateService : public Node {
- public:
- UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/") {
- Node::json["@odata.type"] = "#UpdateService.v1_2_0.UpdateService";
- Node::json["@odata.id"] = "/redfish/v1/UpdateService";
- Node::json["@odata.context"] =
- "/redfish/v1/$metadata#UpdateService.UpdateService";
- Node::json["Id"] = "UpdateService";
- Node::json["Description"] = "Service for Software Update";
- Node::json["Name"] = "Update Service";
- Node::json["HttpPushUri"] = "/redfish/v1/UpdateService";
- // UpdateService cannot be disabled
- Node::json["ServiceEnabled"] = true;
- Node::json["FirmwareInventory"] = {
- {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}};
-
- entityPrivileges = {
- {boost::beast::http::verb::get, {{"Login"}}},
- {boost::beast::http::verb::head, {{"Login"}}},
- {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
- }
-
- private:
- void doGet(crow::Response &res, const crow::Request &req,
- const std::vector<std::string> &params) override {
- res.jsonValue = Node::json;
- res.end();
- }
- static void activateImage(const std::string &objPath) {
- crow::connections::systemBus->async_method_call(
- [objPath](const boost::system::error_code error_code) {
- if (error_code) {
- BMCWEB_LOG_DEBUG << "error_code = " << error_code;
- BMCWEB_LOG_DEBUG << "error msg = " << error_code.message();
- }
- },
- "xyz.openbmc_project.Software.BMC.Updater", objPath,
- "org.freedesktop.DBus.Properties", "Set",
- "xyz.openbmc_project.Software.Activation", "RequestedActivation",
- sdbusplus::message::variant<std::string>(
- "xyz.openbmc_project.Software.Activation.RequestedActivations."
- "Active"));
- }
- void doPost(crow::Response &res, const crow::Request &req,
- const std::vector<std::string> &params) override {
- BMCWEB_LOG_DEBUG << "doPost...";
-
- // Only allow one FW update at a time
- if (fwUpdateMatcher != nullptr) {
- res.addHeader("Retry-After", "30");
- res.result(boost::beast::http::status::service_unavailable);
- res.jsonValue = messages::serviceTemporarilyUnavailable("3");
- res.end();
- return;
+class UpdateService : public Node
+{
+ public:
+ UpdateService(CrowApp &app) : Node(app, "/redfish/v1/UpdateService/")
+ {
+ Node::json["@odata.type"] = "#UpdateService.v1_2_0.UpdateService";
+ Node::json["@odata.id"] = "/redfish/v1/UpdateService";
+ Node::json["@odata.context"] =
+ "/redfish/v1/$metadata#UpdateService.UpdateService";
+ Node::json["Id"] = "UpdateService";
+ Node::json["Description"] = "Service for Software Update";
+ Node::json["Name"] = "Update Service";
+ Node::json["HttpPushUri"] = "/redfish/v1/UpdateService";
+ // UpdateService cannot be disabled
+ Node::json["ServiceEnabled"] = true;
+ Node::json["FirmwareInventory"] = {
+ {"@odata.id", "/redfish/v1/UpdateService/FirmwareInventory"}};
+
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
}
- // Make this const static so it survives outside this method
- static boost::asio::deadline_timer timeout(*req.ioService,
- boost::posix_time::seconds(5));
-
- timeout.expires_from_now(boost::posix_time::seconds(5));
-
- timeout.async_wait([&res](const boost::system::error_code &ec) {
- fwUpdateMatcher = nullptr;
- if (ec == boost::asio::error::operation_aborted) {
- // expected, we were canceled before the timer completed.
- return;
- }
- BMCWEB_LOG_ERROR << "Timed out waiting for firmware object being created";
- BMCWEB_LOG_ERROR << "FW image may has already been uploaded to server";
- if (ec) {
- BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
- return;
- }
-
- res.result(boost::beast::http::status::internal_server_error);
- res.jsonValue = redfish::messages::internalError();
- res.end();
- });
-
- auto callback = [&res](sdbusplus::message::message &m) {
- BMCWEB_LOG_DEBUG << "Match fired";
- bool flag = false;
-
- if (m.is_method_error()) {
- BMCWEB_LOG_DEBUG << "Dbus method error!!!";
+
+ private:
+ void doGet(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> &params) override
+ {
+ res.jsonValue = Node::json;
res.end();
- return;
- }
- std::vector<std::pair<
- std::string,
- std::vector<std::pair<std::string,
- sdbusplus::message::variant<std::string>>>>>
- interfaces_properties;
-
- sdbusplus::message::object_path objPath;
-
- m.read(objPath, interfaces_properties); // Read in the object path
- // that was just created
- // std::string str_objpath = objPath.str; // keep a copy for
- // constructing response message
- BMCWEB_LOG_DEBUG << "obj path = " << objPath.str; // str_objpath;
- for (auto &interface : interfaces_properties) {
- BMCWEB_LOG_DEBUG << "interface = " << interface.first;
-
- if (interface.first == "xyz.openbmc_project.Software.Activation") {
- // cancel timer only when xyz.openbmc_project.Software.Activation
- // interface is added
- boost::system::error_code ec;
- timeout.cancel(ec);
- if (ec) {
- BMCWEB_LOG_ERROR << "error canceling timer " << ec;
- }
- UpdateService::activateImage(objPath.str); // str_objpath);
- res.jsonValue = redfish::messages::success();
- BMCWEB_LOG_DEBUG << "ending response";
- res.end();
- fwUpdateMatcher = nullptr;
+ }
+ static void activateImage(const std::string &objPath)
+ {
+ crow::connections::systemBus->async_method_call(
+ [objPath](const boost::system::error_code error_code) {
+ if (error_code)
+ {
+ BMCWEB_LOG_DEBUG << "error_code = " << error_code;
+ BMCWEB_LOG_DEBUG << "error msg = " << error_code.message();
+ }
+ },
+ "xyz.openbmc_project.Software.BMC.Updater", objPath,
+ "org.freedesktop.DBus.Properties", "Set",
+ "xyz.openbmc_project.Software.Activation", "RequestedActivation",
+ sdbusplus::message::variant<std::string>(
+ "xyz.openbmc_project.Software.Activation.RequestedActivations."
+ "Active"));
+ }
+ void doPost(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> &params) override
+ {
+ BMCWEB_LOG_DEBUG << "doPost...";
+
+ // Only allow one FW update at a time
+ if (fwUpdateMatcher != nullptr)
+ {
+ res.addHeader("Retry-After", "30");
+ res.result(boost::beast::http::status::service_unavailable);
+ res.jsonValue = messages::serviceTemporarilyUnavailable("3");
+ res.end();
+ return;
}
- }
- };
-
- fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
- *crow::connections::systemBus,
- "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
- "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
- callback);
-
- std::string filepath(
- "/tmp/images/" +
- boost::uuids::to_string(boost::uuids::random_generator()()));
- BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
- std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
- std::ofstream::trunc);
- out << req.body;
- out.close();
- BMCWEB_LOG_DEBUG << "file upload complete!!";
- }
-};
+ // Make this const static so it survives outside this method
+ static boost::asio::deadline_timer timeout(
+ *req.ioService, boost::posix_time::seconds(5));
+
+ timeout.expires_from_now(boost::posix_time::seconds(5));
+
+ timeout.async_wait([&res](const boost::system::error_code &ec) {
+ fwUpdateMatcher = nullptr;
+ if (ec == boost::asio::error::operation_aborted)
+ {
+ // expected, we were canceled before the timer completed.
+ return;
+ }
+ BMCWEB_LOG_ERROR
+ << "Timed out waiting for firmware object being created";
+ BMCWEB_LOG_ERROR
+ << "FW image may has already been uploaded to server";
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "Async_wait failed" << ec;
+ return;
+ }
-class SoftwareInventoryCollection : public Node {
- public:
- template <typename CrowApp>
- SoftwareInventoryCollection(CrowApp &app)
- : Node(app, "/redfish/v1/UpdateService/FirmwareInventory/") {
- Node::json["@odata.type"] =
- "#SoftwareInventoryCollection.SoftwareInventoryCollection";
- Node::json["@odata.id"] = "/redfish/v1/UpdateService/FirmwareInventory";
- Node::json["@odata.context"] =
- "/redfish/v1/"
- "$metadata#SoftwareInventoryCollection.SoftwareInventoryCollection";
- Node::json["Name"] = "Software Inventory Collection";
-
- entityPrivileges = {
- {boost::beast::http::verb::get, {{"Login"}}},
- {boost::beast::http::verb::head, {{"Login"}}},
- {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
- }
-
- private:
- void doGet(crow::Response &res, const crow::Request &req,
- const std::vector<std::string> &params) override {
- std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
- res.jsonValue = Node::json;
-
- crow::connections::systemBus->async_method_call(
- [asyncResp](
- const boost::system::error_code ec,
- const std::vector<std::pair<
- std::string,
- std::vector<std::pair<std::string, std::vector<std::string>>>>>
- &subtree) {
- if (ec) {
- asyncResp->res.result(
- boost::beast::http::status::internal_server_error);
- return;
- }
- asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
- asyncResp->res.jsonValue["Members@odata.count"] = 0;
-
- for (auto &obj : subtree) {
- const std::vector<std::pair<std::string, std::vector<std::string>>>
- &connections = obj.second;
-
- for (auto &conn : connections) {
- const std::string &connectionName = conn.first;
- BMCWEB_LOG_DEBUG << "connectionName = " << connectionName;
- BMCWEB_LOG_DEBUG << "obj.first = " << obj.first;
-
- crow::connections::systemBus->async_method_call(
- [asyncResp](const boost::system::error_code error_code,
- const VariantType &activation) {
- BMCWEB_LOG_DEBUG << "safe returned in lambda function";
- if (error_code) {
- asyncResp->res.result(
- boost::beast::http::status::internal_server_error);
- return;
- }
+ res.result(boost::beast::http::status::internal_server_error);
+ res.jsonValue = redfish::messages::internalError();
+ res.end();
+ });
- const std::string *sw_inv_purpose =
- mapbox::getPtr<const std::string>(activation);
- if (sw_inv_purpose == nullptr) {
- asyncResp->res.result(
- boost::beast::http::status::internal_server_error);
- return;
- }
- std::size_t last_pos = sw_inv_purpose->rfind(".");
- if (last_pos == std::string::npos) {
- asyncResp->res.result(
- boost::beast::http::status::internal_server_error);
- return;
+ auto callback = [&res](sdbusplus::message::message &m) {
+ BMCWEB_LOG_DEBUG << "Match fired";
+ bool flag = false;
+
+ if (m.is_method_error())
+ {
+ BMCWEB_LOG_DEBUG << "Dbus method error!!!";
+ res.end();
+ return;
+ }
+ std::vector<std::pair<
+ std::string,
+ std::vector<std::pair<
+ std::string, sdbusplus::message::variant<std::string>>>>>
+ interfaces_properties;
+
+ sdbusplus::message::object_path objPath;
+
+ m.read(objPath, interfaces_properties); // Read in the object path
+ // that was just created
+ // std::string str_objpath = objPath.str; // keep a copy for
+ // constructing response message
+ BMCWEB_LOG_DEBUG << "obj path = " << objPath.str; // str_objpath;
+ for (auto &interface : interfaces_properties)
+ {
+ BMCWEB_LOG_DEBUG << "interface = " << interface.first;
+
+ if (interface.first ==
+ "xyz.openbmc_project.Software.Activation")
+ {
+ // cancel timer only when
+ // xyz.openbmc_project.Software.Activation interface is
+ // added
+ boost::system::error_code ec;
+ timeout.cancel(ec);
+ if (ec)
+ {
+ BMCWEB_LOG_ERROR << "error canceling timer " << ec;
}
- nlohmann::json &members =
- asyncResp->res.jsonValue["Members"];
- members.push_back(
- {{"@odata.id",
- "/redfish/v1/UpdateService/FirmwareInventory/" +
- sw_inv_purpose->substr(last_pos + 1)}});
- asyncResp->res.jsonValue["Members@odata.count"] =
- members.size();
- },
- connectionName, obj.first, "org.freedesktop.DBus.Properties",
- "Get", "xyz.openbmc_project.Software.Activation",
- "Activation");
+ UpdateService::activateImage(objPath.str); // str_objpath);
+ res.jsonValue = redfish::messages::success();
+ BMCWEB_LOG_DEBUG << "ending response";
+ res.end();
+ fwUpdateMatcher = nullptr;
+ }
}
- }
- },
- "xyz.openbmc_project.ObjectMapper",
- "/xyz/openbmc_project/object_mapper",
- "xyz.openbmc_project.ObjectMapper", "GetSubTree",
- "/xyz/openbmc_project/software", int32_t(1),
- std::array<const char *, 1>{"xyz.openbmc_project.Software.Version"});
- }
+ };
+
+ fwUpdateMatcher = std::make_unique<sdbusplus::bus::match::match>(
+ *crow::connections::systemBus,
+ "interface='org.freedesktop.DBus.ObjectManager',type='signal',"
+ "member='InterfacesAdded',path='/xyz/openbmc_project/software'",
+ callback);
+
+ std::string filepath(
+ "/tmp/images/" +
+ boost::uuids::to_string(boost::uuids::random_generator()()));
+ BMCWEB_LOG_DEBUG << "Writing file to " << filepath;
+ std::ofstream out(filepath, std::ofstream::out | std::ofstream::binary |
+ std::ofstream::trunc);
+ out << req.body;
+ out.close();
+ BMCWEB_LOG_DEBUG << "file upload complete!!";
+ }
};
-class SoftwareInventory : public Node {
- public:
- template <typename CrowApp>
- SoftwareInventory(CrowApp &app)
- : Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/",
- std::string()) {
- Node::json["@odata.type"] = "#SoftwareInventory.v1_1_0.SoftwareInventory";
- Node::json["@odata.context"] =
- "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory";
- Node::json["Name"] = "Software Inventory";
- Node::json["Updateable"] = false;
- Node::json["Status"]["Health"] = "OK";
- Node::json["Status"]["HealthRollup"] = "OK";
- Node::json["Status"]["State"] = "Enabled";
- entityPrivileges = {
- {boost::beast::http::verb::get, {{"Login"}}},
- {boost::beast::http::verb::head, {{"Login"}}},
- {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
- {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
- }
-
- private:
- void doGet(crow::Response &res, const crow::Request &req,
- const std::vector<std::string> &params) override {
- std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
- res.jsonValue = Node::json;
-
- if (params.size() != 1) {
- res.result(boost::beast::http::status::internal_server_error);
- res.jsonValue = messages::internalError();
- res.end();
- return;
+class SoftwareInventoryCollection : public Node
+{
+ public:
+ template <typename CrowApp>
+ SoftwareInventoryCollection(CrowApp &app) :
+ Node(app, "/redfish/v1/UpdateService/FirmwareInventory/")
+ {
+ Node::json["@odata.type"] =
+ "#SoftwareInventoryCollection.SoftwareInventoryCollection";
+ Node::json["@odata.id"] = "/redfish/v1/UpdateService/FirmwareInventory";
+ Node::json["@odata.context"] =
+ "/redfish/v1/"
+ "$metadata#SoftwareInventoryCollection.SoftwareInventoryCollection";
+ Node::json["Name"] = "Software Inventory Collection";
+
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
}
- std::shared_ptr<std::string> sw_id =
- std::make_shared<std::string>(params[0]);
+ private:
+ void doGet(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> &params) override
+ {
+ std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
+ res.jsonValue = Node::json;
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](
+ const boost::system::error_code ec,
+ const std::vector<std::pair<
+ std::string, std::vector<std::pair<
+ std::string, std::vector<std::string>>>>>
+ &subtree) {
+ if (ec)
+ {
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
+ return;
+ }
+ asyncResp->res.jsonValue["Members"] = nlohmann::json::array();
+ asyncResp->res.jsonValue["Members@odata.count"] = 0;
+
+ for (auto &obj : subtree)
+ {
+ const std::vector<
+ std::pair<std::string, std::vector<std::string>>>
+ &connections = obj.second;
+
+ for (auto &conn : connections)
+ {
+ const std::string &connectionName = conn.first;
+ BMCWEB_LOG_DEBUG << "connectionName = "
+ << connectionName;
+ BMCWEB_LOG_DEBUG << "obj.first = " << obj.first;
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp](
+ const boost::system::error_code error_code,
+ const VariantType &activation) {
+ BMCWEB_LOG_DEBUG
+ << "safe returned in lambda function";
+ if (error_code)
+ {
+ asyncResp->res.result(
+ boost::beast::http::status::
+ internal_server_error);
+ return;
+ }
+
+ const std::string *sw_inv_purpose =
+ mapbox::getPtr<const std::string>(
+ activation);
+ if (sw_inv_purpose == nullptr)
+ {
+ asyncResp->res.result(
+ boost::beast::http::status::
+ internal_server_error);
+ return;
+ }
+ std::size_t last_pos =
+ sw_inv_purpose->rfind(".");
+ if (last_pos == std::string::npos)
+ {
+ asyncResp->res.result(
+ boost::beast::http::status::
+ internal_server_error);
+ return;
+ }
+ nlohmann::json &members =
+ asyncResp->res.jsonValue["Members"];
+ members.push_back(
+ {{"@odata.id", "/redfish/v1/UpdateService/"
+ "FirmwareInventory/" +
+ sw_inv_purpose->substr(
+ last_pos + 1)}});
+ asyncResp->res
+ .jsonValue["Members@odata.count"] =
+ members.size();
+ },
+ connectionName, obj.first,
+ "org.freedesktop.DBus.Properties", "Get",
+ "xyz.openbmc_project.Software.Activation",
+ "Activation");
+ }
+ }
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
+ "/xyz/openbmc_project/software", int32_t(1),
+ std::array<const char *, 1>{
+ "xyz.openbmc_project.Software.Version"});
+ }
+};
- res.jsonValue["@odata.id"] =
- "/redfish/v1/UpdateService/FirmwareInventory/" + *sw_id;
+class SoftwareInventory : public Node
+{
+ public:
+ template <typename CrowApp>
+ SoftwareInventory(CrowApp &app) :
+ Node(app, "/redfish/v1/UpdateService/FirmwareInventory/<str>/",
+ std::string())
+ {
+ Node::json["@odata.type"] =
+ "#SoftwareInventory.v1_1_0.SoftwareInventory";
+ Node::json["@odata.context"] =
+ "/redfish/v1/$metadata#SoftwareInventory.SoftwareInventory";
+ Node::json["Name"] = "Software Inventory";
+ Node::json["Updateable"] = false;
+ Node::json["Status"]["Health"] = "OK";
+ Node::json["Status"]["HealthRollup"] = "OK";
+ Node::json["Status"]["State"] = "Enabled";
+ entityPrivileges = {
+ {boost::beast::http::verb::get, {{"Login"}}},
+ {boost::beast::http::verb::head, {{"Login"}}},
+ {boost::beast::http::verb::patch, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::put, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::delete_, {{"ConfigureComponents"}}},
+ {boost::beast::http::verb::post, {{"ConfigureComponents"}}}};
+ }
- crow::connections::systemBus->async_method_call(
- [asyncResp, sw_id](
- const boost::system::error_code ec,
- const std::vector<std::pair<
- std::string,
- std::vector<std::pair<std::string, std::vector<std::string>>>>>
- &subtree) {
- BMCWEB_LOG_DEBUG << "doGet callback...";
- if (ec) {
- asyncResp->res.result(
- boost::beast::http::status::internal_server_error);
+ private:
+ void doGet(crow::Response &res, const crow::Request &req,
+ const std::vector<std::string> &params) override
+ {
+ std::shared_ptr<AsyncResp> asyncResp = std::make_shared<AsyncResp>(res);
+ res.jsonValue = Node::json;
+
+ if (params.size() != 1)
+ {
+ res.result(boost::beast::http::status::internal_server_error);
+ res.jsonValue = messages::internalError();
+ res.end();
return;
- }
-
- for (const std::pair<std::string,
- std::vector<std::pair<std::string,
- std::vector<std::string>>>>
- &obj : subtree) {
- if (boost::ends_with(obj.first, *sw_id) != true) {
- continue;
- }
-
- if (obj.second.size() <= 1) {
- continue;
- }
+ }
- crow::connections::systemBus->async_method_call(
- [asyncResp, sw_id](
- const boost::system::error_code error_code,
- const boost::container::flat_map<std::string, VariantType>
- &propertiesList) {
- if (error_code) {
+ std::shared_ptr<std::string> sw_id =
+ std::make_shared<std::string>(params[0]);
+
+ res.jsonValue["@odata.id"] =
+ "/redfish/v1/UpdateService/FirmwareInventory/" + *sw_id;
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp, sw_id](
+ const boost::system::error_code ec,
+ const std::vector<std::pair<
+ std::string, std::vector<std::pair<
+ std::string, std::vector<std::string>>>>>
+ &subtree) {
+ BMCWEB_LOG_DEBUG << "doGet callback...";
+ if (ec)
+ {
asyncResp->res.result(
boost::beast::http::status::internal_server_error);
return;
- }
- boost::container::flat_map<std::string,
- VariantType>::const_iterator it =
- propertiesList.find("Purpose");
- if (it == propertiesList.end()) {
- BMCWEB_LOG_DEBUG << "Can't find property \"Purpose\"!";
- asyncResp->res.result(
- boost::beast::http::status::internal_server_error);
- return;
- }
- const std::string *sw_inv_purpose =
- mapbox::getPtr<const std::string>(it->second);
- if (sw_inv_purpose == nullptr) {
- BMCWEB_LOG_DEBUG << "wrong types for property\"Purpose\"!";
- asyncResp->res.result(
- boost::beast::http::status::internal_server_error);
- return;
- }
-
- BMCWEB_LOG_DEBUG << "sw_inv_purpose = " << *sw_inv_purpose;
- if (boost::ends_with(*sw_inv_purpose, "." + *sw_id)) {
- it = propertiesList.find("Version");
- if (it == propertiesList.end()) {
- BMCWEB_LOG_DEBUG << "Can't find property \"Version\"!";
- asyncResp->res.result(
- boost::beast::http::status::internal_server_error);
- return;
+ }
+
+ for (const std::pair<
+ std::string,
+ std::vector<
+ std::pair<std::string, std::vector<std::string>>>>
+ &obj : subtree)
+ {
+ if (boost::ends_with(obj.first, *sw_id) != true)
+ {
+ continue;
}
- const std::string *version =
- mapbox::getPtr<const std::string>(it->second);
-
- if (version != nullptr) {
- BMCWEB_LOG_DEBUG << "Can't find property \"Version\"!";
- asyncResp->res.result(
- boost::beast::http::status::internal_server_error);
- return;
+ if (obj.second.size() <= 1)
+ {
+ continue;
}
- asyncResp->res.jsonValue["Version"] = *version;
- asyncResp->res.jsonValue["Id"] = *sw_id;
- }
- },
- obj.second[0].first, obj.first,
- "org.freedesktop.DBus.Properties", "GetAll",
- "xyz.openbmc_project.Software.Version");
- }
- },
- "xyz.openbmc_project.ObjectMapper",
- "/xyz/openbmc_project/object_mapper",
- "xyz.openbmc_project.ObjectMapper", "GetSubTree",
- "/xyz/openbmc_project/software", int32_t(1),
- std::array<const char *, 1>{"xyz.openbmc_project.Software.Version"});
- }
+
+ crow::connections::systemBus->async_method_call(
+ [asyncResp,
+ sw_id](const boost::system::error_code error_code,
+ const boost::container::flat_map<
+ std::string, VariantType> &propertiesList) {
+ if (error_code)
+ {
+ asyncResp->res.result(
+ boost::beast::http::status::
+ internal_server_error);
+ return;
+ }
+ boost::container::flat_map<
+ std::string, VariantType>::const_iterator it =
+ propertiesList.find("Purpose");
+ if (it == propertiesList.end())
+ {
+ BMCWEB_LOG_DEBUG
+ << "Can't find property \"Purpose\"!";
+ asyncResp->res.result(
+ boost::beast::http::status::
+ internal_server_error);
+ return;
+ }
+ const std::string *sw_inv_purpose =
+ mapbox::getPtr<const std::string>(it->second);
+ if (sw_inv_purpose == nullptr)
+ {
+ BMCWEB_LOG_DEBUG
+ << "wrong types for property\"Purpose\"!";
+ asyncResp->res.result(
+ boost::beast::http::status::
+ internal_server_error);
+ return;
+ }
+
+ BMCWEB_LOG_DEBUG << "sw_inv_purpose = "
+ << *sw_inv_purpose;
+ if (boost::ends_with(*sw_inv_purpose, "." + *sw_id))
+ {
+ it = propertiesList.find("Version");
+ if (it == propertiesList.end())
+ {
+ BMCWEB_LOG_DEBUG
+ << "Can't find property \"Version\"!";
+ asyncResp->res.result(
+ boost::beast::http::status::
+ internal_server_error);
+ return;
+ }
+
+ const std::string *version =
+ mapbox::getPtr<const std::string>(
+ it->second);
+
+ if (version != nullptr)
+ {
+ BMCWEB_LOG_DEBUG
+ << "Can't find property \"Version\"!";
+ asyncResp->res.result(
+ boost::beast::http::status::
+ internal_server_error);
+ return;
+ }
+ asyncResp->res.jsonValue["Version"] = *version;
+ asyncResp->res.jsonValue["Id"] = *sw_id;
+ }
+ },
+ obj.second[0].first, obj.first,
+ "org.freedesktop.DBus.Properties", "GetAll",
+ "xyz.openbmc_project.Software.Version");
+ }
+ },
+ "xyz.openbmc_project.ObjectMapper",
+ "/xyz/openbmc_project/object_mapper",
+ "xyz.openbmc_project.ObjectMapper", "GetSubTree",
+ "/xyz/openbmc_project/software", int32_t(1),
+ std::array<const char *, 1>{
+ "xyz.openbmc_project.Software.Version"});
+ }
};
-} // namespace redfish
+} // namespace redfish
diff --git a/redfish-core/src/error_messages.cpp b/redfish-core/src/error_messages.cpp
index 4773e3d8a7..a8077629ac 100644
--- a/redfish-core/src/error_messages.cpp
+++ b/redfish-core/src/error_messages.cpp
@@ -13,78 +13,93 @@
// See the License for the specific language governing permissions and
// limitations under the License.
*/
-#include <error_messages.hpp>
#include <crow/logging.h>
-namespace redfish {
+#include <error_messages.hpp>
-namespace messages {
+namespace redfish
+{
-void addMessageToErrorJson(nlohmann::json& target,
- const nlohmann::json& message) {
- auto& error = target["error"];
-
- // If this is the first error message, fill in the information from the first
- // error message to the top level struct
- if (!error.is_object()) {
- auto message_id_iterator = message.find("MessageId");
- if (message_id_iterator == message.end()) {
- BMCWEB_LOG_CRITICAL << "Attempt to add error message without MessageId";
- return;
- }
+namespace messages
+{
- auto message_field_iterator = message.find("Message");
- if (message_field_iterator == message.end()) {
- BMCWEB_LOG_CRITICAL << "Attempt to add error message without Message";
- return;
- }
- // clang-format off
+void addMessageToErrorJson(nlohmann::json& target,
+ const nlohmann::json& message)
+{
+ auto& error = target["error"];
+
+ // If this is the first error message, fill in the information from the
+ // first error message to the top level struct
+ if (!error.is_object())
+ {
+ auto message_id_iterator = message.find("MessageId");
+ if (message_id_iterator == message.end())
+ {
+ BMCWEB_LOG_CRITICAL
+ << "Attempt to add error message without MessageId";
+ return;
+ }
+
+ auto message_field_iterator = message.find("Message");
+ if (message_field_iterator == message.end())
+ {
+ BMCWEB_LOG_CRITICAL
+ << "Attempt to add error message without Message";
+ return;
+ }
+ // clang-format off
error = {
{"code", *message_id_iterator},
{"message", *message_field_iterator}
};
- // clang-format on
- } else {
- // More than 1 error occurred, so the message has to be generic
- error["code"] = std::string(messageVersionPrefix) + "GeneralError";
- error["message"] =
- "A general error has occurred. See ExtendedInfo for more"
- "information.";
- }
-
- // This check could technically be done in in the default construction
- // branch above, but because we need the pointer to the extended info field
- // anyway, it's more efficient to do it here.
- auto& extended_info = error[messages::messageAnnotation];
- if (!extended_info.is_array()) {
- extended_info = nlohmann::json::array();
- }
-
- extended_info.push_back(message);
+ // clang-format on
+ }
+ else
+ {
+ // More than 1 error occurred, so the message has to be generic
+ error["code"] = std::string(messageVersionPrefix) + "GeneralError";
+ error["message"] =
+ "A general error has occurred. See ExtendedInfo for more"
+ "information.";
+ }
+
+ // This check could technically be done in in the default construction
+ // branch above, but because we need the pointer to the extended info field
+ // anyway, it's more efficient to do it here.
+ auto& extended_info = error[messages::messageAnnotation];
+ if (!extended_info.is_array())
+ {
+ extended_info = nlohmann::json::array();
+ }
+
+ extended_info.push_back(message);
}
-void addMessageToJsonRoot(nlohmann::json& target,
- const nlohmann::json& message) {
- if (!target[messages::messageAnnotation].is_array()) {
- // Force object to be an array
- target[messages::messageAnnotation] = nlohmann::json::array();
- }
+void addMessageToJsonRoot(nlohmann::json& target, const nlohmann::json& message)
+{
+ if (!target[messages::messageAnnotation].is_array())
+ {
+ // Force object to be an array
+ target[messages::messageAnnotation] = nlohmann::json::array();
+ }
- target[messages::messageAnnotation].push_back(message);
+ target[messages::messageAnnotation].push_back(message);
}
void addMessageToJson(nlohmann::json& target, const nlohmann::json& message,
- const std::string& fieldPath) {
- nlohmann::json_pointer<nlohmann::json> extendedInfo(
- fieldPath + messages::messageAnnotation);
-
- if (!target[extendedInfo].is_array()) {
- // Force object to be an array
- target[extendedInfo] = nlohmann::json::array();
- }
+ const std::string& fieldPath)
+{
+ nlohmann::json_pointer<nlohmann::json> extendedInfo(
+ fieldPath + messages::messageAnnotation);
+
+ if (!target[extendedInfo].is_array())
+ {
+ // Force object to be an array
+ target[extendedInfo] = nlohmann::json::array();
+ }
- // Object exists and it is an array so we can just push in the message
- target[extendedInfo].push_back(message);
+ // Object exists and it is an array so we can just push in the message
+ target[extendedInfo].push_back(message);
}
/*********************************
@@ -98,17 +113,18 @@ void addMessageToJson(nlohmann::json& target, const nlohmann::json& message,
* See header file for more information
* @endinternal
*/
-nlohmann::json resourceInUse() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.ResourceInUse"},
- {"Message",
- "The change to the requested resource failed because the resource is in "
- "use or in transition."},
- {"Severity", "Warning"},
- {"Resolution",
- "Remove the condition and resubmit the request if the operation "
- "failed."}};
+nlohmann::json resourceInUse()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.ResourceInUse"},
+ {"Message", "The change to the requested resource failed because the "
+ "resource is in "
+ "use or in transition."},
+ {"Severity", "Warning"},
+ {"Resolution",
+ "Remove the condition and resubmit the request if the operation "
+ "failed."}};
}
/**
@@ -118,16 +134,17 @@ nlohmann::json resourceInUse() {
* See header file for more information
* @endinternal
*/
-nlohmann::json malformedJSON() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.MalformedJSON"},
- {"Message",
- "The request body submitted was malformed JSON and could not be parsed "
- "by the receiving service."},
- {"Severity", "Critical"},
- {"Resolution",
- "Ensure that the request body is valid JSON and resubmit the request."}};
+nlohmann::json malformedJSON()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.MalformedJSON"},
+ {"Message", "The request body submitted was malformed JSON and could "
+ "not be parsed "
+ "by the receiving service."},
+ {"Severity", "Critical"},
+ {"Resolution", "Ensure that the request body is valid JSON and "
+ "resubmit the request."}};
}
/**
@@ -137,15 +154,16 @@ nlohmann::json malformedJSON() {
* See header file for more information
* @endinternal
*/
-nlohmann::json resourceMissingAtURI(const std::string& arg1) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.ResourceMissingAtURI"},
- {"Message", "The resource at the URI " + arg1 + " was not found."},
- {"Severity", "Critical"},
- {"Resolution",
- "Place a valid resource at the URI or correct the URI and resubmit the "
- "request."}};
+nlohmann::json resourceMissingAtURI(const std::string& arg1)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.ResourceMissingAtURI"},
+ {"Message", "The resource at the URI " + arg1 + " was not found."},
+ {"Severity", "Critical"},
+ {"Resolution", "Place a valid resource at the URI or correct the URI "
+ "and resubmit the "
+ "request."}};
}
/**
@@ -157,17 +175,19 @@ nlohmann::json resourceMissingAtURI(const std::string& arg1) {
*/
nlohmann::json actionParameterValueFormatError(const std::string& arg1,
const std::string& arg2,
- const std::string& arg3) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.ActionParameterValueFormatError"},
- {"Message",
- "The value " + arg1 + " for the parameter " + arg2 + " in the action " +
- arg3 + " is of a different format than the parameter can accept."},
- {"Severity", "Warning"},
- {"Resolution",
- "Correct the value for the parameter in the request body and resubmit "
- "the request if the operation failed."}};
+ const std::string& arg3)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.ActionParameterValueFormatError"},
+ {"Message",
+ "The value " + arg1 + " for the parameter " + arg2 +
+ " in the action " + arg3 +
+ " is of a different format than the parameter can accept."},
+ {"Severity", "Warning"},
+ {"Resolution",
+ "Correct the value for the parameter in the request body and resubmit "
+ "the request if the operation failed."}};
}
/**
@@ -177,17 +197,18 @@ nlohmann::json actionParameterValueFormatError(const std::string& arg1,
* See header file for more information
* @endinternal
*/
-nlohmann::json internalError() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.InternalError"},
- {"Message",
- "The request failed due to an internal service error. The service is "
- "still operational."},
- {"Severity", "Critical"},
- {"Resolution",
- "Resubmit the request. If the problem persists, consider resetting the "
- "service."}};
+nlohmann::json internalError()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.InternalError"},
+ {"Message",
+ "The request failed due to an internal service error. The service is "
+ "still operational."},
+ {"Severity", "Critical"},
+ {"Resolution", "Resubmit the request. If the problem persists, "
+ "consider resetting the "
+ "service."}};
}
/**
@@ -197,16 +218,17 @@ nlohmann::json internalError() {
* See header file for more information
* @endinternal
*/
-nlohmann::json unrecognizedRequestBody() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.UnrecognizedRequestBody"},
- {"Message",
- "The service detected a malformed request body that it was unable to "
- "interpret."},
- {"Severity", "Warning"},
- {"Resolution",
- "Correct the request body and resubmit the request if it failed."}};
+nlohmann::json unrecognizedRequestBody()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.UnrecognizedRequestBody"},
+ {"Message",
+ "The service detected a malformed request body that it was unable to "
+ "interpret."},
+ {"Severity", "Warning"},
+ {"Resolution",
+ "Correct the request body and resubmit the request if it failed."}};
}
/**
@@ -217,17 +239,18 @@ nlohmann::json unrecognizedRequestBody() {
* @endinternal
*/
nlohmann::json resourceAtUriUnauthorized(const std::string& arg1,
- const std::string& arg2) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.ResourceAtUriUnauthorized"},
- {"Message", "While accessing the resource at " + arg1 +
- ", the service received an authorization error " + arg2 +
- "."},
- {"Severity", "Critical"},
- {"Resolution",
- "Ensure that the appropriate access is provided for the service in "
- "order for it to access the URI."}};
+ const std::string& arg2)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.ResourceAtUriUnauthorized"},
+ {"Message", "While accessing the resource at " + arg1 +
+ ", the service received an authorization error " +
+ arg2 + "."},
+ {"Severity", "Critical"},
+ {"Resolution",
+ "Ensure that the appropriate access is provided for the service in "
+ "order for it to access the URI."}};
}
/**
@@ -238,17 +261,18 @@ nlohmann::json resourceAtUriUnauthorized(const std::string& arg1,
* @endinternal
*/
nlohmann::json actionParameterUnknown(const std::string& arg1,
- const std::string& arg2) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.ActionParameterUnknown"},
- {"Message", "The action " + arg1 +
- " was submitted with the invalid parameter " + arg2 +
- "."},
- {"Severity", "Warning"},
- {"Resolution",
- "Correct the invalid parameter and resubmit the request if the "
- "operation failed."}};
+ const std::string& arg2)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.ActionParameterUnknown"},
+ {"Message", "The action " + arg1 +
+ " was submitted with the invalid parameter " + arg2 +
+ "."},
+ {"Severity", "Warning"},
+ {"Resolution",
+ "Correct the invalid parameter and resubmit the request if the "
+ "operation failed."}};
}
/**
@@ -258,15 +282,16 @@ nlohmann::json actionParameterUnknown(const std::string& arg1,
* See header file for more information
* @endinternal
*/
-nlohmann::json resourceCannotBeDeleted() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.ResourceCannotBeDeleted"},
- {"Message",
- "The delete request failed because the resource requested cannot be "
- "deleted."},
- {"Severity", "Critical"},
- {"Resolution", "Do not attempt to delete a non-deletable resource."}};
+nlohmann::json resourceCannotBeDeleted()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.ResourceCannotBeDeleted"},
+ {"Message",
+ "The delete request failed because the resource requested cannot be "
+ "deleted."},
+ {"Severity", "Critical"},
+ {"Resolution", "Do not attempt to delete a non-deletable resource."}};
}
/**
@@ -276,15 +301,16 @@ nlohmann::json resourceCannotBeDeleted() {
* See header file for more information
* @endinternal
*/
-nlohmann::json propertyDuplicate(const std::string& arg1) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.PropertyDuplicate"},
- {"Message", "The property " + arg1 + " was duplicated in the request."},
- {"Severity", "Warning"},
- {"Resolution",
- "Remove the duplicate property from the request body and resubmit the "
- "request if the operation failed."}};
+nlohmann::json propertyDuplicate(const std::string& arg1)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.PropertyDuplicate"},
+ {"Message", "The property " + arg1 + " was duplicated in the request."},
+ {"Severity", "Warning"},
+ {"Resolution",
+ "Remove the duplicate property from the request body and resubmit the "
+ "request if the operation failed."}};
}
/**
@@ -294,15 +320,16 @@ nlohmann::json propertyDuplicate(const std::string& arg1) {
* See header file for more information
* @endinternal
*/
-nlohmann::json serviceTemporarilyUnavailable(const std::string& arg1) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.ServiceTemporarilyUnavailable"},
- {"Message", "The service is temporarily unavailable. Retry in " + arg1 +
- " seconds."},
- {"Severity", "Critical"},
- {"Resolution",
- "Wait for the indicated retry duration and retry the operation."}};
+nlohmann::json serviceTemporarilyUnavailable(const std::string& arg1)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.ServiceTemporarilyUnavailable"},
+ {"Message", "The service is temporarily unavailable. Retry in " +
+ arg1 + " seconds."},
+ {"Severity", "Critical"},
+ {"Resolution",
+ "Wait for the indicated retry duration and retry the operation."}};
}
/**
@@ -314,17 +341,18 @@ nlohmann::json serviceTemporarilyUnavailable(const std::string& arg1) {
*/
nlohmann::json resourceAlreadyExists(const std::string& arg1,
const std::string& arg2,
- const std::string& arg3) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.ResourceAlreadyExists"},
- {"Message", "The requested resource of type " + arg1 +
- " with the property " + arg2 + " with the value " + arg3 +
- " already exists."},
- {"Severity", "Critical"},
- {"Resolution",
- "Do not repeat the create operation as the resource has already been "
- "created."}};
+ const std::string& arg3)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.ResourceAlreadyExists"},
+ {"Message", "The requested resource of type " + arg1 +
+ " with the property " + arg2 + " with the value " +
+ arg3 + " already exists."},
+ {"Severity", "Critical"},
+ {"Resolution",
+ "Do not repeat the create operation as the resource has already been "
+ "created."}};
}
/**
@@ -334,15 +362,16 @@ nlohmann::json resourceAlreadyExists(const std::string& arg1,
* See header file for more information
* @endinternal
*/
-nlohmann::json accountForSessionNoLongerExists() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.AccountForSessionNoLongerExists"},
- {"Message",
- "The account for the current session has been removed, thus the current "
- "session has been removed as well."},
- {"Severity", "OK"},
- {"Resolution", "Attempt to connect with a valid account."}};
+nlohmann::json accountForSessionNoLongerExists()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.AccountForSessionNoLongerExists"},
+ {"Message", "The account for the current session has been removed, "
+ "thus the current "
+ "session has been removed as well."},
+ {"Severity", "OK"},
+ {"Resolution", "Attempt to connect with a valid account."}};
}
/**
@@ -352,16 +381,18 @@ nlohmann::json accountForSessionNoLongerExists() {
* See header file for more information
* @endinternal
*/
-nlohmann::json createFailedMissingReqProperties(const std::string& arg1) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.CreateFailedMissingReqProperties"},
- {"Message", "The create operation failed because the required property " +
- arg1 + " was missing from the request."},
- {"Severity", "Critical"},
- {"Resolution",
- "Correct the body to include the required property with a valid value "
- "and resubmit the request if the operation failed."}};
+nlohmann::json createFailedMissingReqProperties(const std::string& arg1)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.CreateFailedMissingReqProperties"},
+ {"Message",
+ "The create operation failed because the required property " + arg1 +
+ " was missing from the request."},
+ {"Severity", "Critical"},
+ {"Resolution",
+ "Correct the body to include the required property with a valid value "
+ "and resubmit the request if the operation failed."}};
}
/**
@@ -372,17 +403,18 @@ nlohmann::json createFailedMissingReqProperties(const std::string& arg1) {
* @endinternal
*/
nlohmann::json propertyValueFormatError(const std::string& arg1,
- const std::string& arg2) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.PropertyValueFormatError"},
- {"Message",
- "The value " + arg1 + " for the property " + arg2 +
- " is of a different format than the property can accept."},
- {"Severity", "Warning"},
- {"Resolution",
- "Correct the value for the property in the request body and resubmit "
- "the request if the operation failed."}};
+ const std::string& arg2)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.PropertyValueFormatError"},
+ {"Message",
+ "The value " + arg1 + " for the property " + arg2 +
+ " is of a different format than the property can accept."},
+ {"Severity", "Warning"},
+ {"Resolution",
+ "Correct the value for the property in the request body and resubmit "
+ "the request if the operation failed."}};
}
/**
@@ -393,16 +425,17 @@ nlohmann::json propertyValueFormatError(const std::string& arg1,
* @endinternal
*/
nlohmann::json propertyValueNotInList(const std::string& arg1,
- const std::string& arg2) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.PropertyValueNotInList"},
- {"Message", "The value " + arg1 + " for the property " + arg2 +
- " is not in the list of acceptable values."},
- {"Severity", "Warning"},
- {"Resolution",
- "Choose a value from the enumeration list that the implementation can "
- "support and resubmit the request if the operation failed."}};
+ const std::string& arg2)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.PropertyValueNotInList"},
+ {"Message", "The value " + arg1 + " for the property " + arg2 +
+ " is not in the list of acceptable values."},
+ {"Severity", "Warning"},
+ {"Resolution",
+ "Choose a value from the enumeration list that the implementation can "
+ "support and resubmit the request if the operation failed."}};
}
/**
@@ -412,16 +445,17 @@ nlohmann::json propertyValueNotInList(const std::string& arg1,
* See header file for more information
* @endinternal
*/
-nlohmann::json resourceAtUriInUnknownFormat(const std::string& arg1) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.ResourceAtUriInUnknownFormat"},
- {"Message", "The resource at " + arg1 +
- " is in a format not recognized by the service."},
- {"Severity", "Critical"},
- {"Resolution",
- "Place an image or resource or file that is recognized by the service "
- "at the URI."}};
+nlohmann::json resourceAtUriInUnknownFormat(const std::string& arg1)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.ResourceAtUriInUnknownFormat"},
+ {"Message", "The resource at " + arg1 +
+ " is in a format not recognized by the service."},
+ {"Severity", "Critical"},
+ {"Resolution",
+ "Place an image or resource or file that is recognized by the service "
+ "at the URI."}};
}
/**
@@ -431,17 +465,18 @@ nlohmann::json resourceAtUriInUnknownFormat(const std::string& arg1) {
* See header file for more information
* @endinternal
*/
-nlohmann::json serviceInUnknownState() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.ServiceInUnknownState"},
- {"Message",
- "The operation failed because the service is in an unknown state and "
- "can no longer take incoming requests."},
- {"Severity", "Critical"},
- {"Resolution",
- "Restart the service and resubmit the request if the operation "
- "failed."}};
+nlohmann::json serviceInUnknownState()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.ServiceInUnknownState"},
+ {"Message",
+ "The operation failed because the service is in an unknown state and "
+ "can no longer take incoming requests."},
+ {"Severity", "Critical"},
+ {"Resolution",
+ "Restart the service and resubmit the request if the operation "
+ "failed."}};
}
/**
@@ -451,18 +486,19 @@ nlohmann::json serviceInUnknownState() {
* See header file for more information
* @endinternal
*/
-nlohmann::json eventSubscriptionLimitExceeded() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.EventSubscriptionLimitExceeded"},
- {"Message",
- "The event subscription failed due to the number of simultaneous "
- "subscriptions exceeding the limit of the implementation."},
- {"Severity", "Critical"},
- {"Resolution",
- "Reduce the number of other subscriptions before trying to establish "
- "the event subscription or increase the limit of simultaneous "
- "subscriptions (if supported)."}};
+nlohmann::json eventSubscriptionLimitExceeded()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.EventSubscriptionLimitExceeded"},
+ {"Message",
+ "The event subscription failed due to the number of simultaneous "
+ "subscriptions exceeding the limit of the implementation."},
+ {"Severity", "Critical"},
+ {"Resolution",
+ "Reduce the number of other subscriptions before trying to establish "
+ "the event subscription or increase the limit of simultaneous "
+ "subscriptions (if supported)."}};
}
/**
@@ -473,16 +509,17 @@ nlohmann::json eventSubscriptionLimitExceeded() {
* @endinternal
*/
nlohmann::json actionParameterMissing(const std::string& arg1,
- const std::string& arg2) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.ActionParameterMissing"},
- {"Message", "The action " + arg1 + " requires the parameter " + arg2 +
- " to be present in the request body."},
- {"Severity", "Critical"},
- {"Resolution",
- "Supply the action with the required parameter in the request body when "
- "the request is resubmitted."}};
+ const std::string& arg2)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.ActionParameterMissing"},
+ {"Message", "The action " + arg1 + " requires the parameter " + arg2 +
+ " to be present in the request body."},
+ {"Severity", "Critical"},
+ {"Resolution", "Supply the action with the required parameter in the "
+ "request body when "
+ "the request is resubmitted."}};
}
/**
@@ -492,15 +529,16 @@ nlohmann::json actionParameterMissing(const std::string& arg1,
* See header file for more information
* @endinternal
*/
-nlohmann::json stringValueTooLong(const std::string& arg1, const int& arg2) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.StringValueTooLong"},
- {"Message", "The string " + arg1 + " exceeds the length limit " +
- std::to_string(arg2) + "."},
- {"Severity", "Warning"},
- {"Resolution",
- "Resubmit the request with an appropriate string length."}};
+nlohmann::json stringValueTooLong(const std::string& arg1, const int& arg2)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.StringValueTooLong"},
+ {"Message", "The string " + arg1 + " exceeds the length limit " +
+ std::to_string(arg2) + "."},
+ {"Severity", "Warning"},
+ {"Resolution",
+ "Resubmit the request with an appropriate string length."}};
}
/**
@@ -511,16 +549,18 @@ nlohmann::json stringValueTooLong(const std::string& arg1, const int& arg2) {
* @endinternal
*/
nlohmann::json propertyValueTypeError(const std::string& arg1,
- const std::string& arg2) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.PropertyValueTypeError"},
- {"Message", "The value " + arg1 + " for the property " + arg2 +
- " is of a different type than the property can accept."},
- {"Severity", "Warning"},
- {"Resolution",
- "Correct the value for the property in the request body and resubmit "
- "the request if the operation failed."}};
+ const std::string& arg2)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.PropertyValueTypeError"},
+ {"Message",
+ "The value " + arg1 + " for the property " + arg2 +
+ " is of a different type than the property can accept."},
+ {"Severity", "Warning"},
+ {"Resolution",
+ "Correct the value for the property in the request body and resubmit "
+ "the request if the operation failed."}};
}
/**
@@ -531,15 +571,16 @@ nlohmann::json propertyValueTypeError(const std::string& arg1,
* @endinternal
*/
nlohmann::json resourceNotFound(const std::string& arg1,
- const std::string& arg2) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.ResourceNotFound"},
- {"Message", "The requested resource of type " + arg1 + " named " + arg2 +
- " was not found."},
- {"Severity", "Critical"},
- {"Resolution",
- "Provide a valid resource identifier and resubmit the request."}};
+ const std::string& arg2)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.ResourceNotFound"},
+ {"Message", "The requested resource of type " + arg1 + " named " +
+ arg2 + " was not found."},
+ {"Severity", "Critical"},
+ {"Resolution",
+ "Provide a valid resource identifier and resubmit the request."}};
}
/**
@@ -549,16 +590,18 @@ nlohmann::json resourceNotFound(const std::string& arg1,
* See header file for more information
* @endinternal
*/
-nlohmann::json couldNotEstablishConnection(const std::string& arg1) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.CouldNotEstablishConnection"},
- {"Message", "The service failed to establish a Connection with the URI " +
- arg1 + "."},
- {"Severity", "Critical"},
- {"Resolution",
- "Ensure that the URI contains a valid and reachable node name, protocol "
- "information and other URI components."}};
+nlohmann::json couldNotEstablishConnection(const std::string& arg1)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.CouldNotEstablishConnection"},
+ {"Message",
+ "The service failed to establish a Connection with the URI " + arg1 +
+ "."},
+ {"Severity", "Critical"},
+ {"Resolution", "Ensure that the URI contains a valid and reachable "
+ "node name, protocol "
+ "information and other URI components."}};
}
/**
@@ -568,17 +611,18 @@ nlohmann::json couldNotEstablishConnection(const std::string& arg1) {
* See header file for more information
* @endinternal
*/
-nlohmann::json propertyNotWritable(const std::string& arg1) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.PropertyNotWritable"},
- {"Message",
- "The property " + arg1 +
- " is a read only property and cannot be assigned a value."},
- {"Severity", "Warning"},
- {"Resolution",
- "Remove the property from the request body and resubmit the request if "
- "the operation failed."}};
+nlohmann::json propertyNotWritable(const std::string& arg1)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.PropertyNotWritable"},
+ {"Message",
+ "The property " + arg1 +
+ " is a read only property and cannot be assigned a value."},
+ {"Severity", "Warning"},
+ {"Resolution", "Remove the property from the request body and resubmit "
+ "the request if "
+ "the operation failed."}};
}
/**
@@ -589,16 +633,18 @@ nlohmann::json propertyNotWritable(const std::string& arg1) {
* @endinternal
*/
nlohmann::json queryParameterValueTypeError(const std::string& arg1,
- const std::string& arg2) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.QueryParameterValueTypeError"},
- {"Message", "The value " + arg1 + " for the query parameter " + arg2 +
- " is of a different type than the parameter can accept."},
- {"Severity", "Warning"},
- {"Resolution",
- "Correct the value for the query parameter in the request and resubmit "
- "the request if the operation failed."}};
+ const std::string& arg2)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.QueryParameterValueTypeError"},
+ {"Message",
+ "The value " + arg1 + " for the query parameter " + arg2 +
+ " is of a different type than the parameter can accept."},
+ {"Severity", "Warning"},
+ {"Resolution", "Correct the value for the query parameter in the "
+ "request and resubmit "
+ "the request if the operation failed."}};
}
/**
@@ -608,17 +654,18 @@ nlohmann::json queryParameterValueTypeError(const std::string& arg1,
* See header file for more information
* @endinternal
*/
-nlohmann::json serviceShuttingDown() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.ServiceShuttingDown"},
- {"Message",
- "The operation failed because the service is shutting down and can no "
- "longer take incoming requests."},
- {"Severity", "Critical"},
- {"Resolution",
- "When the service becomes available, resubmit the request if the "
- "operation failed."}};
+nlohmann::json serviceShuttingDown()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.ServiceShuttingDown"},
+ {"Message",
+ "The operation failed because the service is shutting down and can no "
+ "longer take incoming requests."},
+ {"Severity", "Critical"},
+ {"Resolution",
+ "When the service becomes available, resubmit the request if the "
+ "operation failed."}};
}
/**
@@ -629,18 +676,19 @@ nlohmann::json serviceShuttingDown() {
* @endinternal
*/
nlohmann::json actionParameterDuplicate(const std::string& arg1,
- const std::string& arg2) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.ActionParameterDuplicate"},
- {"Message",
- "The action " + arg1 +
- " was submitted with more than one value for the parameter " + arg2 +
- "."},
- {"Severity", "Warning"},
- {"Resolution",
- "Resubmit the action with only one instance of the parameter in the "
- "request body if the operation failed."}};
+ const std::string& arg2)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.ActionParameterDuplicate"},
+ {"Message",
+ "The action " + arg1 +
+ " was submitted with more than one value for the parameter " +
+ arg2 + "."},
+ {"Severity", "Warning"},
+ {"Resolution",
+ "Resubmit the action with only one instance of the parameter in the "
+ "request body if the operation failed."}};
}
/**
@@ -651,16 +699,17 @@ nlohmann::json actionParameterDuplicate(const std::string& arg1,
* @endinternal
*/
nlohmann::json actionParameterNotSupported(const std::string& arg1,
- const std::string& arg2) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.ActionParameterNotSupported"},
- {"Message", "The parameter " + arg1 + " for the action " + arg2 +
- " is not supported on the target resource."},
- {"Severity", "Warning"},
- {"Resolution",
- "Remove the parameter supplied and resubmit the request if the "
- "operation failed."}};
+ const std::string& arg2)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.ActionParameterNotSupported"},
+ {"Message", "The parameter " + arg1 + " for the action " + arg2 +
+ " is not supported on the target resource."},
+ {"Severity", "Warning"},
+ {"Resolution",
+ "Remove the parameter supplied and resubmit the request if the "
+ "operation failed."}};
}
/**
@@ -671,14 +720,16 @@ nlohmann::json actionParameterNotSupported(const std::string& arg1,
* @endinternal
*/
nlohmann::json sourceDoesNotSupportProtocol(const std::string& arg1,
- const std::string& arg2) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.SourceDoesNotSupportProtocol"},
- {"Message", "The other end of the Connection at " + arg1 +
- " does not support the specified protocol " + arg2 + "."},
- {"Severity", "Critical"},
- {"Resolution", "Change protocols or URIs. "}};
+ const std::string& arg2)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.SourceDoesNotSupportProtocol"},
+ {"Message", "The other end of the Connection at " + arg1 +
+ " does not support the specified protocol " + arg2 +
+ "."},
+ {"Severity", "Critical"},
+ {"Resolution", "Change protocols or URIs. "}};
}
/**
@@ -688,13 +739,14 @@ nlohmann::json sourceDoesNotSupportProtocol(const std::string& arg1,
* See header file for more information
* @endinternal
*/
-nlohmann::json accountRemoved() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.AccountRemoved"},
- {"Message", "The account was successfully removed."},
- {"Severity", "OK"},
- {"Resolution", "No resolution is required."}};
+nlohmann::json accountRemoved()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.AccountRemoved"},
+ {"Message", "The account was successfully removed."},
+ {"Severity", "OK"},
+ {"Resolution", "No resolution is required."}};
}
/**
@@ -704,16 +756,17 @@ nlohmann::json accountRemoved() {
* See header file for more information
* @endinternal
*/
-nlohmann::json accessDenied(const std::string& arg1) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.AccessDenied"},
- {"Message", "While attempting to establish a Connection to " + arg1 +
- ", the service denied access."},
- {"Severity", "Critical"},
- {"Resolution",
- "Attempt to ensure that the URI is correct and that the service has the "
- "appropriate credentials."}};
+nlohmann::json accessDenied(const std::string& arg1)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.AccessDenied"},
+ {"Message", "While attempting to establish a Connection to " + arg1 +
+ ", the service denied access."},
+ {"Severity", "Critical"},
+ {"Resolution", "Attempt to ensure that the URI is correct and that the "
+ "service has the "
+ "appropriate credentials."}};
}
/**
@@ -723,15 +776,16 @@ nlohmann::json accessDenied(const std::string& arg1) {
* See header file for more information
* @endinternal
*/
-nlohmann::json queryNotSupported() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.QueryNotSupported"},
- {"Message", "Querying is not supported by the implementation."},
- {"Severity", "Warning"},
- {"Resolution",
- "Remove the query parameters and resubmit the request if the operation "
- "failed."}};
+nlohmann::json queryNotSupported()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.QueryNotSupported"},
+ {"Message", "Querying is not supported by the implementation."},
+ {"Severity", "Warning"},
+ {"Resolution", "Remove the query parameters and resubmit the request "
+ "if the operation "
+ "failed."}};
}
/**
@@ -741,17 +795,18 @@ nlohmann::json queryNotSupported() {
* See header file for more information
* @endinternal
*/
-nlohmann::json createLimitReachedForResource() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.CreateLimitReachedForResource"},
- {"Message",
- "The create operation failed because the resource has reached the limit "
- "of possible resources."},
- {"Severity", "Critical"},
- {"Resolution",
- "Either delete resources and resubmit the request if the operation "
- "failed or do not resubmit the request."}};
+nlohmann::json createLimitReachedForResource()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.CreateLimitReachedForResource"},
+ {"Message", "The create operation failed because the resource has "
+ "reached the limit "
+ "of possible resources."},
+ {"Severity", "Critical"},
+ {"Resolution",
+ "Either delete resources and resubmit the request if the operation "
+ "failed or do not resubmit the request."}};
}
/**
@@ -761,14 +816,15 @@ nlohmann::json createLimitReachedForResource() {
* See header file for more information
* @endinternal
*/
-nlohmann::json generalError() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.GeneralError"},
- {"Message",
- "A general error has occurred. See ExtendedInfo for more information."},
- {"Severity", "Critical"},
- {"Resolution", "See ExtendedInfo for more information."}};
+nlohmann::json generalError()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.GeneralError"},
+ {"Message", "A general error has occurred. See ExtendedInfo for more "
+ "information."},
+ {"Severity", "Critical"},
+ {"Resolution", "See ExtendedInfo for more information."}};
}
/**
@@ -778,13 +834,14 @@ nlohmann::json generalError() {
* See header file for more information
* @endinternal
*/
-nlohmann::json success() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.Success"},
- {"Message", "Successfully Completed Request"},
- {"Severity", "OK"},
- {"Resolution", "None"}};
+nlohmann::json success()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.Success"},
+ {"Message", "Successfully Completed Request"},
+ {"Severity", "OK"},
+ {"Resolution", "None"}};
}
/**
@@ -794,13 +851,14 @@ nlohmann::json success() {
* See header file for more information
* @endinternal
*/
-nlohmann::json created() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.Created"},
- {"Message", "The resource has been created successfully"},
- {"Severity", "OK"},
- {"Resolution", "None"}};
+nlohmann::json created()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.Created"},
+ {"Message", "The resource has been created successfully"},
+ {"Severity", "OK"},
+ {"Resolution", "None"}};
}
/**
@@ -810,17 +868,18 @@ nlohmann::json created() {
* See header file for more information
* @endinternal
*/
-nlohmann::json propertyUnknown(const std::string& arg1) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.PropertyUnknown"},
- {"Message",
- "The property " + arg1 +
- " is not in the list of valid properties for the resource."},
- {"Severity", "Warning"},
- {"Resolution",
- "Remove the unknown property from the request body and resubmit the "
- "request if the operation failed."}};
+nlohmann::json propertyUnknown(const std::string& arg1)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.PropertyUnknown"},
+ {"Message",
+ "The property " + arg1 +
+ " is not in the list of valid properties for the resource."},
+ {"Severity", "Warning"},
+ {"Resolution",
+ "Remove the unknown property from the request body and resubmit the "
+ "request if the operation failed."}};
}
/**
@@ -830,14 +889,16 @@ nlohmann::json propertyUnknown(const std::string& arg1) {
* See header file for more information
* @endinternal
*/
-nlohmann::json noValidSession() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.NoValidSession"},
- {"Message",
- "There is no valid session established with the implementation."},
- {"Severity", "Critical"},
- {"Resolution", "Establish as session before attempting any operations."}};
+nlohmann::json noValidSession()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.NoValidSession"},
+ {"Message",
+ "There is no valid session established with the implementation."},
+ {"Severity", "Critical"},
+ {"Resolution",
+ "Establish as session before attempting any operations."}};
}
/**
@@ -847,15 +908,16 @@ nlohmann::json noValidSession() {
* See header file for more information
* @endinternal
*/
-nlohmann::json invalidObject(const std::string& arg1) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.InvalidObject"},
- {"Message", "The object at " + arg1 + " is invalid."},
- {"Severity", "Critical"},
- {"Resolution",
- "Either the object is malformed or the URI is not correct. Correct the "
- "condition and resubmit the request if it failed."}};
+nlohmann::json invalidObject(const std::string& arg1)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.InvalidObject"},
+ {"Message", "The object at " + arg1 + " is invalid."},
+ {"Severity", "Critical"},
+ {"Resolution", "Either the object is malformed or the URI is not "
+ "correct. Correct the "
+ "condition and resubmit the request if it failed."}};
}
/**
@@ -865,17 +927,18 @@ nlohmann::json invalidObject(const std::string& arg1) {
* See header file for more information
* @endinternal
*/
-nlohmann::json resourceInStandby() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.ResourceInStandby"},
- {"Message",
- "The request could not be performed because the resource is in "
- "standby."},
- {"Severity", "Critical"},
- {"Resolution",
- "Ensure that the resource is in the correct power state and resubmit "
- "the request."}};
+nlohmann::json resourceInStandby()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.ResourceInStandby"},
+ {"Message",
+ "The request could not be performed because the resource is in "
+ "standby."},
+ {"Severity", "Critical"},
+ {"Resolution",
+ "Ensure that the resource is in the correct power state and resubmit "
+ "the request."}};
}
/**
@@ -887,17 +950,19 @@ nlohmann::json resourceInStandby() {
*/
nlohmann::json actionParameterValueTypeError(const std::string& arg1,
const std::string& arg2,
- const std::string& arg3) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.ActionParameterValueTypeError"},
- {"Message", "The value " + arg1 + " for the parameter " + arg2 +
- " in the action " + arg3 +
- " is of a different type than the parameter can accept."},
- {"Severity", "Warning"},
- {"Resolution",
- "Correct the value for the parameter in the request body and resubmit "
- "the request if the operation failed."}};
+ const std::string& arg3)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.ActionParameterValueTypeError"},
+ {"Message",
+ "The value " + arg1 + " for the parameter " + arg2 +
+ " in the action " + arg3 +
+ " is of a different type than the parameter can accept."},
+ {"Severity", "Warning"},
+ {"Resolution",
+ "Correct the value for the parameter in the request body and resubmit "
+ "the request if the operation failed."}};
}
/**
@@ -907,18 +972,19 @@ nlohmann::json actionParameterValueTypeError(const std::string& arg1,
* See header file for more information
* @endinternal
*/
-nlohmann::json sessionLimitExceeded() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.SessionLimitExceeded"},
- {"Message",
- "The session establishment failed due to the number of simultaneous "
- "sessions exceeding the limit of the implementation."},
- {"Severity", "Critical"},
- {"Resolution",
- "Reduce the number of other sessions before trying to establish the "
- "session or increase the limit of simultaneous sessions (if "
- "supported)."}};
+nlohmann::json sessionLimitExceeded()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.SessionLimitExceeded"},
+ {"Message",
+ "The session establishment failed due to the number of simultaneous "
+ "sessions exceeding the limit of the implementation."},
+ {"Severity", "Critical"},
+ {"Resolution",
+ "Reduce the number of other sessions before trying to establish the "
+ "session or increase the limit of simultaneous sessions (if "
+ "supported)."}};
}
/**
@@ -928,16 +994,18 @@ nlohmann::json sessionLimitExceeded() {
* See header file for more information
* @endinternal
*/
-nlohmann::json actionNotSupported(const std::string& arg1) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.ActionNotSupported"},
- {"Message", "The action " + arg1 + " is not supported by the resource."},
- {"Severity", "Critical"},
- {"Resolution",
- "The action supplied cannot be resubmitted to the implementation. "
- "Perhaps the action was invalid, the wrong resource was the target or "
- "the implementation documentation may be of assistance."}};
+nlohmann::json actionNotSupported(const std::string& arg1)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.ActionNotSupported"},
+ {"Message",
+ "The action " + arg1 + " is not supported by the resource."},
+ {"Severity", "Critical"},
+ {"Resolution",
+ "The action supplied cannot be resubmitted to the implementation. "
+ "Perhaps the action was invalid, the wrong resource was the target or "
+ "the implementation documentation may be of assistance."}};
}
/**
@@ -947,15 +1015,16 @@ nlohmann::json actionNotSupported(const std::string& arg1) {
* See header file for more information
* @endinternal
*/
-nlohmann::json invalidIndex(const int& arg1) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.InvalidIndex"},
- {"Message", "The index " + std::to_string(arg1) +
- " is not a valid offset into the array."},
- {"Severity", "Warning"},
- {"Resolution",
- "Verify the index value provided is within the bounds of the array."}};
+nlohmann::json invalidIndex(const int& arg1)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.InvalidIndex"},
+ {"Message", "The index " + std::to_string(arg1) +
+ " is not a valid offset into the array."},
+ {"Severity", "Warning"},
+ {"Resolution",
+ "Verify the index value provided is within the bounds of the array."}};
}
/**
@@ -965,16 +1034,17 @@ nlohmann::json invalidIndex(const int& arg1) {
* See header file for more information
* @endinternal
*/
-nlohmann::json emptyJSON() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.EmptyJSON"},
- {"Message",
- "The request body submitted contained an empty JSON object and the "
- "service is unable to process it."},
- {"Severity", "Warning"},
- {"Resolution",
- "Add properties in the JSON object and resubmit the request."}};
+nlohmann::json emptyJSON()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.EmptyJSON"},
+ {"Message",
+ "The request body submitted contained an empty JSON object and the "
+ "service is unable to process it."},
+ {"Severity", "Warning"},
+ {"Resolution",
+ "Add properties in the JSON object and resubmit the request."}};
}
/**
@@ -984,15 +1054,16 @@ nlohmann::json emptyJSON() {
* See header file for more information
* @endinternal
*/
-nlohmann::json queryNotSupportedOnResource() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.QueryNotSupportedOnResource"},
- {"Message", "Querying is not supported on the requested resource."},
- {"Severity", "Warning"},
- {"Resolution",
- "Remove the query parameters and resubmit the request if the operation "
- "failed."}};
+nlohmann::json queryNotSupportedOnResource()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.QueryNotSupportedOnResource"},
+ {"Message", "Querying is not supported on the requested resource."},
+ {"Severity", "Warning"},
+ {"Resolution", "Remove the query parameters and resubmit the request "
+ "if the operation "
+ "failed."}};
}
/**
@@ -1002,18 +1073,19 @@ nlohmann::json queryNotSupportedOnResource() {
* See header file for more information
* @endinternal
*/
-nlohmann::json insufficientPrivilege() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.InsufficientPrivilege"},
- {"Message",
- "There are insufficient privileges for the account or credentials "
- "associated with the current session to perform the requested "
- "operation."},
- {"Severity", "Critical"},
- {"Resolution",
- "Either abandon the operation or change the associated access rights "
- "and resubmit the request if the operation failed."}};
+nlohmann::json insufficientPrivilege()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.InsufficientPrivilege"},
+ {"Message",
+ "There are insufficient privileges for the account or credentials "
+ "associated with the current session to perform the requested "
+ "operation."},
+ {"Severity", "Critical"},
+ {"Resolution",
+ "Either abandon the operation or change the associated access rights "
+ "and resubmit the request if the operation failed."}};
}
/**
@@ -1024,14 +1096,15 @@ nlohmann::json insufficientPrivilege() {
* @endinternal
*/
nlohmann::json propertyValueModified(const std::string& arg1,
- const std::string& arg2) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.PropertyValueModified"},
- {"Message", "The property " + arg1 + " was assigned the value " + arg2 +
- " due to modification by the service."},
- {"Severity", "Warning"},
- {"Resolution", "No resolution is required."}};
+ const std::string& arg2)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.PropertyValueModified"},
+ {"Message", "The property " + arg1 + " was assigned the value " + arg2 +
+ " due to modification by the service."},
+ {"Severity", "Warning"},
+ {"Resolution", "No resolution is required."}};
}
/**
@@ -1041,15 +1114,16 @@ nlohmann::json propertyValueModified(const std::string& arg1,
* See header file for more information
* @endinternal
*/
-nlohmann::json accountNotModified() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.AccountNotModified"},
- {"Message", "The account modification request failed."},
- {"Severity", "Warning"},
- {"Resolution",
- "The modification may have failed due to permission issues or issues "
- "with the request body."}};
+nlohmann::json accountNotModified()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.AccountNotModified"},
+ {"Message", "The account modification request failed."},
+ {"Severity", "Warning"},
+ {"Resolution",
+ "The modification may have failed due to permission issues or issues "
+ "with the request body."}};
}
/**
@@ -1060,17 +1134,18 @@ nlohmann::json accountNotModified() {
* @endinternal
*/
nlohmann::json queryParameterValueFormatError(const std::string& arg1,
- const std::string& arg2) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.QueryParameterValueFormatError"},
- {"Message",
- "The value " + arg1 + " for the parameter " + arg2 +
- " is of a different format than the parameter can accept."},
- {"Severity", "Warning"},
- {"Resolution",
- "Correct the value for the query parameter in the request and resubmit "
- "the request if the operation failed."}};
+ const std::string& arg2)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.QueryParameterValueFormatError"},
+ {"Message",
+ "The value " + arg1 + " for the parameter " + arg2 +
+ " is of a different format than the parameter can accept."},
+ {"Severity", "Warning"},
+ {"Resolution", "Correct the value for the query parameter in the "
+ "request and resubmit "
+ "the request if the operation failed."}};
}
/**
@@ -1080,17 +1155,18 @@ nlohmann::json queryParameterValueFormatError(const std::string& arg1,
* See header file for more information
* @endinternal
*/
-nlohmann::json propertyMissing(const std::string& arg1) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.PropertyMissing"},
- {"Message",
- "The property " + arg1 +
- " is a required property and must be included in the request."},
- {"Severity", "Warning"},
- {"Resolution",
- "Ensure that the property is in the request body and has a valid value "
- "and resubmit the request if the operation failed."}};
+nlohmann::json propertyMissing(const std::string& arg1)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.PropertyMissing"},
+ {"Message",
+ "The property " + arg1 +
+ " is a required property and must be included in the request."},
+ {"Severity", "Warning"},
+ {"Resolution", "Ensure that the property is in the request body and "
+ "has a valid value "
+ "and resubmit the request if the operation failed."}};
}
/**
@@ -1100,17 +1176,18 @@ nlohmann::json propertyMissing(const std::string& arg1) {
* See header file for more information
* @endinternal
*/
-nlohmann::json resourceExhaustion(const std::string& arg1) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.ResourceExhaustion"},
- {"Message", "The resource " + arg1 +
- " was unable to satisfy the request "
- "due to unavailability of "
- "resources."},
- {"Severity", "Critical"},
- {"Resolution",
- "Ensure that the resources are available and resubmit the request."}};
+nlohmann::json resourceExhaustion(const std::string& arg1)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.ResourceExhaustion"},
+ {"Message", "The resource " + arg1 +
+ " was unable to satisfy the request "
+ "due to unavailability of "
+ "resources."},
+ {"Severity", "Critical"},
+ {"Resolution",
+ "Ensure that the resources are available and resubmit the request."}};
}
/**
@@ -1120,13 +1197,14 @@ nlohmann::json resourceExhaustion(const std::string& arg1) {
* See header file for more information
* @endinternal
*/
-nlohmann::json accountModified() {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.AccountModified"},
- {"Message", "The account was successfully modified."},
- {"Severity", "OK"},
- {"Resolution", "No resolution is required."}};
+nlohmann::json accountModified()
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.AccountModified"},
+ {"Message", "The account was successfully modified."},
+ {"Severity", "OK"},
+ {"Resolution", "No resolution is required."}};
}
/**
@@ -1138,24 +1216,26 @@ nlohmann::json accountModified() {
*/
nlohmann::json queryParameterOutOfRange(const std::string& arg1,
const std::string& arg2,
- const std::string& arg3) {
- return nlohmann::json{
- {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
- {"MessageId", "Base.1.2.0.QueryParameterOutOfRange"},
- {"Message", "The value " + arg1 + " for the query parameter " + arg2 +
- " is out of range " + arg3 + "."},
- {"Severity", "Warning"},
- {"Resolution",
- "Reduce the value for the query parameter to a value that is within "
- "range, such as a start or count value that is within bounds of the "
- "number of resources in a collection or a page that is within the range "
- "of valid pages."}};
+ const std::string& arg3)
+{
+ return nlohmann::json{
+ {"@odata.type", "/redfish/v1/$metadata#Message.v1_0_0.Message"},
+ {"MessageId", "Base.1.2.0.QueryParameterOutOfRange"},
+ {"Message", "The value " + arg1 + " for the query parameter " + arg2 +
+ " is out of range " + arg3 + "."},
+ {"Severity", "Warning"},
+ {"Resolution",
+ "Reduce the value for the query parameter to a value that is within "
+ "range, such as a start or count value that is within bounds of the "
+ "number of resources in a collection or a page that is within the "
+ "range "
+ "of valid pages."}};
}
/*********************************
* AUTOGENERATED FUNCTIONS END *
*********************************/
-} // namespace messages
+} // namespace messages
-} // namespace redfish
+} // namespace redfish
diff --git a/redfish-core/src/utils/json_utils.cpp b/redfish-core/src/utils/json_utils.cpp
index 5d81c21fa9..868601f72d 100644
--- a/redfish-core/src/utils/json_utils.cpp
+++ b/redfish-core/src/utils/json_utils.cpp
@@ -14,440 +14,512 @@
// limitations under the License.
*/
#include "utils/json_utils.hpp"
+
#include <error_messages.hpp>
-namespace redfish {
+namespace redfish
+{
-namespace json_util {
+namespace json_util
+{
Result getString(const char* fieldName, const nlohmann::json& json,
- const std::string*& output) {
- // Find field
- auto fieldIt = json.find(fieldName);
-
- // Verify existence
- if (fieldIt == json.end()) {
- return Result::NOT_EXIST;
- }
+ const std::string*& output)
+{
+ // Find field
+ auto fieldIt = json.find(fieldName);
+
+ // Verify existence
+ if (fieldIt == json.end())
+ {
+ return Result::NOT_EXIST;
+ }
- output = fieldIt->get_ptr<const std::string*>();
+ output = fieldIt->get_ptr<const std::string*>();
- // Verify type - we know that it exists, so nullptr means wrong type
- if (output == nullptr) {
- return Result::WRONG_TYPE;
- }
+ // Verify type - we know that it exists, so nullptr means wrong type
+ if (output == nullptr)
+ {
+ return Result::WRONG_TYPE;
+ }
- return Result::SUCCESS;
+ return Result::SUCCESS;
}
Result getObject(const char* fieldName, const nlohmann::json& json,
- nlohmann::json* output) {
- // Verify input pointer
- if (output == nullptr) {
- return Result::NULL_POINTER;
- }
+ nlohmann::json* output)
+{
+ // Verify input pointer
+ if (output == nullptr)
+ {
+ return Result::NULL_POINTER;
+ }
- // Find field
- auto fieldIt = json.find(fieldName);
+ // Find field
+ auto fieldIt = json.find(fieldName);
- // Verify existence
- if (fieldIt == json.end()) {
- return Result::NOT_EXIST;
- }
+ // Verify existence
+ if (fieldIt == json.end())
+ {
+ return Result::NOT_EXIST;
+ }
- // Verify type
- if (!fieldIt->is_object()) {
- return Result::WRONG_TYPE;
- }
+ // Verify type
+ if (!fieldIt->is_object())
+ {
+ return Result::WRONG_TYPE;
+ }
- // Extract value
- *output = *fieldIt;
+ // Extract value
+ *output = *fieldIt;
- return Result::SUCCESS;
+ return Result::SUCCESS;
}
Result getArray(const char* fieldName, const nlohmann::json& json,
- nlohmann::json* output) {
- // Verify input pointer
- if (output == nullptr) {
- return Result::NULL_POINTER;
- }
+ nlohmann::json* output)
+{
+ // Verify input pointer
+ if (output == nullptr)
+ {
+ return Result::NULL_POINTER;
+ }
- // Find field
- auto fieldIt = json.find(fieldName);
+ // Find field
+ auto fieldIt = json.find(fieldName);
- // Verify existence
- if (fieldIt == json.end()) {
- return Result::NOT_EXIST;
- }
+ // Verify existence
+ if (fieldIt == json.end())
+ {
+ return Result::NOT_EXIST;
+ }
- // Verify type
- if (!fieldIt->is_array()) {
- return Result::WRONG_TYPE;
- }
+ // Verify type
+ if (!fieldIt->is_array())
+ {
+ return Result::WRONG_TYPE;
+ }
- // Extract value
- *output = *fieldIt;
+ // Extract value
+ *output = *fieldIt;
- return Result::SUCCESS;
+ return Result::SUCCESS;
}
Result getInt(const char* fieldName, const nlohmann::json& json,
- int64_t& output) {
- // Find field
- auto fieldIt = json.find(fieldName);
-
- // Verify existence
- if (fieldIt == json.end()) {
- return Result::NOT_EXIST;
- }
+ int64_t& output)
+{
+ // Find field
+ auto fieldIt = json.find(fieldName);
+
+ // Verify existence
+ if (fieldIt == json.end())
+ {
+ return Result::NOT_EXIST;
+ }
- const int64_t* retVal = fieldIt->get_ptr<const int64_t*>();
+ const int64_t* retVal = fieldIt->get_ptr<const int64_t*>();
- // Verify type - we know that it exists, so nullptr means wrong type
- if (retVal == nullptr) {
- return Result::WRONG_TYPE;
- }
+ // Verify type - we know that it exists, so nullptr means wrong type
+ if (retVal == nullptr)
+ {
+ return Result::WRONG_TYPE;
+ }
- // Extract value
- output = *retVal;
+ // Extract value
+ output = *retVal;
- return Result::SUCCESS;
+ return Result::SUCCESS;
}
Result getUnsigned(const char* fieldName, const nlohmann::json& json,
- uint64_t& output) {
- // Find field
- auto fieldIt = json.find(fieldName);
-
- // Verify existence
- if (fieldIt == json.end()) {
- return Result::NOT_EXIST;
- }
+ uint64_t& output)
+{
+ // Find field
+ auto fieldIt = json.find(fieldName);
+
+ // Verify existence
+ if (fieldIt == json.end())
+ {
+ return Result::NOT_EXIST;
+ }
- const uint64_t* retVal = fieldIt->get_ptr<const uint64_t*>();
+ const uint64_t* retVal = fieldIt->get_ptr<const uint64_t*>();
- // Verify type - we know that it exists, so nullptr means wrong type
- if (retVal == nullptr) {
- return Result::WRONG_TYPE;
- }
+ // Verify type - we know that it exists, so nullptr means wrong type
+ if (retVal == nullptr)
+ {
+ return Result::WRONG_TYPE;
+ }
- // Extract value
- output = *retVal;
+ // Extract value
+ output = *retVal;
- return Result::SUCCESS;
+ return Result::SUCCESS;
}
-Result getBool(const char* fieldName, const nlohmann::json& json,
- bool& output) {
- // Find field
- auto fieldIt = json.find(fieldName);
+Result getBool(const char* fieldName, const nlohmann::json& json, bool& output)
+{
+ // Find field
+ auto fieldIt = json.find(fieldName);
- // Verify existence
- if (fieldIt == json.end()) {
- return Result::NOT_EXIST;
- }
+ // Verify existence
+ if (fieldIt == json.end())
+ {
+ return Result::NOT_EXIST;
+ }
- const bool* retVal = fieldIt->get_ptr<const bool*>();
+ const bool* retVal = fieldIt->get_ptr<const bool*>();
- // Verify type - we know that it exists, so nullptr means wrong type
- if (retVal == nullptr) {
- return Result::WRONG_TYPE;
- }
+ // Verify type - we know that it exists, so nullptr means wrong type
+ if (retVal == nullptr)
+ {
+ return Result::WRONG_TYPE;
+ }
- // Extract value
- output = *retVal;
+ // Extract value
+ output = *retVal;
- return Result::SUCCESS;
+ return Result::SUCCESS;
}
Result getDouble(const char* fieldName, const nlohmann::json& json,
- double& output) {
- // Find field
- auto fieldIt = json.find(fieldName);
-
- // Verify existence
- if (fieldIt == json.end()) {
- return Result::NOT_EXIST;
- }
+ double& output)
+{
+ // Find field
+ auto fieldIt = json.find(fieldName);
+
+ // Verify existence
+ if (fieldIt == json.end())
+ {
+ return Result::NOT_EXIST;
+ }
- const double* retVal = fieldIt->get_ptr<const double*>();
+ const double* retVal = fieldIt->get_ptr<const double*>();
- // Verify type - we know that it exists, so nullptr means wrong type
- if (retVal == nullptr) {
- return Result::WRONG_TYPE;
- }
+ // Verify type - we know that it exists, so nullptr means wrong type
+ if (retVal == nullptr)
+ {
+ return Result::WRONG_TYPE;
+ }
- // Extract value
- output = *retVal;
+ // Extract value
+ output = *retVal;
- return Result::SUCCESS;
+ return Result::SUCCESS;
}
Result getString(const char* fieldName, const nlohmann::json& json,
const std::string*& output, uint8_t msgCfgMap,
- nlohmann::json& msgJson, const std::string&& fieldPath) {
- // Find field
- auto fieldIt = json.find(fieldName);
-
- // Verify existence
- if (fieldIt == json.end()) {
- if (msgCfgMap & static_cast<int>(MessageSetting::MISSING)) {
- messages::addMessageToJson(msgJson, messages::propertyMissing(fieldName),
- fieldPath);
+ nlohmann::json& msgJson, const std::string&& fieldPath)
+{
+ // Find field
+ auto fieldIt = json.find(fieldName);
+
+ // Verify existence
+ if (fieldIt == json.end())
+ {
+ if (msgCfgMap & static_cast<int>(MessageSetting::MISSING))
+ {
+ messages::addMessageToJson(
+ msgJson, messages::propertyMissing(fieldName), fieldPath);
+ }
+
+ return Result::NOT_EXIST;
}
- return Result::NOT_EXIST;
- }
+ output = fieldIt->get_ptr<const std::string*>();
- output = fieldIt->get_ptr<const std::string*>();
+ // Verify type - we know that it exists, so nullptr means wrong type
+ if (output == nullptr)
+ {
+ if (msgCfgMap & static_cast<int>(MessageSetting::TYPE_ERROR))
+ {
+ messages::addMessageToJson(
+ msgJson,
+ messages::propertyValueTypeError(fieldIt->dump(), fieldName),
+ fieldPath);
+ }
- // Verify type - we know that it exists, so nullptr means wrong type
- if (output == nullptr) {
- if (msgCfgMap & static_cast<int>(MessageSetting::TYPE_ERROR)) {
- messages::addMessageToJson(
- msgJson, messages::propertyValueTypeError(fieldIt->dump(), fieldName),
- fieldPath);
+ return Result::WRONG_TYPE;
}
- return Result::WRONG_TYPE;
- }
-
- return Result::SUCCESS;
+ return Result::SUCCESS;
}
Result getObject(const char* fieldName, const nlohmann::json& json,
nlohmann::json* output, uint8_t msgCfgMap,
- nlohmann::json& msgJson, const std::string&& fieldPath) {
- // Verify input pointer
- if (output == nullptr) {
- return Result::NULL_POINTER;
- }
-
- // Find field
- auto fieldIt = json.find(fieldName);
-
- // Verify existence
- if (fieldIt == json.end()) {
- if (msgCfgMap & static_cast<int>(MessageSetting::MISSING)) {
- messages::addMessageToJson(msgJson, messages::propertyMissing(fieldName),
- fieldPath);
+ nlohmann::json& msgJson, const std::string&& fieldPath)
+{
+ // Verify input pointer
+ if (output == nullptr)
+ {
+ return Result::NULL_POINTER;
}
- return Result::NOT_EXIST;
- }
+ // Find field
+ auto fieldIt = json.find(fieldName);
- // Verify type
- if (!fieldIt->is_object()) {
- if (msgCfgMap & static_cast<int>(MessageSetting::TYPE_ERROR)) {
- messages::addMessageToJson(
- msgJson, messages::propertyValueTypeError(fieldIt->dump(), fieldName),
- fieldPath);
+ // Verify existence
+ if (fieldIt == json.end())
+ {
+ if (msgCfgMap & static_cast<int>(MessageSetting::MISSING))
+ {
+ messages::addMessageToJson(
+ msgJson, messages::propertyMissing(fieldName), fieldPath);
+ }
+
+ return Result::NOT_EXIST;
}
- return Result::WRONG_TYPE;
- }
+ // Verify type
+ if (!fieldIt->is_object())
+ {
+ if (msgCfgMap & static_cast<int>(MessageSetting::TYPE_ERROR))
+ {
+ messages::addMessageToJson(
+ msgJson,
+ messages::propertyValueTypeError(fieldIt->dump(), fieldName),
+ fieldPath);
+ }
+
+ return Result::WRONG_TYPE;
+ }
- // Extract value
- *output = *fieldIt;
+ // Extract value
+ *output = *fieldIt;
- return Result::SUCCESS;
+ return Result::SUCCESS;
}
Result getArray(const char* fieldName, const nlohmann::json& json,
nlohmann::json* output, uint8_t msgCfgMap,
- nlohmann::json& msgJson, const std::string&& fieldPath) {
- // Verify input pointer
- if (output == nullptr) {
- return Result::NULL_POINTER;
- }
-
- // Find field
- auto fieldIt = json.find(fieldName);
-
- // Verify existence
- if (fieldIt == json.end()) {
- if (msgCfgMap & static_cast<int>(MessageSetting::MISSING)) {
- messages::addMessageToJson(msgJson, messages::propertyMissing(fieldName),
- fieldPath);
+ nlohmann::json& msgJson, const std::string&& fieldPath)
+{
+ // Verify input pointer
+ if (output == nullptr)
+ {
+ return Result::NULL_POINTER;
}
- return Result::NOT_EXIST;
- }
+ // Find field
+ auto fieldIt = json.find(fieldName);
+
+ // Verify existence
+ if (fieldIt == json.end())
+ {
+ if (msgCfgMap & static_cast<int>(MessageSetting::MISSING))
+ {
+ messages::addMessageToJson(
+ msgJson, messages::propertyMissing(fieldName), fieldPath);
+ }
- // Verify type
- if (!fieldIt->is_array()) {
- if (msgCfgMap & static_cast<int>(MessageSetting::TYPE_ERROR)) {
- messages::addMessageToJson(
- msgJson, messages::propertyValueTypeError(fieldIt->dump(), fieldName),
- fieldPath);
+ return Result::NOT_EXIST;
}
- return Result::WRONG_TYPE;
- }
+ // Verify type
+ if (!fieldIt->is_array())
+ {
+ if (msgCfgMap & static_cast<int>(MessageSetting::TYPE_ERROR))
+ {
+ messages::addMessageToJson(
+ msgJson,
+ messages::propertyValueTypeError(fieldIt->dump(), fieldName),
+ fieldPath);
+ }
+
+ return Result::WRONG_TYPE;
+ }
- // Extract value
- *output = *fieldIt;
+ // Extract value
+ *output = *fieldIt;
- return Result::SUCCESS;
+ return Result::SUCCESS;
}
Result getInt(const char* fieldName, const nlohmann::json& json,
int64_t& output, uint8_t msgCfgMap, nlohmann::json& msgJson,
- const std::string&& fieldPath) {
- // Find field
- auto fieldIt = json.find(fieldName);
-
- // Verify existence
- if (fieldIt == json.end()) {
- if (msgCfgMap & static_cast<int>(MessageSetting::MISSING)) {
- messages::addMessageToJson(msgJson, messages::propertyMissing(fieldName),
- fieldPath);
+ const std::string&& fieldPath)
+{
+ // Find field
+ auto fieldIt = json.find(fieldName);
+
+ // Verify existence
+ if (fieldIt == json.end())
+ {
+ if (msgCfgMap & static_cast<int>(MessageSetting::MISSING))
+ {
+ messages::addMessageToJson(
+ msgJson, messages::propertyMissing(fieldName), fieldPath);
+ }
+
+ return Result::NOT_EXIST;
}
- return Result::NOT_EXIST;
- }
+ const int64_t* retVal = fieldIt->get_ptr<const int64_t*>();
- const int64_t* retVal = fieldIt->get_ptr<const int64_t*>();
+ // Verify type - we know that it exists, so nullptr means wrong type
+ if (retVal == nullptr)
+ {
+ if (msgCfgMap & static_cast<int>(MessageSetting::TYPE_ERROR))
+ {
+ messages::addMessageToJson(
+ msgJson,
+ messages::propertyValueTypeError(fieldIt->dump(), fieldName),
+ fieldPath);
+ }
- // Verify type - we know that it exists, so nullptr means wrong type
- if (retVal == nullptr) {
- if (msgCfgMap & static_cast<int>(MessageSetting::TYPE_ERROR)) {
- messages::addMessageToJson(
- msgJson, messages::propertyValueTypeError(fieldIt->dump(), fieldName),
- fieldPath);
+ return Result::WRONG_TYPE;
}
- return Result::WRONG_TYPE;
- }
-
- // Extract value
- output = *retVal;
+ // Extract value
+ output = *retVal;
- return Result::SUCCESS;
+ return Result::SUCCESS;
}
Result getUnsigned(const char* fieldName, const nlohmann::json& json,
uint64_t& output, uint8_t msgCfgMap, nlohmann::json& msgJson,
- const std::string&& fieldPath) {
- // Find field
- auto fieldIt = json.find(fieldName);
-
- // Verify existence
- if (fieldIt == json.end()) {
- if (msgCfgMap & static_cast<int>(MessageSetting::MISSING)) {
- messages::addMessageToJson(msgJson, messages::propertyMissing(fieldName),
- fieldPath);
+ const std::string&& fieldPath)
+{
+ // Find field
+ auto fieldIt = json.find(fieldName);
+
+ // Verify existence
+ if (fieldIt == json.end())
+ {
+ if (msgCfgMap & static_cast<int>(MessageSetting::MISSING))
+ {
+ messages::addMessageToJson(
+ msgJson, messages::propertyMissing(fieldName), fieldPath);
+ }
+
+ return Result::NOT_EXIST;
}
- return Result::NOT_EXIST;
- }
+ const uint64_t* retVal = fieldIt->get_ptr<const uint64_t*>();
- const uint64_t* retVal = fieldIt->get_ptr<const uint64_t*>();
+ // Verify type - we know that it exists, so nullptr means wrong type
+ if (retVal == nullptr)
+ {
+ if (msgCfgMap & static_cast<int>(MessageSetting::TYPE_ERROR))
+ {
+ messages::addMessageToJson(
+ msgJson,
+ messages::propertyValueTypeError(fieldIt->dump(), fieldName),
+ fieldPath);
+ }
- // Verify type - we know that it exists, so nullptr means wrong type
- if (retVal == nullptr) {
- if (msgCfgMap & static_cast<int>(MessageSetting::TYPE_ERROR)) {
- messages::addMessageToJson(
- msgJson, messages::propertyValueTypeError(fieldIt->dump(), fieldName),
- fieldPath);
+ return Result::WRONG_TYPE;
}
- return Result::WRONG_TYPE;
- }
-
- // Extract value
- output = *retVal;
+ // Extract value
+ output = *retVal;
- return Result::SUCCESS;
+ return Result::SUCCESS;
}
Result getBool(const char* fieldName, const nlohmann::json& json, bool& output,
uint8_t msgCfgMap, nlohmann::json& msgJson,
- const std::string&& fieldPath) {
- // Find field
- auto fieldIt = json.find(fieldName);
-
- // Verify existence
- if (fieldIt == json.end()) {
- if (msgCfgMap & static_cast<int>(MessageSetting::MISSING)) {
- messages::addMessageToJson(msgJson, messages::propertyMissing(fieldName),
- fieldPath);
+ const std::string&& fieldPath)
+{
+ // Find field
+ auto fieldIt = json.find(fieldName);
+
+ // Verify existence
+ if (fieldIt == json.end())
+ {
+ if (msgCfgMap & static_cast<int>(MessageSetting::MISSING))
+ {
+ messages::addMessageToJson(
+ msgJson, messages::propertyMissing(fieldName), fieldPath);
+ }
+
+ return Result::NOT_EXIST;
}
- return Result::NOT_EXIST;
- }
+ const bool* retVal = fieldIt->get_ptr<const bool*>();
- const bool* retVal = fieldIt->get_ptr<const bool*>();
+ // Verify type - we know that it exists, so nullptr means wrong type
+ if (retVal == nullptr)
+ {
+ if (msgCfgMap & static_cast<int>(MessageSetting::TYPE_ERROR))
+ {
+ messages::addMessageToJson(
+ msgJson,
+ messages::propertyValueTypeError(fieldIt->dump(), fieldName),
+ fieldPath);
+ }
- // Verify type - we know that it exists, so nullptr means wrong type
- if (retVal == nullptr) {
- if (msgCfgMap & static_cast<int>(MessageSetting::TYPE_ERROR)) {
- messages::addMessageToJson(
- msgJson, messages::propertyValueTypeError(fieldIt->dump(), fieldName),
- fieldPath);
+ return Result::WRONG_TYPE;
}
- return Result::WRONG_TYPE;
- }
-
- // Extract value
- output = *retVal;
+ // Extract value
+ output = *retVal;
- return Result::SUCCESS;
+ return Result::SUCCESS;
}
Result getDouble(const char* fieldName, const nlohmann::json& json,
double& output, uint8_t msgCfgMap, nlohmann::json& msgJson,
- const std::string&& fieldPath) {
- // Find field
- auto fieldIt = json.find(fieldName);
-
- // Verify existence
- if (fieldIt == json.end()) {
- if (msgCfgMap & static_cast<int>(MessageSetting::MISSING)) {
- messages::addMessageToJson(msgJson, messages::propertyMissing(fieldName),
- fieldPath);
+ const std::string&& fieldPath)
+{
+ // Find field
+ auto fieldIt = json.find(fieldName);
+
+ // Verify existence
+ if (fieldIt == json.end())
+ {
+ if (msgCfgMap & static_cast<int>(MessageSetting::MISSING))
+ {
+ messages::addMessageToJson(
+ msgJson, messages::propertyMissing(fieldName), fieldPath);
+ }
+
+ return Result::NOT_EXIST;
}
- return Result::NOT_EXIST;
- }
+ const double* retVal = fieldIt->get_ptr<const double*>();
- const double* retVal = fieldIt->get_ptr<const double*>();
+ // Verify type - we know that it exists, so nullptr means wrong type
+ if (retVal == nullptr)
+ {
+ if (msgCfgMap & static_cast<int>(MessageSetting::TYPE_ERROR))
+ {
+ messages::addMessageToJson(
+ msgJson,
+ messages::propertyValueTypeError(fieldIt->dump(), fieldName),
+ fieldPath);
+ }
- // Verify type - we know that it exists, so nullptr means wrong type
- if (retVal == nullptr) {
- if (msgCfgMap & static_cast<int>(MessageSetting::TYPE_ERROR)) {
- messages::addMessageToJson(
- msgJson, messages::propertyValueTypeError(fieldIt->dump(), fieldName),
- fieldPath);
+ return Result::WRONG_TYPE;
}
- return Result::WRONG_TYPE;
- }
+ // Extract value
+ output = *retVal;
- // Extract value
- output = *retVal;
-
- return Result::SUCCESS;
+ return Result::SUCCESS;
}
bool processJsonFromRequest(crow::Response& res, const crow::Request& req,
- nlohmann::json& reqJson) {
- reqJson = nlohmann::json::parse(req.body, nullptr, false);
+ nlohmann::json& reqJson)
+{
+ reqJson = nlohmann::json::parse(req.body, nullptr, false);
- if (reqJson.is_discarded()) {
- messages::addMessageToErrorJson(res.jsonValue, messages::malformedJSON());
+ if (reqJson.is_discarded())
+ {
+ messages::addMessageToErrorJson(res.jsonValue,
+ messages::malformedJSON());
- res.result(boost::beast::http::status::bad_request);
- res.end();
+ res.result(boost::beast::http::status::bad_request);
+ res.end();
- return false;
- }
+ return false;
+ }
- return true;
+ return true;
}
-} // namespace json_util
+} // namespace json_util
-} // namespace redfish
+} // namespace redfish
diff --git a/redfish-core/ut/privileges_test.cpp b/redfish-core/ut/privileges_test.cpp
index 92cd6c42a4..d857290250 100644
--- a/redfish-core/ut/privileges_test.cpp
+++ b/redfish-core/ut/privileges_test.cpp
@@ -1,114 +1,127 @@
+#include "nlohmann/json.hpp"
#include "privileges.hpp"
+
#include <fstream>
#include <string>
-#include "nlohmann/json.hpp"
+
#include "gmock/gmock.h"
using namespace redfish;
-TEST(PrivilegeTest, PrivilegeConstructor) {
- Privileges privileges{"Login", "ConfigureManager"};
+TEST(PrivilegeTest, PrivilegeConstructor)
+{
+ Privileges privileges{"Login", "ConfigureManager"};
- EXPECT_THAT(privileges.getActivePrivilegeNames(PrivilegeType::BASE),
- ::testing::UnorderedElementsAre(
- ::testing::Pointee(&"Login"[0]),
- ::testing::Pointee(&"ConfigureManager"[0])));
+ EXPECT_THAT(privileges.getActivePrivilegeNames(PrivilegeType::BASE),
+ ::testing::UnorderedElementsAre(
+ ::testing::Pointee(&"Login"[0]),
+ ::testing::Pointee(&"ConfigureManager"[0])));
}
-TEST(PrivilegeTest, PrivilegeCheckForNoPrivilegesRequired) {
- Privileges userPrivileges{"Login"};
+TEST(PrivilegeTest, PrivilegeCheckForNoPrivilegesRequired)
+{
+ Privileges userPrivileges{"Login"};
- OperationMap entityPrivileges{{boost::beast::http::verb::get, {{"Login"}}}};
+ OperationMap entityPrivileges{{boost::beast::http::verb::get, {{"Login"}}}};
- EXPECT_TRUE(isMethodAllowedWithPrivileges(boost::beast::http::verb::get,
- entityPrivileges, userPrivileges));
+ EXPECT_TRUE(isMethodAllowedWithPrivileges(
+ boost::beast::http::verb::get, entityPrivileges, userPrivileges));
}
-TEST(PrivilegeTest, PrivilegeCheckForSingleCaseSuccess) {
- auto userPrivileges = Privileges{"Login"};
- OperationMap entityPrivileges{{boost::beast::http::verb::get, {}}};
+TEST(PrivilegeTest, PrivilegeCheckForSingleCaseSuccess)
+{
+ auto userPrivileges = Privileges{"Login"};
+ OperationMap entityPrivileges{{boost::beast::http::verb::get, {}}};
- EXPECT_TRUE(isMethodAllowedWithPrivileges(boost::beast::http::verb::get,
- entityPrivileges, userPrivileges));
+ EXPECT_TRUE(isMethodAllowedWithPrivileges(
+ boost::beast::http::verb::get, entityPrivileges, userPrivileges));
}
-TEST(PrivilegeTest, PrivilegeCheckForSingleCaseFailure) {
- auto userPrivileges = Privileges{"Login"};
- OperationMap entityPrivileges{
- {boost::beast::http::verb::get, {{"ConfigureManager"}}}};
+TEST(PrivilegeTest, PrivilegeCheckForSingleCaseFailure)
+{
+ auto userPrivileges = Privileges{"Login"};
+ OperationMap entityPrivileges{
+ {boost::beast::http::verb::get, {{"ConfigureManager"}}}};
- EXPECT_FALSE(isMethodAllowedWithPrivileges(boost::beast::http::verb::get,
- entityPrivileges, userPrivileges));
+ EXPECT_FALSE(isMethodAllowedWithPrivileges(
+ boost::beast::http::verb::get, entityPrivileges, userPrivileges));
}
-TEST(PrivilegeTest, PrivilegeCheckForANDCaseSuccess) {
- auto userPrivileges =
- Privileges{"Login", "ConfigureManager", "ConfigureSelf"};
- OperationMap entityPrivileges{
- {boost::beast::http::verb::get,
- {{"Login", "ConfigureManager", "ConfigureSelf"}}}};
+TEST(PrivilegeTest, PrivilegeCheckForANDCaseSuccess)
+{
+ auto userPrivileges =
+ Privileges{"Login", "ConfigureManager", "ConfigureSelf"};
+ OperationMap entityPrivileges{
+ {boost::beast::http::verb::get,
+ {{"Login", "ConfigureManager", "ConfigureSelf"}}}};
- EXPECT_TRUE(isMethodAllowedWithPrivileges(boost::beast::http::verb::get,
- entityPrivileges, userPrivileges));
+ EXPECT_TRUE(isMethodAllowedWithPrivileges(
+ boost::beast::http::verb::get, entityPrivileges, userPrivileges));
}
-TEST(PrivilegeTest, PrivilegeCheckForANDCaseFailure) {
- auto userPrivileges = Privileges{"Login", "ConfigureManager"};
- OperationMap entityPrivileges{
- {boost::beast::http::verb::get,
- {{"Login", "ConfigureManager", "ConfigureSelf"}}}};
+TEST(PrivilegeTest, PrivilegeCheckForANDCaseFailure)
+{
+ auto userPrivileges = Privileges{"Login", "ConfigureManager"};
+ OperationMap entityPrivileges{
+ {boost::beast::http::verb::get,
+ {{"Login", "ConfigureManager", "ConfigureSelf"}}}};
- EXPECT_FALSE(isMethodAllowedWithPrivileges(boost::beast::http::verb::get,
- entityPrivileges, userPrivileges));
+ EXPECT_FALSE(isMethodAllowedWithPrivileges(
+ boost::beast::http::verb::get, entityPrivileges, userPrivileges));
}
-TEST(PrivilegeTest, PrivilegeCheckForORCaseSuccess) {
- auto userPrivileges = Privileges{"ConfigureManager"};
- OperationMap entityPrivileges{
- {boost::beast::http::verb::get, {{"Login"}, {"ConfigureManager"}}}};
+TEST(PrivilegeTest, PrivilegeCheckForORCaseSuccess)
+{
+ auto userPrivileges = Privileges{"ConfigureManager"};
+ OperationMap entityPrivileges{
+ {boost::beast::http::verb::get, {{"Login"}, {"ConfigureManager"}}}};
- EXPECT_TRUE(isMethodAllowedWithPrivileges(boost::beast::http::verb::get,
- entityPrivileges, userPrivileges));
+ EXPECT_TRUE(isMethodAllowedWithPrivileges(
+ boost::beast::http::verb::get, entityPrivileges, userPrivileges));
}
-TEST(PrivilegeTest, PrivilegeCheckForORCaseFailure) {
- auto userPrivileges = Privileges{"ConfigureComponents"};
- OperationMap entityPrivileges = OperationMap(
- {{boost::beast::http::verb::get, {{"Login"}, {"ConfigureManager"}}}});
+TEST(PrivilegeTest, PrivilegeCheckForORCaseFailure)
+{
+ auto userPrivileges = Privileges{"ConfigureComponents"};
+ OperationMap entityPrivileges = OperationMap(
+ {{boost::beast::http::verb::get, {{"Login"}, {"ConfigureManager"}}}});
- EXPECT_FALSE(isMethodAllowedWithPrivileges(boost::beast::http::verb::get,
- entityPrivileges, userPrivileges));
+ EXPECT_FALSE(isMethodAllowedWithPrivileges(
+ boost::beast::http::verb::get, entityPrivileges, userPrivileges));
}
-TEST(PrivilegeTest, DefaultPrivilegeBitsetsAreEmpty) {
- Privileges privileges;
+TEST(PrivilegeTest, DefaultPrivilegeBitsetsAreEmpty)
+{
+ Privileges privileges;
- EXPECT_THAT(privileges.getActivePrivilegeNames(PrivilegeType::BASE),
- ::testing::IsEmpty());
+ EXPECT_THAT(privileges.getActivePrivilegeNames(PrivilegeType::BASE),
+ ::testing::IsEmpty());
- EXPECT_THAT(privileges.getActivePrivilegeNames(PrivilegeType::OEM),
- ::testing::IsEmpty());
+ EXPECT_THAT(privileges.getActivePrivilegeNames(PrivilegeType::OEM),
+ ::testing::IsEmpty());
}
-TEST(PrivilegeTest, GetActivePrivilegeNames) {
- Privileges privileges;
-
- EXPECT_THAT(privileges.getActivePrivilegeNames(PrivilegeType::BASE),
- ::testing::IsEmpty());
-
- std::array<const char*, 5> expectedPrivileges{
- "Login", "ConfigureManager", "ConfigureUsers", "ConfigureComponents",
- "ConfigureSelf"};
-
- for (const auto& privilege : expectedPrivileges) {
- EXPECT_TRUE(privileges.setSinglePrivilege(privilege));
- }
-
- EXPECT_THAT(privileges.getActivePrivilegeNames(PrivilegeType::BASE),
- ::testing::UnorderedElementsAre(
- ::testing::Pointee(expectedPrivileges[0]),
- ::testing::Pointee(expectedPrivileges[1]),
- ::testing::Pointee(expectedPrivileges[2]),
- ::testing::Pointee(expectedPrivileges[3]),
- ::testing::Pointee(expectedPrivileges[4])));
+TEST(PrivilegeTest, GetActivePrivilegeNames)
+{
+ Privileges privileges;
+
+ EXPECT_THAT(privileges.getActivePrivilegeNames(PrivilegeType::BASE),
+ ::testing::IsEmpty());
+
+ std::array<const char*, 5> expectedPrivileges{
+ "Login", "ConfigureManager", "ConfigureUsers", "ConfigureComponents",
+ "ConfigureSelf"};
+
+ for (const auto& privilege : expectedPrivileges)
+ {
+ EXPECT_TRUE(privileges.setSinglePrivilege(privilege));
+ }
+
+ EXPECT_THAT(privileges.getActivePrivilegeNames(PrivilegeType::BASE),
+ ::testing::UnorderedElementsAre(
+ ::testing::Pointee(expectedPrivileges[0]),
+ ::testing::Pointee(expectedPrivileges[1]),
+ ::testing::Pointee(expectedPrivileges[2]),
+ ::testing::Pointee(expectedPrivileges[3]),
+ ::testing::Pointee(expectedPrivileges[4])));
}
diff --git a/src/ast_jpeg_decoder_test.cpp b/src/ast_jpeg_decoder_test.cpp
index 277ba2cc8b..1552f46f76 100644
--- a/src/ast_jpeg_decoder_test.cpp
+++ b/src/ast_jpeg_decoder_test.cpp
@@ -1,4 +1,5 @@
#include "ast_jpeg_decoder.hpp"
+
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -10,150 +11,160 @@
using namespace testing;
MATCHER_P2(IsBetween, a, b,
std::string(negation ? "isn't" : "is") + " between " +
- PrintToString(a) + " and " + PrintToString(b)) {
- return a <= arg && arg <= b;
+ PrintToString(a) + " and " + PrintToString(b))
+{
+ return a <= arg && arg <= b;
};
-TEST(AstJpegDecoder, AllBlue) {
- ast_video::RawVideoBuffer out;
-
- // This binary blog was created on the aspeed hardware using a blue screen
- // consisting of the color 0x8EFFFA in a web browser window
- FILE *fp = fopen("test_resources/aspeedbluescreen.bin", "rb");
- EXPECT_NE(fp, nullptr);
- size_t bufferlen =
- fread(out.buffer.data(), sizeof(decltype(out.buffer)::value_type),
- out.buffer.size(), fp);
- fclose(fp);
-
- ASSERT_GT(bufferlen, 0);
-
- out.ySelector = 0;
- out.uvSelector = 0;
- out.mode = ast_video::YuvMode::YUV444;
- out.width = 800;
- out.height = 600;
-
- ast_video::AstJpegDecoder d;
- d.decode(out.buffer, out.width, out.height, out.mode, out.ySelector,
- out.uvSelector);
-
- int tolerance = 16;
-
- // All pixels should be blue (0x8EFFFA) to within a tolerance (due to jpeg
- // compression artifacts and quanitization)
- for (int i = 0; i < out.width * out.height; i++) {
- ast_video::RGB &pixel = d.outBuffer[i];
- EXPECT_GT(pixel.r, 0x8E - tolerance);
- EXPECT_LT(pixel.r, 0x8E + tolerance);
- EXPECT_GT(pixel.g, 0xFF - tolerance);
- EXPECT_LT(pixel.g, 0xFF + tolerance);
- EXPECT_GT(pixel.b, 0xF1 - tolerance);
- EXPECT_LT(pixel.b, 0xF1 + tolerance);
- }
+TEST(AstJpegDecoder, AllBlue)
+{
+ ast_video::RawVideoBuffer out;
+
+ // This binary blog was created on the aspeed hardware using a blue screen
+ // consisting of the color 0x8EFFFA in a web browser window
+ FILE *fp = fopen("test_resources/aspeedbluescreen.bin", "rb");
+ EXPECT_NE(fp, nullptr);
+ size_t bufferlen =
+ fread(out.buffer.data(), sizeof(decltype(out.buffer)::value_type),
+ out.buffer.size(), fp);
+ fclose(fp);
+
+ ASSERT_GT(bufferlen, 0);
+
+ out.ySelector = 0;
+ out.uvSelector = 0;
+ out.mode = ast_video::YuvMode::YUV444;
+ out.width = 800;
+ out.height = 600;
+
+ ast_video::AstJpegDecoder d;
+ d.decode(out.buffer, out.width, out.height, out.mode, out.ySelector,
+ out.uvSelector);
+
+ int tolerance = 16;
+
+ // All pixels should be blue (0x8EFFFA) to within a tolerance (due to jpeg
+ // compression artifacts and quanitization)
+ for (int i = 0; i < out.width * out.height; i++)
+ {
+ ast_video::RGB &pixel = d.outBuffer[i];
+ EXPECT_GT(pixel.r, 0x8E - tolerance);
+ EXPECT_LT(pixel.r, 0x8E + tolerance);
+ EXPECT_GT(pixel.g, 0xFF - tolerance);
+ EXPECT_LT(pixel.g, 0xFF + tolerance);
+ EXPECT_GT(pixel.b, 0xF1 - tolerance);
+ EXPECT_LT(pixel.b, 0xF1 + tolerance);
+ }
}
-TEST(AstJpegDecoder, AllBlack) {
- ast_video::RawVideoBuffer out;
-
- // This binary blog was created on the aspeed hardware using a black screen
- FILE *fp = fopen("test_resources/aspeedblackscreen.bin", "rb");
- EXPECT_NE(fp, nullptr);
- size_t bufferlen = fread(out.buffer.data(), sizeof(char),
- out.buffer.size() * sizeof(long), fp);
- fclose(fp);
-
- ASSERT_GT(bufferlen, 0);
-
- out.ySelector = 0;
- out.uvSelector = 0;
- out.mode = ast_video::YuvMode::YUV444;
- out.width = 800;
- out.height = 600;
-
- ast_video::AstJpegDecoder d;
- d.decode(out.buffer, out.width, out.height, out.mode, out.ySelector,
- out.uvSelector);
-
- // All pixels should be blue (0x8EFFFA) to within a tolerance (due to jpeg
- // compression artifacts and quanitization)
- for (int x = 0; x < out.width; x++) {
- for (int y = 0; y < out.height; y++) {
- ast_video::RGB pixel = d.outBuffer[x + (y * out.width)];
- ASSERT_EQ(pixel.r, 0x00) << "X:" << x << " Y: " << y;
- ASSERT_EQ(pixel.g, 0x00) << "X:" << x << " Y: " << y;
- ASSERT_EQ(pixel.b, 0x00) << "X:" << x << " Y: " << y;
+TEST(AstJpegDecoder, AllBlack)
+{
+ ast_video::RawVideoBuffer out;
+
+ // This binary blog was created on the aspeed hardware using a black screen
+ FILE *fp = fopen("test_resources/aspeedblackscreen.bin", "rb");
+ EXPECT_NE(fp, nullptr);
+ size_t bufferlen = fread(out.buffer.data(), sizeof(char),
+ out.buffer.size() * sizeof(long), fp);
+ fclose(fp);
+
+ ASSERT_GT(bufferlen, 0);
+
+ out.ySelector = 0;
+ out.uvSelector = 0;
+ out.mode = ast_video::YuvMode::YUV444;
+ out.width = 800;
+ out.height = 600;
+
+ ast_video::AstJpegDecoder d;
+ d.decode(out.buffer, out.width, out.height, out.mode, out.ySelector,
+ out.uvSelector);
+
+ // All pixels should be blue (0x8EFFFA) to within a tolerance (due to jpeg
+ // compression artifacts and quanitization)
+ for (int x = 0; x < out.width; x++)
+ {
+ for (int y = 0; y < out.height; y++)
+ {
+ ast_video::RGB pixel = d.outBuffer[x + (y * out.width)];
+ ASSERT_EQ(pixel.r, 0x00) << "X:" << x << " Y: " << y;
+ ASSERT_EQ(pixel.g, 0x00) << "X:" << x << " Y: " << y;
+ ASSERT_EQ(pixel.b, 0x00) << "X:" << x << " Y: " << y;
+ }
}
- }
}
-TEST(AstJpegDecoder, TestColors) {
- ast_video::RawVideoBuffer out;
-
- // This binary blog was created on the aspeed hardware using a blue screen
- // consisting of the color 0x8EFFFA in a web browser window
- FILE *fp = fopen("test_resources/ubuntu_444_800x600_0chrom_0lum.bin", "rb");
- EXPECT_NE(fp, nullptr);
- size_t bufferlen = fread(out.buffer.data(), sizeof(char),
- out.buffer.size() * sizeof(long), fp);
- fclose(fp);
-
- ASSERT_GT(bufferlen, 0);
-
- out.ySelector = 0;
- out.uvSelector = 0;
- out.mode = ast_video::YuvMode::YUV444;
- out.width = 800;
- out.height = 600;
-
- ast_video::AstJpegDecoder d;
- d.decode(out.buffer, out.width, out.height, out.mode, out.ySelector,
- out.uvSelector);
-
- int tolerance = 16;
- /*
- for (int i = 0; i < out.width * out.height; i++) {
- ast_video::RGB &pixel = d.outBuffer[i];
- EXPECT_GT(pixel.r, 0x8E - tolerance);
- EXPECT_LT(pixel.r, 0x8E + tolerance);
- EXPECT_GT(pixel.g, 0xFF - tolerance);
- EXPECT_LT(pixel.g, 0xFF + tolerance);
- EXPECT_GT(pixel.b, 0xF1 - tolerance);
- EXPECT_LT(pixel.b, 0xF1 + tolerance);
- }
- */
+TEST(AstJpegDecoder, TestColors)
+{
+ ast_video::RawVideoBuffer out;
+
+ // This binary blog was created on the aspeed hardware using a blue screen
+ // consisting of the color 0x8EFFFA in a web browser window
+ FILE *fp = fopen("test_resources/ubuntu_444_800x600_0chrom_0lum.bin", "rb");
+ EXPECT_NE(fp, nullptr);
+ size_t bufferlen = fread(out.buffer.data(), sizeof(char),
+ out.buffer.size() * sizeof(long), fp);
+ fclose(fp);
+
+ ASSERT_GT(bufferlen, 0);
+
+ out.ySelector = 0;
+ out.uvSelector = 0;
+ out.mode = ast_video::YuvMode::YUV444;
+ out.width = 800;
+ out.height = 600;
+
+ ast_video::AstJpegDecoder d;
+ d.decode(out.buffer, out.width, out.height, out.mode, out.ySelector,
+ out.uvSelector);
+
+ int tolerance = 16;
+ /*
+ for (int i = 0; i < out.width * out.height; i++) {
+ ast_video::RGB &pixel = d.outBuffer[i];
+ EXPECT_GT(pixel.r, 0x8E - tolerance);
+ EXPECT_LT(pixel.r, 0x8E + tolerance);
+ EXPECT_GT(pixel.g, 0xFF - tolerance);
+ EXPECT_LT(pixel.g, 0xFF + tolerance);
+ EXPECT_GT(pixel.b, 0xF1 - tolerance);
+ EXPECT_LT(pixel.b, 0xF1 + tolerance);
+ }
+ */
}
// Tests the buffers around the screen aren't written to
-TEST(AstJpegDecoder, BufferLimits) {
- ast_video::RawVideoBuffer out;
-
- // This binary blog was created on the aspeed hardware using a black screen
- FILE *fp = fopen("test_resources/aspeedblackscreen.bin", "rb");
- EXPECT_NE(fp, nullptr);
- size_t bufferlen = fread(out.buffer.data(), sizeof(char),
- out.buffer.size() * sizeof(long), fp);
- fclose(fp);
-
- ASSERT_GT(bufferlen, 0);
-
- out.ySelector = 0;
- out.uvSelector = 0;
- out.mode = ast_video::YuvMode::YUV444;
- out.width = 800;
- out.height = 600;
-
- ast_video::AstJpegDecoder d;
- d.decode(out.buffer, out.width, out.height, out.mode, out.ySelector,
- out.uvSelector);
- // reserved pixel should be default value
- for (auto &pixel : d.outBuffer) {
- EXPECT_EQ(pixel.reserved, 0xAA);
- }
- // All pixels beyond the buffer should be zero
- for (int i = out.width * out.height; i < d.outBuffer.size(); i++) {
- EXPECT_EQ(d.outBuffer[i].r, 0x00) << "index:" << i;
- EXPECT_EQ(d.outBuffer[i].b, 0x00) << "index:" << i;
- EXPECT_EQ(d.outBuffer[i].g, 0x00) << "index:" << i;
- }
+TEST(AstJpegDecoder, BufferLimits)
+{
+ ast_video::RawVideoBuffer out;
+
+ // This binary blog was created on the aspeed hardware using a black screen
+ FILE *fp = fopen("test_resources/aspeedblackscreen.bin", "rb");
+ EXPECT_NE(fp, nullptr);
+ size_t bufferlen = fread(out.buffer.data(), sizeof(char),
+ out.buffer.size() * sizeof(long), fp);
+ fclose(fp);
+
+ ASSERT_GT(bufferlen, 0);
+
+ out.ySelector = 0;
+ out.uvSelector = 0;
+ out.mode = ast_video::YuvMode::YUV444;
+ out.width = 800;
+ out.height = 600;
+
+ ast_video::AstJpegDecoder d;
+ d.decode(out.buffer, out.width, out.height, out.mode, out.ySelector,
+ out.uvSelector);
+ // reserved pixel should be default value
+ for (auto &pixel : d.outBuffer)
+ {
+ EXPECT_EQ(pixel.reserved, 0xAA);
+ }
+ // All pixels beyond the buffer should be zero
+ for (int i = out.width * out.height; i < d.outBuffer.size(); i++)
+ {
+ EXPECT_EQ(d.outBuffer[i].r, 0x00) << "index:" << i;
+ EXPECT_EQ(d.outBuffer[i].b, 0x00) << "index:" << i;
+ EXPECT_EQ(d.outBuffer[i].g, 0x00) << "index:" << i;
+ }
} \ No newline at end of file
diff --git a/src/ast_video_puller_test.cpp b/src/ast_video_puller_test.cpp
index 58adda9697..4fa3dccc68 100644
--- a/src/ast_video_puller_test.cpp
+++ b/src/ast_video_puller_test.cpp
@@ -2,6 +2,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
+
#include <ast_jpeg_decoder.hpp>
#include <ast_video_puller.hpp>
#include <chrono>
@@ -10,38 +11,46 @@
#include <iostream>
#include <thread>
#include <vector>
+
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-TEST(AstvideoPuller, BasicRead) {
- ast_video::RawVideoBuffer out;
- bool have_hardware = false;
- if (access("/dev/video", F_OK) != -1) {
- ast_video::SimpleVideoPuller p;
- p.initialize();
- out = p.readVideo();
- } else {
- FILE *fp = fopen("test_resources/ubuntu_444_800x600_0chrom_0lum.bin", "rb");
- if (fp) {
- size_t newLen = fread(out.buffer.data(), sizeof(char),
- out.buffer.size() * sizeof(long), fp);
- if (ferror(fp) != 0) {
- fputs("Error reading file", stderr);
- }
- fclose(fp);
- out.buffer.resize(newLen);
- out.mode = ast_video::YuvMode::YUV444;
- out.width = 800;
- out.height = 600;
- out.ySelector = 0;
- out.uvSelector = 0;
+TEST(AstvideoPuller, BasicRead)
+{
+ ast_video::RawVideoBuffer out;
+ bool have_hardware = false;
+ if (access("/dev/video", F_OK) != -1)
+ {
+ ast_video::SimpleVideoPuller p;
+ p.initialize();
+ out = p.readVideo();
+ }
+ else
+ {
+ FILE *fp =
+ fopen("test_resources/ubuntu_444_800x600_0chrom_0lum.bin", "rb");
+ if (fp)
+ {
+ size_t newLen = fread(out.buffer.data(), sizeof(char),
+ out.buffer.size() * sizeof(long), fp);
+ if (ferror(fp) != 0)
+ {
+ fputs("Error reading file", stderr);
+ }
+ fclose(fp);
+ out.buffer.resize(newLen);
+ out.mode = ast_video::YuvMode::YUV444;
+ out.width = 800;
+ out.height = 600;
+ out.ySelector = 0;
+ out.uvSelector = 0;
+ }
}
- }
- FILE *fp = fopen("/tmp/screendata.bin", "wb");
- fwrite(out.buffer.data(), sizeof(char), out.buffer.size(), fp);
+ FILE *fp = fopen("/tmp/screendata.bin", "wb");
+ fwrite(out.buffer.data(), sizeof(char), out.buffer.size(), fp);
- ast_video::AstJpegDecoder d;
- d.decode(out.buffer, out.width, out.height, out.mode, out.ySelector,
- out.uvSelector);
+ ast_video::AstJpegDecoder d;
+ d.decode(out.buffer, out.width, out.height, out.mode, out.ySelector,
+ out.uvSelector);
}
diff --git a/src/base64.cpp b/src/base64.cpp
index 0013c28ac3..851ef72a42 100644
--- a/src/base64.cpp
+++ b/src/base64.cpp
@@ -1,143 +1,165 @@
#include <base64.hpp>
-namespace base64 {
-bool base64_encode(const std::string &input, std::string &output) {
- // This is left as a raw array (and not a range checked std::array) under the
- // suspicion that the optimizer is not smart enough to remove the range checks
- // that would be done below if at were called. As is, this array is 64 bytes
- // long, which should be greater than the max of 0b00111111 when indexed
- // NOLINT calls below are to silence clang-tidy about this
- // TODO(ed) this requires further investigation if a more safe method could be
- // used without performance impact.
- static const char encoding_data[] =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
-
- size_t input_length = input.size();
-
- // allocate space for output string
- output.clear();
- output.reserve(((input_length + 2) / 3) * 4);
-
- // for each 3-bytes sequence from the input, extract 4 6-bits sequences and
- // encode using
- // encoding_data lookup table.
- // if input do not contains enough chars to complete 3-byte sequence,use pad
- // char '='
- for (size_t i = 0; i < input_length; i++) {
- int base64code0 = 0;
- int base64code1 = 0;
- int base64code2 = 0;
- int base64code3 = 0;
-
- base64code0 = (input[i] >> 2) & 0x3f; // 1-byte 6 bits
-
- output += encoding_data[base64code0]; // NOLINT
- base64code1 = (input[i] << 4) & 0x3f; // 1-byte 2 bits +
-
- if (++i < input_length) {
- base64code1 |= (input[i] >> 4) & 0x0f; // 2-byte 4 bits
- output += encoding_data[base64code1]; // NOLINT
- base64code2 = (input[i] << 2) & 0x3f; // 2-byte 4 bits +
-
- if (++i < input_length) {
- base64code2 |= (input[i] >> 6) & 0x03; // 3-byte 2 bits
- base64code3 = input[i] & 0x3f; // 3-byte 6 bits
- output += encoding_data[base64code2]; // NOLINT
- output += encoding_data[base64code3]; // NOLINT
- } else {
- output += encoding_data[base64code2]; // NOLINT
- output += '=';
- }
- } else {
- output += encoding_data[base64code1]; // NOLINT
- output += '=';
- output += '=';
+namespace base64
+{
+bool base64_encode(const std::string &input, std::string &output)
+{
+ // This is left as a raw array (and not a range checked std::array) under
+ // the suspicion that the optimizer is not smart enough to remove the range
+ // checks that would be done below if at were called. As is, this array is
+ // 64 bytes long, which should be greater than the max of 0b00111111 when
+ // indexed NOLINT calls below are to silence clang-tidy about this
+ // TODO(ed) this requires further investigation if a more safe method could
+ // be used without performance impact.
+ static const char encoding_data[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+ size_t input_length = input.size();
+
+ // allocate space for output string
+ output.clear();
+ output.reserve(((input_length + 2) / 3) * 4);
+
+ // for each 3-bytes sequence from the input, extract 4 6-bits sequences and
+ // encode using
+ // encoding_data lookup table.
+ // if input do not contains enough chars to complete 3-byte sequence,use pad
+ // char '='
+ for (size_t i = 0; i < input_length; i++)
+ {
+ int base64code0 = 0;
+ int base64code1 = 0;
+ int base64code2 = 0;
+ int base64code3 = 0;
+
+ base64code0 = (input[i] >> 2) & 0x3f; // 1-byte 6 bits
+
+ output += encoding_data[base64code0]; // NOLINT
+ base64code1 = (input[i] << 4) & 0x3f; // 1-byte 2 bits +
+
+ if (++i < input_length)
+ {
+ base64code1 |= (input[i] >> 4) & 0x0f; // 2-byte 4 bits
+ output += encoding_data[base64code1]; // NOLINT
+ base64code2 = (input[i] << 2) & 0x3f; // 2-byte 4 bits +
+
+ if (++i < input_length)
+ {
+ base64code2 |= (input[i] >> 6) & 0x03; // 3-byte 2 bits
+ base64code3 = input[i] & 0x3f; // 3-byte 6 bits
+ output += encoding_data[base64code2]; // NOLINT
+ output += encoding_data[base64code3]; // NOLINT
+ }
+ else
+ {
+ output += encoding_data[base64code2]; // NOLINT
+ output += '=';
+ }
+ }
+ else
+ {
+ output += encoding_data[base64code1]; // NOLINT
+ output += '=';
+ output += '=';
+ }
}
- }
- return true;
+ return true;
}
-bool base64_decode(const std::string &input, std::string &output) {
- static const char nop = -1;
- // See note on encoding_data[] in above function
- static const char decoding_data[] = {
- 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 input_length = input.size();
-
- // allocate space for output string
- output.clear();
- output.reserve(((input_length + 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 < input_length; i++) {
- char base64code0;
- char base64code1;
- char base64code2 = 0; // initialized to 0 to suppress warnings
- char base64code3;
-
- base64code0 = decoding_data[static_cast<int>(input[i])]; // NOLINT
- if (base64code0 == nop) { // non base64 character
- return false;
+bool base64_decode(const std::string &input, std::string &output)
+{
+ static const char nop = -1;
+ // See note on encoding_data[] in above function
+ static const char decoding_data[] = {
+ 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 input_length = input.size();
+
+ // allocate space for output string
+ output.clear();
+ output.reserve(((input_length + 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 < input_length; i++)
+ {
+ char base64code0;
+ char base64code1;
+ char base64code2 = 0; // initialized to 0 to suppress warnings
+ char base64code3;
+
+ base64code0 = decoding_data[static_cast<int>(input[i])]; // NOLINT
+ if (base64code0 == nop)
+ { // non base64 character
+ return false;
+ }
+ if (!(++i < input_length))
+ { // we need at least two input bytes for first
+ // byte output
+ return false;
+ }
+ base64code1 = decoding_data[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 < input_length)
+ {
+ char c = input[i];
+ if (c == '=')
+ { // padding , end of input
+ return (base64code1 & 0x0f) == 0;
+ }
+ base64code2 = decoding_data[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 < input_length)
+ {
+ char c = input[i];
+ if (c == '=')
+ { // padding , end of input
+ return (base64code2 & 0x03) == 0;
+ }
+ base64code3 = decoding_data[static_cast<int>(input[i])]; // NOLINT
+ if (base64code3 == nop)
+ { // non base64 character
+ return false;
+ }
+ output +=
+ static_cast<char>((((base64code2 << 6) & 0xc0) | base64code3));
+ }
}
- if (!(++i < input_length)) { // we need at least two input bytes for first
- // byte output
- return false;
- }
- base64code1 = decoding_data[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 < input_length) {
- char c = input[i];
- if (c == '=') { // padding , end of input
- return (base64code1 & 0x0f) == 0;
- }
- base64code2 = decoding_data[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 < input_length) {
- char c = input[i];
- if (c == '=') { // padding , end of input
- return (base64code2 & 0x03) == 0;
- }
- base64code3 = decoding_data[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 base64
+} // namespace base64
diff --git a/src/crow_getroutes_test.cpp b/src/crow_getroutes_test.cpp
index 29052a9a21..e76d221479 100644
--- a/src/crow_getroutes_test.cpp
+++ b/src/crow_getroutes_test.cpp
@@ -1,43 +1,47 @@
#include <crow/app.h>
+
#include "gmock/gmock.h"
#include "gtest/gtest.h"
using namespace crow;
using namespace std;
-TEST(GetRoutes, TestEmptyRoutes) {
- SimpleApp app;
- decltype(app)::server_t server(&app, "127.0.0.1", 45451);
+TEST(GetRoutes, TestEmptyRoutes)
+{
+ SimpleApp app;
+ decltype(app)::server_t server(&app, "127.0.0.1", 45451);
- EXPECT_THAT(app.getRoutes(), testing::IsEmpty());
+ EXPECT_THAT(app.getRoutes(), testing::IsEmpty());
}
// Tests that static urls are correctly passed
-TEST(GetRoutes, TestOneRoute) {
- SimpleApp app;
- decltype(app)::server_t server(&app, "127.0.0.1", 45451);
- BMCWEB_ROUTE(app, "/")([]() { return boost::beast::http::status::ok; });
+TEST(GetRoutes, TestOneRoute)
+{
+ SimpleApp app;
+ decltype(app)::server_t server(&app, "127.0.0.1", 45451);
+ BMCWEB_ROUTE(app, "/")([]() { return boost::beast::http::status::ok; });
- EXPECT_THAT(app.getRoutes(),
- testing::ElementsAre(testing::Pointee(std::string("/"))));
+ EXPECT_THAT(app.getRoutes(),
+ testing::ElementsAre(testing::Pointee(std::string("/"))));
}
// Tests that static urls are correctly passed
-TEST(GetRoutes, TestlotsOfRoutes) {
- SimpleApp app;
- decltype(app)::server_t server(&app, "127.0.0.1", 45451);
- BMCWEB_ROUTE(app, "/")([]() { return boost::beast::http::status::ok; });
- BMCWEB_ROUTE(app, "/foo")([]() { return boost::beast::http::status::ok; });
- BMCWEB_ROUTE(app, "/bar")([]() { return boost::beast::http::status::ok; });
- BMCWEB_ROUTE(app, "/baz")([]() { return boost::beast::http::status::ok; });
- BMCWEB_ROUTE(app, "/boo")([]() { return boost::beast::http::status::ok; });
- BMCWEB_ROUTE(app, "/moo")([]() { return boost::beast::http::status::ok; });
-
- EXPECT_THAT(app.getRoutes(), testing::UnorderedElementsAre(
- testing::Pointee(std::string("/")),
- testing::Pointee(std::string("/foo")),
- testing::Pointee(std::string("/bar")),
- testing::Pointee(std::string("/baz")),
- testing::Pointee(std::string("/boo")),
- testing::Pointee(std::string("/moo"))));
+TEST(GetRoutes, TestlotsOfRoutes)
+{
+ SimpleApp app;
+ decltype(app)::server_t server(&app, "127.0.0.1", 45451);
+ BMCWEB_ROUTE(app, "/")([]() { return boost::beast::http::status::ok; });
+ BMCWEB_ROUTE(app, "/foo")([]() { return boost::beast::http::status::ok; });
+ BMCWEB_ROUTE(app, "/bar")([]() { return boost::beast::http::status::ok; });
+ BMCWEB_ROUTE(app, "/baz")([]() { return boost::beast::http::status::ok; });
+ BMCWEB_ROUTE(app, "/boo")([]() { return boost::beast::http::status::ok; });
+ BMCWEB_ROUTE(app, "/moo")([]() { return boost::beast::http::status::ok; });
+
+ EXPECT_THAT(app.getRoutes(), testing::UnorderedElementsAre(
+ testing::Pointee(std::string("/")),
+ testing::Pointee(std::string("/foo")),
+ testing::Pointee(std::string("/bar")),
+ testing::Pointee(std::string("/baz")),
+ testing::Pointee(std::string("/boo")),
+ testing::Pointee(std::string("/moo"))));
} \ No newline at end of file
diff --git a/src/crow_test.cpp b/src/crow_test.cpp
index cd668171db..96b90b0ed2 100644
--- a/src/crow_test.cpp
+++ b/src/crow_test.cpp
@@ -1,7 +1,9 @@
-#include "crow.h"
#include <iostream>
#include <sstream>
#include <vector>
+
+#include "crow.h"
+
#include "gtest/gtest.h"
#undef BMCWEB_LOG_LEVEL
#define BMCWEB_LOG_LEVEL 0
@@ -10,864 +12,934 @@ using namespace std;
using namespace crow;
bool failed__ = false;
-void error_print() { cerr << endl; }
+void error_print()
+{
+ cerr << endl;
+}
template <typename A, typename... Args>
-void error_print(const A& a, Args... args) {
- cerr << a;
- error_print(args...);
+void error_print(const A& a, Args... args)
+{
+ cerr << a;
+ error_print(args...);
}
-template <typename... Args>
-void fail(Args... args) {
- error_print(args...);
- failed__ = true;
+template <typename... Args> void fail(Args... args)
+{
+ error_print(args...);
+ failed__ = true;
}
-#define ASSERT_EQUAL(a, b) \
- if ((a) != (b)) \
- fail(__FILE__ ":", __LINE__, ": Assert fail: expected ", (a), " actual ", \
- (b), ", " #a " == " #b ", at " __FILE__ ":", __LINE__)
-#define ASSERT_NOTEQUAL(a, b) \
- if ((a) == (b)) \
- fail(__FILE__ ":", __LINE__, ": Assert fail: not expected ", (a), \
- ", " #a " != " #b ", at " __FILE__ ":", __LINE__)
-
-#define DISABLE_TEST(x) \
- struct test##x { \
- void test(); \
- } x##_; \
- void test##x::test()
+#define ASSERT_EQUAL(a, b) \
+ if ((a) != (b)) \
+ fail(__FILE__ ":", __LINE__, ": Assert fail: expected ", (a), " actual ", \
+ (b), ", " #a " == " #b ", at " __FILE__ ":", __LINE__)
+#define ASSERT_NOTEQUAL(a, b) \
+ if ((a) == (b)) \
+ fail(__FILE__ ":", __LINE__, ": Assert fail: not expected ", (a), \
+ ", " #a " != " #b ", at " __FILE__ ":", __LINE__)
+
+#define DISABLE_TEST(x) \
+ struct test##x \
+ { \
+ void test(); \
+ } x##_; \
+ void test##x::test()
#define LOCALHOST_ADDRESS "127.0.0.1"
-TEST(Crow, Rule) {
- TaggedRule<> r("/http/");
- r.name("abc");
+TEST(Crow, Rule)
+{
+ TaggedRule<> r("/http/");
+ r.name("abc");
- // empty handler - fail to validate
- try {
- r.validate();
- fail("empty handler should fail to validate");
- } catch (runtime_error& e) {
- }
+ // empty handler - fail to validate
+ try
+ {
+ r.validate();
+ fail("empty handler should fail to validate");
+ }
+ catch (runtime_error& e)
+ {
+ }
- int x = 0;
+ int x = 0;
- // registering handler
- r([&x] {
- x = 1;
- return "";
- });
+ // registering handler
+ r([&x] {
+ x = 1;
+ return "";
+ });
- r.validate();
+ r.validate();
- Response res;
+ Response res;
- // executing handler
- ASSERT_EQUAL(0, x);
- boost::beast::http::request<boost::beast::http::string_body> req{};
- r.handle(Request(req), res, RoutingParams());
- ASSERT_EQUAL(1, x);
+ // executing handler
+ ASSERT_EQUAL(0, x);
+ boost::beast::http::request<boost::beast::http::string_body> req{};
+ r.handle(Request(req), res, RoutingParams());
+ ASSERT_EQUAL(1, x);
- // registering handler with Request argument
- r([&x](const crow::Request&) {
- x = 2;
- return "";
- });
+ // registering handler with Request argument
+ r([&x](const crow::Request&) {
+ x = 2;
+ return "";
+ });
- r.validate();
+ r.validate();
- // executing handler
- ASSERT_EQUAL(1, x);
- r.handle(Request(req), res, RoutingParams());
- ASSERT_EQUAL(2, x);
+ // executing handler
+ ASSERT_EQUAL(1, x);
+ r.handle(Request(req), res, RoutingParams());
+ ASSERT_EQUAL(2, x);
}
-TEST(Crow, ParameterTagging) {
- static_assert(black_magic::isValid("<int><int><int>"), "valid url");
- static_assert(!black_magic::isValid("<int><int<<int>"), "invalid url");
- static_assert(!black_magic::isValid("nt>"), "invalid url");
- ASSERT_EQUAL(1, black_magic::get_parameter_tag("<int>"));
- ASSERT_EQUAL(2, black_magic::get_parameter_tag("<uint>"));
- ASSERT_EQUAL(3, black_magic::get_parameter_tag("<float>"));
- ASSERT_EQUAL(3, black_magic::get_parameter_tag("<double>"));
- ASSERT_EQUAL(4, black_magic::get_parameter_tag("<str>"));
- ASSERT_EQUAL(4, black_magic::get_parameter_tag("<string>"));
- ASSERT_EQUAL(5, black_magic::get_parameter_tag("<path>"));
- ASSERT_EQUAL(6 * 6 + 6 + 1,
- black_magic::get_parameter_tag("<int><int><int>"));
- ASSERT_EQUAL(6 * 6 + 6 + 2,
- black_magic::get_parameter_tag("<uint><int><int>"));
- ASSERT_EQUAL(6 * 6 + 6 * 3 + 2,
- black_magic::get_parameter_tag("<uint><double><int>"));
-
- // url definition parsed in compile time, build into *one number*, and given
- // to template argument
- static_assert(
- std::is_same<black_magic::S<uint64_t, double, int64_t>,
- black_magic::Arguments<6 * 6 + 6 * 3 + 2>::type>::value,
- "tag to type container");
+TEST(Crow, ParameterTagging)
+{
+ static_assert(black_magic::isValid("<int><int><int>"), "valid url");
+ static_assert(!black_magic::isValid("<int><int<<int>"), "invalid url");
+ static_assert(!black_magic::isValid("nt>"), "invalid url");
+ ASSERT_EQUAL(1, black_magic::get_parameter_tag("<int>"));
+ ASSERT_EQUAL(2, black_magic::get_parameter_tag("<uint>"));
+ ASSERT_EQUAL(3, black_magic::get_parameter_tag("<float>"));
+ ASSERT_EQUAL(3, black_magic::get_parameter_tag("<double>"));
+ ASSERT_EQUAL(4, black_magic::get_parameter_tag("<str>"));
+ ASSERT_EQUAL(4, black_magic::get_parameter_tag("<string>"));
+ ASSERT_EQUAL(5, black_magic::get_parameter_tag("<path>"));
+ ASSERT_EQUAL(6 * 6 + 6 + 1,
+ black_magic::get_parameter_tag("<int><int><int>"));
+ ASSERT_EQUAL(6 * 6 + 6 + 2,
+ black_magic::get_parameter_tag("<uint><int><int>"));
+ ASSERT_EQUAL(6 * 6 + 6 * 3 + 2,
+ black_magic::get_parameter_tag("<uint><double><int>"));
+
+ // url definition parsed in compile time, build into *one number*, and given
+ // to template argument
+ static_assert(
+ std::is_same<black_magic::S<uint64_t, double, int64_t>,
+ black_magic::Arguments<6 * 6 + 6 * 3 + 2>::type>::value,
+ "tag to type container");
}
-TEST(Crow, PathRouting) {
- SimpleApp app;
+TEST(Crow, PathRouting)
+{
+ SimpleApp app;
- BMCWEB_ROUTE(app, "/file")
- ([] { return "file"; });
+ BMCWEB_ROUTE(app, "/file")
+ ([] { return "file"; });
- BMCWEB_ROUTE(app, "/path/")
- ([] { return "path"; });
+ BMCWEB_ROUTE(app, "/path/")
+ ([] { return "path"; });
- {
- boost::beast::http::request<boost::beast::http::string_body> r{};
- Request req{r};
- Response res;
+ {
+ boost::beast::http::request<boost::beast::http::string_body> r{};
+ Request req{r};
+ Response res;
- req.url = "/file";
+ req.url = "/file";
- app.handle(req, res);
+ app.handle(req, res);
- ASSERT_EQUAL(200, res.resultInt());
- }
- {
- boost::beast::http::request<boost::beast::http::string_body> r{};
- Request req{r};
- Response res;
+ ASSERT_EQUAL(200, res.resultInt());
+ }
+ {
+ boost::beast::http::request<boost::beast::http::string_body> r{};
+ Request req{r};
+ Response res;
- req.url = "/file/";
+ req.url = "/file/";
- app.handle(req, res);
- ASSERT_EQUAL(404, res.resultInt());
- }
- {
- boost::beast::http::request<boost::beast::http::string_body> r{};
- Request req{r};
- Response res;
+ app.handle(req, res);
+ ASSERT_EQUAL(404, res.resultInt());
+ }
+ {
+ boost::beast::http::request<boost::beast::http::string_body> r{};
+ Request req{r};
+ Response res;
- req.url = "/path";
+ req.url = "/path";
- app.handle(req, res);
- ASSERT_NOTEQUAL(404, res.resultInt());
- }
- {
- boost::beast::http::request<boost::beast::http::string_body> r{};
- Request req{r};
- Response res;
+ app.handle(req, res);
+ ASSERT_NOTEQUAL(404, res.resultInt());
+ }
+ {
+ boost::beast::http::request<boost::beast::http::string_body> r{};
+ Request req{r};
+ Response res;
- req.url = "/path/";
+ req.url = "/path/";
- app.handle(req, res);
- ASSERT_EQUAL(200, res.resultInt());
- }
+ app.handle(req, res);
+ ASSERT_EQUAL(200, res.resultInt());
+ }
}
-TEST(Crow, RoutingTest) {
- SimpleApp app;
- int A{};
- uint32_t b{};
- double C{};
- string D{};
- string E{};
-
- BMCWEB_ROUTE(app, "/0/<uint>")
- ([&](uint32_t b) {
- b = b;
- return "OK";
- });
-
- BMCWEB_ROUTE(app, "/1/<int>/<uint>")
- ([&](int a, uint32_t b) {
- A = a;
- b = b;
- return "OK";
- });
-
- BMCWEB_ROUTE(app, "/4/<int>/<uint>/<double>/<string>")
- ([&](int a, uint32_t b, double c, string d) {
- A = a;
- b = b;
- C = c;
- D = d;
- return "OK";
- });
-
- BMCWEB_ROUTE(app, "/5/<int>/<uint>/<double>/<string>/<path>")
- ([&](int a, uint32_t b, double c, string d, string e) {
- A = a;
- b = b;
- C = c;
- D = d;
- E = e;
- return "OK";
- });
-
- app.validate();
- // app.debugPrint();
- {
- boost::beast::http::request<boost::beast::http::string_body> r{};
- Request req{r};
- Response res;
+TEST(Crow, RoutingTest)
+{
+ SimpleApp app;
+ int A{};
+ uint32_t b{};
+ double C{};
+ string D{};
+ string E{};
+
+ BMCWEB_ROUTE(app, "/0/<uint>")
+ ([&](uint32_t b) {
+ b = b;
+ return "OK";
+ });
+
+ BMCWEB_ROUTE(app, "/1/<int>/<uint>")
+ ([&](int a, uint32_t b) {
+ A = a;
+ b = b;
+ return "OK";
+ });
+
+ BMCWEB_ROUTE(app, "/4/<int>/<uint>/<double>/<string>")
+ ([&](int a, uint32_t b, double c, string d) {
+ A = a;
+ b = b;
+ C = c;
+ D = d;
+ return "OK";
+ });
+
+ BMCWEB_ROUTE(app, "/5/<int>/<uint>/<double>/<string>/<path>")
+ ([&](int a, uint32_t b, double c, string d, string e) {
+ A = a;
+ b = b;
+ C = c;
+ D = d;
+ E = e;
+ return "OK";
+ });
- req.url = "/-1";
+ app.validate();
+ // app.debugPrint();
+ {
+ boost::beast::http::request<boost::beast::http::string_body> r{};
+ Request req{r};
+ Response res;
- app.handle(req, res);
+ req.url = "/-1";
- ASSERT_EQUAL(404, res.resultInt());
- }
+ app.handle(req, res);
- {
- boost::beast::http::request<boost::beast::http::string_body> r{};
- Request req{r};
- Response res;
+ ASSERT_EQUAL(404, res.resultInt());
+ }
- req.url = "/0/1001999";
+ {
+ boost::beast::http::request<boost::beast::http::string_body> r{};
+ Request req{r};
+ Response res;
- app.handle(req, res);
+ req.url = "/0/1001999";
- ASSERT_EQUAL(200, res.resultInt());
+ app.handle(req, res);
- ASSERT_EQUAL(1001999, b);
- }
+ ASSERT_EQUAL(200, res.resultInt());
- {
- boost::beast::http::request<boost::beast::http::string_body> r{};
- Request req{r};
- Response res;
+ ASSERT_EQUAL(1001999, b);
+ }
- req.url = "/1/-100/1999";
+ {
+ boost::beast::http::request<boost::beast::http::string_body> r{};
+ Request req{r};
+ Response res;
- app.handle(req, res);
+ req.url = "/1/-100/1999";
- ASSERT_EQUAL(200, res.resultInt());
+ app.handle(req, res);
- ASSERT_EQUAL(-100, A);
- ASSERT_EQUAL(1999, b);
- }
- {
- boost::beast::http::request<boost::beast::http::string_body> r{};
- Request req{r};
- Response res;
+ ASSERT_EQUAL(200, res.resultInt());
- req.url = "/4/5000/3/-2.71828/hellhere";
+ ASSERT_EQUAL(-100, A);
+ ASSERT_EQUAL(1999, b);
+ }
+ {
+ boost::beast::http::request<boost::beast::http::string_body> r{};
+ Request req{r};
+ Response res;
- app.handle(req, res);
+ req.url = "/4/5000/3/-2.71828/hellhere";
- ASSERT_EQUAL(200, res.resultInt());
+ app.handle(req, res);
- ASSERT_EQUAL(5000, A);
- ASSERT_EQUAL(3, b);
- ASSERT_EQUAL(-2.71828, C);
- ASSERT_EQUAL("hellhere", D);
- }
- {
- boost::beast::http::request<boost::beast::http::string_body> r{};
- Request req{r};
- Response res;
+ ASSERT_EQUAL(200, res.resultInt());
- req.url = "/5/-5/999/3.141592/hello_there/a/b/c/d";
+ ASSERT_EQUAL(5000, A);
+ ASSERT_EQUAL(3, b);
+ ASSERT_EQUAL(-2.71828, C);
+ ASSERT_EQUAL("hellhere", D);
+ }
+ {
+ boost::beast::http::request<boost::beast::http::string_body> r{};
+ Request req{r};
+ Response res;
- app.handle(req, res);
+ req.url = "/5/-5/999/3.141592/hello_there/a/b/c/d";
- ASSERT_EQUAL(200, res.resultInt());
+ app.handle(req, res);
- ASSERT_EQUAL(-5, A);
- ASSERT_EQUAL(999, b);
- ASSERT_EQUAL(3.141592, C);
- ASSERT_EQUAL("hello_there", D);
- ASSERT_EQUAL("a/b/c/d", E);
- }
+ ASSERT_EQUAL(200, res.resultInt());
+
+ ASSERT_EQUAL(-5, A);
+ ASSERT_EQUAL(999, b);
+ ASSERT_EQUAL(3.141592, C);
+ ASSERT_EQUAL("hello_there", D);
+ ASSERT_EQUAL("a/b/c/d", E);
+ }
}
-TEST(Crow, simple_response_RoutingParams) {
- ASSERT_EQUAL(100,
- Response(boost::beast::http::status::continue_).resultInt());
- ASSERT_EQUAL(200, Response("Hello there").resultInt());
- ASSERT_EQUAL(500, Response(boost::beast::http::status::internal_server_error,
- "Internal Error?")
- .resultInt());
-
- RoutingParams rp;
- rp.intParams.push_back(1);
- rp.intParams.push_back(5);
- rp.uintParams.push_back(2);
- rp.doubleParams.push_back(3);
- rp.stringParams.push_back("hello");
- ASSERT_EQUAL(1, rp.get<int64_t>(0));
- ASSERT_EQUAL(5, rp.get<int64_t>(1));
- ASSERT_EQUAL(2, rp.get<uint64_t>(0));
- ASSERT_EQUAL(3, rp.get<double>(0));
- ASSERT_EQUAL("hello", rp.get<string>(0));
+TEST(Crow, simple_response_RoutingParams)
+{
+ ASSERT_EQUAL(100,
+ Response(boost::beast::http::status::continue_).resultInt());
+ ASSERT_EQUAL(200, Response("Hello there").resultInt());
+ ASSERT_EQUAL(500,
+ Response(boost::beast::http::status::internal_server_error,
+ "Internal Error?")
+ .resultInt());
+
+ RoutingParams rp;
+ rp.intParams.push_back(1);
+ rp.intParams.push_back(5);
+ rp.uintParams.push_back(2);
+ rp.doubleParams.push_back(3);
+ rp.stringParams.push_back("hello");
+ ASSERT_EQUAL(1, rp.get<int64_t>(0));
+ ASSERT_EQUAL(5, rp.get<int64_t>(1));
+ ASSERT_EQUAL(2, rp.get<uint64_t>(0));
+ ASSERT_EQUAL(3, rp.get<double>(0));
+ ASSERT_EQUAL("hello", rp.get<string>(0));
}
-TEST(Crow, handler_with_response) {
- SimpleApp app;
- BMCWEB_ROUTE(app, "/")([](const crow::Request&, crow::Response&) {});
+TEST(Crow, handler_with_response)
+{
+ SimpleApp app;
+ BMCWEB_ROUTE(app, "/")([](const crow::Request&, crow::Response&) {});
}
-TEST(Crow, http_method) {
- SimpleApp app;
-
- BMCWEB_ROUTE(app, "/").methods("POST"_method,
- "GET"_method)([](const Request& req) {
- if (req.method() == "GET"_method)
- return "2";
- else
- return "1";
- });
-
- BMCWEB_ROUTE(app, "/get_only")
- .methods("GET"_method)([](const Request& /*req*/) { return "get"; });
- BMCWEB_ROUTE(app, "/post_only")
- .methods("POST"_method)([](const Request& /*req*/) { return "post"; });
-
- // cannot have multiple handlers for the same url
- // BMCWEB_ROUTE(app, "/")
- //.methods("GET"_method)
- //([]{ return "2"; });
-
- {
- boost::beast::http::request<boost::beast::http::string_body> r{};
- Request req{r};
- Response res;
+TEST(Crow, http_method)
+{
+ SimpleApp app;
- req.url = "/";
- app.handle(req, res);
+ BMCWEB_ROUTE(app, "/").methods("POST"_method,
+ "GET"_method)([](const Request& req) {
+ if (req.method() == "GET"_method)
+ return "2";
+ else
+ return "1";
+ });
- ASSERT_EQUAL("2", res.body());
- }
- {
- boost::beast::http::request<boost::beast::http::string_body> r{};
- Request req{r};
- Response res;
+ BMCWEB_ROUTE(app, "/get_only")
+ .methods("GET"_method)([](const Request& /*req*/) { return "get"; });
+ BMCWEB_ROUTE(app, "/post_only")
+ .methods("POST"_method)([](const Request& /*req*/) { return "post"; });
- req.url = "/";
- r.method("POST"_method);
- app.handle(req, res);
+ // cannot have multiple handlers for the same url
+ // BMCWEB_ROUTE(app, "/")
+ //.methods("GET"_method)
+ //([]{ return "2"; });
- ASSERT_EQUAL("1", res.body());
- }
+ {
+ boost::beast::http::request<boost::beast::http::string_body> r{};
+ Request req{r};
+ Response res;
- {
- boost::beast::http::request<boost::beast::http::string_body> r{};
- Request req{r};
- Response res;
+ req.url = "/";
+ app.handle(req, res);
+
+ ASSERT_EQUAL("2", res.body());
+ }
+ {
+ boost::beast::http::request<boost::beast::http::string_body> r{};
+ Request req{r};
+ Response res;
- req.url = "/get_only";
- app.handle(req, res);
+ req.url = "/";
+ r.method("POST"_method);
+ app.handle(req, res);
- ASSERT_EQUAL("get", res.body());
- }
+ ASSERT_EQUAL("1", res.body());
+ }
- {
- boost::beast::http::request<boost::beast::http::string_body> r{};
- Request req{r};
- Response res;
+ {
+ boost::beast::http::request<boost::beast::http::string_body> r{};
+ Request req{r};
+ Response res;
- req.url = "/get_only";
- r.method("POST"_method);
- app.handle(req, res);
+ req.url = "/get_only";
+ app.handle(req, res);
- ASSERT_NOTEQUAL("get", res.body());
- }
-}
+ ASSERT_EQUAL("get", res.body());
+ }
-TEST(Crow, server_handling_error_request) {
- static char buf[2048];
- SimpleApp app;
- BMCWEB_ROUTE(app, "/")([] { return "A"; });
- Server<SimpleApp> server(&app, LOCALHOST_ADDRESS, 45451);
- auto _ = async(launch::async, [&] { server.run(); });
- std::string sendmsg = "POX";
- asio::io_service is;
- {
- asio::ip::tcp::socket c(is);
- c.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
-
- c.send(asio::buffer(sendmsg));
-
- try {
- c.receive(asio::buffer(buf, 2048));
- fail();
- } catch (std::exception& e) {
- // std::cerr << e.what() << std::endl;
- }
- }
- server.stop();
+ {
+ boost::beast::http::request<boost::beast::http::string_body> r{};
+ Request req{r};
+ Response res;
+
+ req.url = "/get_only";
+ r.method("POST"_method);
+ app.handle(req, res);
+
+ ASSERT_NOTEQUAL("get", res.body());
+ }
}
-TEST(Crow, multi_server) {
- static char buf[2048];
- SimpleApp app1, app2;
- BMCWEB_ROUTE(app1, "/").methods("GET"_method,
- "POST"_method)([] { return "A"; });
- BMCWEB_ROUTE(app2, "/").methods("GET"_method,
- "POST"_method)([] { return "B"; });
+TEST(Crow, server_handling_error_request)
+{
+ static char buf[2048];
+ SimpleApp app;
+ BMCWEB_ROUTE(app, "/")([] { return "A"; });
+ Server<SimpleApp> server(&app, LOCALHOST_ADDRESS, 45451);
+ auto _ = async(launch::async, [&] { server.run(); });
+ std::string sendmsg = "POX";
+ asio::io_service is;
+ {
+ asio::ip::tcp::socket c(is);
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
- Server<SimpleApp> server1(&app1, LOCALHOST_ADDRESS, 45451);
- Server<SimpleApp> server2(&app2, LOCALHOST_ADDRESS, 45452);
+ c.send(asio::buffer(sendmsg));
- auto _ = async(launch::async, [&] { server1.run(); });
- auto _2 = async(launch::async, [&] { server2.run(); });
+ try
+ {
+ c.receive(asio::buffer(buf, 2048));
+ fail();
+ }
+ catch (std::exception& e)
+ {
+ // std::cerr << e.what() << std::endl;
+ }
+ }
+ server.stop();
+}
- std::string sendmsg =
- "POST /\r\nContent-Length:3\r\nX-HeaderTest: 123\r\n\r\nA=b\r\n";
- asio::io_service is;
- {
- asio::ip::tcp::socket c(is);
- c.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
+TEST(Crow, multi_server)
+{
+ static char buf[2048];
+ SimpleApp app1, app2;
+ BMCWEB_ROUTE(app1, "/").methods("GET"_method,
+ "POST"_method)([] { return "A"; });
+ BMCWEB_ROUTE(app2, "/").methods("GET"_method,
+ "POST"_method)([] { return "B"; });
- c.send(asio::buffer(sendmsg));
+ Server<SimpleApp> server1(&app1, LOCALHOST_ADDRESS, 45451);
+ Server<SimpleApp> server2(&app2, LOCALHOST_ADDRESS, 45452);
- size_t recved = c.receive(asio::buffer(buf, 2048));
- ASSERT_EQUAL('A', buf[recved - 1]);
- }
+ auto _ = async(launch::async, [&] { server1.run(); });
+ auto _2 = async(launch::async, [&] { server2.run(); });
- {
- asio::ip::tcp::socket c(is);
- c.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string(LOCALHOST_ADDRESS), 45452));
+ std::string sendmsg =
+ "POST /\r\nContent-Length:3\r\nX-HeaderTest: 123\r\n\r\nA=b\r\n";
+ asio::io_service is;
+ {
+ asio::ip::tcp::socket c(is);
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
+
+ c.send(asio::buffer(sendmsg));
- for (auto ch : sendmsg) {
- char buf[1] = {ch};
- c.send(asio::buffer(buf));
+ size_t recved = c.receive(asio::buffer(buf, 2048));
+ ASSERT_EQUAL('A', buf[recved - 1]);
}
- size_t recved = c.receive(asio::buffer(buf, 2048));
- ASSERT_EQUAL('b', buf[recved - 1]);
- }
+ {
+ asio::ip::tcp::socket c(is);
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string(LOCALHOST_ADDRESS), 45452));
+
+ for (auto ch : sendmsg)
+ {
+ char buf[1] = {ch};
+ c.send(asio::buffer(buf));
+ }
+
+ size_t recved = c.receive(asio::buffer(buf, 2048));
+ ASSERT_EQUAL('b', buf[recved - 1]);
+ }
- server1.stop();
- server2.stop();
+ server1.stop();
+ server2.stop();
}
-TEST(Crow, black_magic) {
- using namespace black_magic;
- static_assert(
- std::is_same<void, LastElementType<int, char, void>::type>::value,
- "LastElementType");
- static_assert(
- std::is_same<
- char, PopBack<int, char, void>::rebind<LastElementType>::type>::value,
- "pop_back");
- static_assert(
- std::is_same<int, PopBack<int, char, void>::rebind<PopBack>::rebind<
- LastElementType>::type>::value,
- "pop_back");
+TEST(Crow, black_magic)
+{
+ using namespace black_magic;
+ static_assert(
+ std::is_same<void, LastElementType<int, char, void>::type>::value,
+ "LastElementType");
+ static_assert(
+ std::is_same<char, PopBack<int, char,
+ void>::rebind<LastElementType>::type>::value,
+ "pop_back");
+ static_assert(
+ std::is_same<int, PopBack<int, char, void>::rebind<PopBack>::rebind<
+ LastElementType>::type>::value,
+ "pop_back");
}
-struct NullMiddleware {
- struct Context {};
+struct NullMiddleware
+{
+ struct Context
+ {
+ };
- template <typename AllContext>
- void beforeHandle(Request&, Response&, Context&, AllContext&) {}
+ template <typename AllContext>
+ void beforeHandle(Request&, Response&, Context&, AllContext&)
+ {
+ }
- template <typename AllContext>
- void afterHandle(Request&, Response&, Context&, AllContext&) {}
+ template <typename AllContext>
+ void afterHandle(Request&, Response&, Context&, AllContext&)
+ {
+ }
};
-struct NullSimpleMiddleware {
- struct Context {};
+struct NullSimpleMiddleware
+{
+ struct Context
+ {
+ };
- void beforeHandle(Request& /*req*/, Response& /*res*/, Context& /*ctx*/) {}
+ void beforeHandle(Request& /*req*/, Response& /*res*/, Context& /*ctx*/)
+ {
+ }
- void afterHandle(Request& /*req*/, Response& /*res*/, Context& /*ctx*/) {}
+ void afterHandle(Request& /*req*/, Response& /*res*/, Context& /*ctx*/)
+ {
+ }
};
-TEST(Crow, middleware_simple) {
- App<NullMiddleware, NullSimpleMiddleware> app;
- decltype(app)::server_t server(&app, LOCALHOST_ADDRESS, 45451);
- BMCWEB_ROUTE(app, "/")
- ([&](const crow::Request& req) {
- app.getContext<NullMiddleware>(req);
- app.getContext<NullSimpleMiddleware>(req);
- return "";
- });
+TEST(Crow, middleware_simple)
+{
+ App<NullMiddleware, NullSimpleMiddleware> app;
+ decltype(app)::server_t server(&app, LOCALHOST_ADDRESS, 45451);
+ BMCWEB_ROUTE(app, "/")
+ ([&](const crow::Request& req) {
+ app.getContext<NullMiddleware>(req);
+ app.getContext<NullSimpleMiddleware>(req);
+ return "";
+ });
}
-struct IntSettingMiddleware {
- struct Context {
- int val;
- };
+struct IntSettingMiddleware
+{
+ struct Context
+ {
+ int val;
+ };
- template <typename AllContext>
- void beforeHandle(Request&, Response&, Context& ctx, AllContext&) {
- ctx.val = 1;
- }
+ template <typename AllContext>
+ void beforeHandle(Request&, Response&, Context& ctx, AllContext&)
+ {
+ ctx.val = 1;
+ }
- template <typename AllContext>
- void afterHandle(Request&, Response&, Context& ctx, AllContext&) {
- ctx.val = 2;
- }
+ template <typename AllContext>
+ void afterHandle(Request&, Response&, Context& ctx, AllContext&)
+ {
+ ctx.val = 2;
+ }
};
std::vector<std::string> test_middleware_context_vector;
-struct FirstMW {
- struct Context {
- std::vector<string> v;
- };
+struct FirstMW
+{
+ struct Context
+ {
+ std::vector<string> v;
+ };
- void beforeHandle(Request& /*req*/, Response& /*res*/, Context& ctx) {
- ctx.v.push_back("1 before");
- }
+ void beforeHandle(Request& /*req*/, Response& /*res*/, Context& ctx)
+ {
+ ctx.v.push_back("1 before");
+ }
- void afterHandle(Request& /*req*/, Response& /*res*/, Context& ctx) {
- ctx.v.push_back("1 after");
- test_middleware_context_vector = ctx.v;
- }
+ void afterHandle(Request& /*req*/, Response& /*res*/, Context& ctx)
+ {
+ ctx.v.push_back("1 after");
+ test_middleware_context_vector = ctx.v;
+ }
};
-struct SecondMW {
- struct Context {};
- template <typename AllContext>
- void beforeHandle(Request& req, Response& res, Context&,
- AllContext& all_ctx) {
- all_ctx.template get<FirstMW>().v.push_back("2 before");
- if (req.url == "/break") res.end();
- }
-
- template <typename AllContext>
- void afterHandle(Request&, Response&, Context&, AllContext& all_ctx) {
- all_ctx.template get<FirstMW>().v.push_back("2 after");
- }
+struct SecondMW
+{
+ struct Context
+ {
+ };
+ template <typename AllContext>
+ void beforeHandle(Request& req, Response& res, Context&,
+ AllContext& all_ctx)
+ {
+ all_ctx.template get<FirstMW>().v.push_back("2 before");
+ if (req.url == "/break")
+ res.end();
+ }
+
+ template <typename AllContext>
+ void afterHandle(Request&, Response&, Context&, AllContext& all_ctx)
+ {
+ all_ctx.template get<FirstMW>().v.push_back("2 after");
+ }
};
-struct ThirdMW {
- struct Context {};
- template <typename AllContext>
- void beforeHandle(Request&, Response&, Context&, AllContext& all_ctx) {
- all_ctx.template get<FirstMW>().v.push_back("3 before");
- }
-
- template <typename AllContext>
- void afterHandle(Request&, Response&, Context&, AllContext& all_ctx) {
- all_ctx.template get<FirstMW>().v.push_back("3 after");
- }
+struct ThirdMW
+{
+ struct Context
+ {
+ };
+ template <typename AllContext>
+ void beforeHandle(Request&, Response&, Context&, AllContext& all_ctx)
+ {
+ all_ctx.template get<FirstMW>().v.push_back("3 before");
+ }
+
+ template <typename AllContext>
+ void afterHandle(Request&, Response&, Context&, AllContext& all_ctx)
+ {
+ all_ctx.template get<FirstMW>().v.push_back("3 after");
+ }
};
-TEST(Crow, middlewareContext) {
- static char buf[2048];
- // SecondMW depends on FirstMW (it uses all_ctx.get<FirstMW>)
- // so it leads to compile error if we remove FirstMW from definition
- // App<IntSettingMiddleware, SecondMW> app;
- // or change the order of FirstMW and SecondMW
- // App<IntSettingMiddleware, SecondMW, FirstMW> app;
+TEST(Crow, middlewareContext)
+{
+ static char buf[2048];
+ // SecondMW depends on FirstMW (it uses all_ctx.get<FirstMW>)
+ // so it leads to compile error if we remove FirstMW from definition
+ // App<IntSettingMiddleware, SecondMW> app;
+ // or change the order of FirstMW and SecondMW
+ // App<IntSettingMiddleware, SecondMW, FirstMW> app;
+
+ App<IntSettingMiddleware, FirstMW, SecondMW, ThirdMW> app;
+
+ int x{};
+ BMCWEB_ROUTE(app, "/")
+ ([&](const Request& req) {
+ {
+ auto& ctx = app.getContext<IntSettingMiddleware>(req);
+ x = ctx.val;
+ }
+ {
+ auto& ctx = app.getContext<FirstMW>(req);
+ ctx.v.push_back("handle");
+ }
+
+ return "";
+ });
+ BMCWEB_ROUTE(app, "/break")
+ ([&](const Request& req) {
+ {
+ auto& ctx = app.getContext<FirstMW>(req);
+ ctx.v.push_back("handle");
+ }
- App<IntSettingMiddleware, FirstMW, SecondMW, ThirdMW> app;
+ return "";
+ });
- int x{};
- BMCWEB_ROUTE(app, "/")
- ([&](const Request& req) {
+ decltype(app)::server_t server(&app, LOCALHOST_ADDRESS, 45451);
+ auto _ = async(launch::async, [&] { server.run(); });
+ std::string sendmsg = "GET /\r\n\r\n";
+ asio::io_service is;
{
- auto& ctx = app.getContext<IntSettingMiddleware>(req);
- x = ctx.val;
+ asio::ip::tcp::socket c(is);
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
+
+ c.send(asio::buffer(sendmsg));
+
+ c.receive(asio::buffer(buf, 2048));
+ c.close();
}
{
- auto& ctx = app.getContext<FirstMW>(req);
- ctx.v.push_back("handle");
+ auto& out = test_middleware_context_vector;
+ ASSERT_EQUAL(1, x);
+ ASSERT_EQUAL(7, out.size());
+ ASSERT_EQUAL("1 before", out[0]);
+ ASSERT_EQUAL("2 before", out[1]);
+ ASSERT_EQUAL("3 before", out[2]);
+ ASSERT_EQUAL("handle", out[3]);
+ ASSERT_EQUAL("3 after", out[4]);
+ ASSERT_EQUAL("2 after", out[5]);
+ ASSERT_EQUAL("1 after", out[6]);
}
+ std::string sendmsg2 = "GET /break\r\n\r\n";
+ {
+ asio::ip::tcp::socket c(is);
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
+
+ c.send(asio::buffer(sendmsg2));
- return "";
- });
- BMCWEB_ROUTE(app, "/break")
- ([&](const Request& req) {
+ c.receive(asio::buffer(buf, 2048));
+ c.close();
+ }
{
- auto& ctx = app.getContext<FirstMW>(req);
- ctx.v.push_back("handle");
+ auto& out = test_middleware_context_vector;
+ ASSERT_EQUAL(4, out.size());
+ ASSERT_EQUAL("1 before", out[0]);
+ ASSERT_EQUAL("2 before", out[1]);
+ ASSERT_EQUAL("2 after", out[2]);
+ ASSERT_EQUAL("1 after", out[3]);
}
+ server.stop();
+}
- return "";
- });
+TEST(Crow, bug_quick_repeated_request)
+{
+ static char buf[2048];
- decltype(app)::server_t server(&app, LOCALHOST_ADDRESS, 45451);
- auto _ = async(launch::async, [&] { server.run(); });
- std::string sendmsg = "GET /\r\n\r\n";
- asio::io_service is;
- {
- asio::ip::tcp::socket c(is);
- c.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
+ SimpleApp app;
- c.send(asio::buffer(sendmsg));
+ BMCWEB_ROUTE(app, "/")([&] { return "hello"; });
- c.receive(asio::buffer(buf, 2048));
- c.close();
- }
- {
- auto& out = test_middleware_context_vector;
- ASSERT_EQUAL(1, x);
- ASSERT_EQUAL(7, out.size());
- ASSERT_EQUAL("1 before", out[0]);
- ASSERT_EQUAL("2 before", out[1]);
- ASSERT_EQUAL("3 before", out[2]);
- ASSERT_EQUAL("handle", out[3]);
- ASSERT_EQUAL("3 after", out[4]);
- ASSERT_EQUAL("2 after", out[5]);
- ASSERT_EQUAL("1 after", out[6]);
- }
- std::string sendmsg2 = "GET /break\r\n\r\n";
- {
- asio::ip::tcp::socket c(is);
- c.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
-
- c.send(asio::buffer(sendmsg2));
-
- c.receive(asio::buffer(buf, 2048));
- c.close();
- }
- {
- auto& out = test_middleware_context_vector;
- ASSERT_EQUAL(4, out.size());
- ASSERT_EQUAL("1 before", out[0]);
- ASSERT_EQUAL("2 before", out[1]);
- ASSERT_EQUAL("2 after", out[2]);
- ASSERT_EQUAL("1 after", out[3]);
- }
- server.stop();
+ decltype(app)::server_t server(&app, LOCALHOST_ADDRESS, 45451);
+ auto _ = async(launch::async, [&] { server.run(); });
+ std::string sendmsg = "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n";
+ asio::io_service is;
+ {
+ std::vector<std::future<void>> v;
+ for (int i = 0; i < 5; i++)
+ {
+ v.push_back(async(launch::async, [&] {
+ asio::ip::tcp::socket c(is);
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
+
+ for (int j = 0; j < 5; j++)
+ {
+ c.send(asio::buffer(sendmsg));
+
+ size_t received = c.receive(asio::buffer(buf, 2048));
+ ASSERT_EQUAL("hello", std::string(buf + received - 5,
+ buf + received));
+ }
+ c.close();
+ }));
+ }
+ }
+ server.stop();
}
-TEST(Crow, bug_quick_repeated_request) {
- static char buf[2048];
+TEST(Crow, simple_url_params)
+{
+ static char buf[2048];
+
+ SimpleApp app;
+
+ QueryString lastUrlParams;
+
+ BMCWEB_ROUTE(app, "/params")
+ ([&lastUrlParams](const crow::Request& req) {
+ lastUrlParams = std::move(req.urlParams);
+ return "OK";
+ });
- SimpleApp app;
+ /// params?h=1&foo=bar&lol&count[]=1&count[]=4&pew=5.2
- BMCWEB_ROUTE(app, "/")([&] { return "hello"; });
+ decltype(app)::server_t server(&app, LOCALHOST_ADDRESS, 45451);
+ auto _ = async(launch::async, [&] { server.run(); });
+ asio::io_service is;
+ std::string sendmsg;
- decltype(app)::server_t server(&app, LOCALHOST_ADDRESS, 45451);
- auto _ = async(launch::async, [&] { server.run(); });
- std::string sendmsg = "GET / HTTP/1.1\r\nHost: localhost\r\n\r\n";
- asio::io_service is;
- {
- std::vector<std::future<void>> v;
- for (int i = 0; i < 5; i++) {
- v.push_back(async(launch::async, [&] {
+ // check empty params
+ sendmsg = "GET /params\r\n\r\n";
+ {
asio::ip::tcp::socket c(is);
c.connect(asio::ip::tcp::endpoint(
asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
+ c.send(asio::buffer(sendmsg));
+ c.receive(asio::buffer(buf, 2048));
+ c.close();
- for (int j = 0; j < 5; j++) {
- c.send(asio::buffer(sendmsg));
+ stringstream ss;
+ ss << lastUrlParams;
- size_t received = c.receive(asio::buffer(buf, 2048));
- ASSERT_EQUAL("hello",
- std::string(buf + received - 5, buf + received));
- }
+ ASSERT_EQUAL("[ ]", ss.str());
+ }
+ // check single presence
+ sendmsg = "GET /params?foobar\r\n\r\n";
+ {
+ asio::ip::tcp::socket c(is);
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
+ c.send(asio::buffer(sendmsg));
+ c.receive(asio::buffer(buf, 2048));
+ c.close();
+
+ ASSERT_TRUE(lastUrlParams.get("missing") == nullptr);
+ ASSERT_TRUE(lastUrlParams.get("foobar") != nullptr);
+ ASSERT_TRUE(lastUrlParams.getList("missing").empty());
+ }
+ // check multiple presence
+ sendmsg = "GET /params?foo&bar&baz\r\n\r\n";
+ {
+ asio::ip::tcp::socket c(is);
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
+ c.send(asio::buffer(sendmsg));
+ c.receive(asio::buffer(buf, 2048));
c.close();
- }));
+
+ ASSERT_TRUE(lastUrlParams.get("missing") == nullptr);
+ ASSERT_TRUE(lastUrlParams.get("foo") != nullptr);
+ ASSERT_TRUE(lastUrlParams.get("bar") != nullptr);
+ ASSERT_TRUE(lastUrlParams.get("baz") != nullptr);
}
- }
- server.stop();
-}
+ // check single value
+ sendmsg = "GET /params?hello=world\r\n\r\n";
+ {
+ asio::ip::tcp::socket c(is);
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
+ c.send(asio::buffer(sendmsg));
+ c.receive(asio::buffer(buf, 2048));
+ c.close();
-TEST(Crow, simple_url_params) {
- static char buf[2048];
-
- SimpleApp app;
-
- QueryString lastUrlParams;
-
- BMCWEB_ROUTE(app, "/params")
- ([&lastUrlParams](const crow::Request& req) {
- lastUrlParams = std::move(req.urlParams);
- return "OK";
- });
-
- /// params?h=1&foo=bar&lol&count[]=1&count[]=4&pew=5.2
-
- decltype(app)::server_t server(&app, LOCALHOST_ADDRESS, 45451);
- auto _ = async(launch::async, [&] { server.run(); });
- asio::io_service is;
- std::string sendmsg;
-
- // check empty params
- sendmsg = "GET /params\r\n\r\n";
- {
- asio::ip::tcp::socket c(is);
- c.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
- c.send(asio::buffer(sendmsg));
- c.receive(asio::buffer(buf, 2048));
- c.close();
-
- stringstream ss;
- ss << lastUrlParams;
-
- ASSERT_EQUAL("[ ]", ss.str());
- }
- // check single presence
- sendmsg = "GET /params?foobar\r\n\r\n";
- {
- asio::ip::tcp::socket c(is);
- c.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
- c.send(asio::buffer(sendmsg));
- c.receive(asio::buffer(buf, 2048));
- c.close();
-
- ASSERT_TRUE(lastUrlParams.get("missing") == nullptr);
- ASSERT_TRUE(lastUrlParams.get("foobar") != nullptr);
- ASSERT_TRUE(lastUrlParams.getList("missing").empty());
- }
- // check multiple presence
- sendmsg = "GET /params?foo&bar&baz\r\n\r\n";
- {
- asio::ip::tcp::socket c(is);
- c.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
- c.send(asio::buffer(sendmsg));
- c.receive(asio::buffer(buf, 2048));
- c.close();
-
- ASSERT_TRUE(lastUrlParams.get("missing") == nullptr);
- ASSERT_TRUE(lastUrlParams.get("foo") != nullptr);
- ASSERT_TRUE(lastUrlParams.get("bar") != nullptr);
- ASSERT_TRUE(lastUrlParams.get("baz") != nullptr);
- }
- // check single value
- sendmsg = "GET /params?hello=world\r\n\r\n";
- {
- asio::ip::tcp::socket c(is);
- c.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
- c.send(asio::buffer(sendmsg));
- c.receive(asio::buffer(buf, 2048));
- c.close();
-
- ASSERT_EQUAL(string(lastUrlParams.get("hello")), "world");
- }
- // check multiple value
- sendmsg = "GET /params?hello=world&left=right&up=down\r\n\r\n";
- {
- asio::ip::tcp::socket c(is);
- c.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
- c.send(asio::buffer(sendmsg));
- c.receive(asio::buffer(buf, 2048));
- c.close();
-
- ASSERT_EQUAL(string(lastUrlParams.get("hello")), "world");
- ASSERT_EQUAL(string(lastUrlParams.get("left")), "right");
- ASSERT_EQUAL(string(lastUrlParams.get("up")), "down");
- }
- // check multiple value, multiple types
- sendmsg = "GET /params?int=100&double=123.45&boolean=1\r\n\r\n";
- {
- asio::ip::tcp::socket c(is);
- c.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
- c.send(asio::buffer(sendmsg));
- c.receive(asio::buffer(buf, 2048));
- c.close();
-
- ASSERT_EQUAL(boost::lexical_cast<int>(lastUrlParams.get("int")), 100);
- ASSERT_EQUAL(boost::lexical_cast<double>(lastUrlParams.get("double")),
- 123.45);
- ASSERT_EQUAL(boost::lexical_cast<bool>(lastUrlParams.get("boolean")), true);
- }
- // check single array value
- sendmsg = "GET /params?tmnt[]=leonardo\r\n\r\n";
- {
- asio::ip::tcp::socket c(is);
-
- c.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
- c.send(asio::buffer(sendmsg));
- c.receive(asio::buffer(buf, 2048));
- c.close();
-
- ASSERT_TRUE(lastUrlParams.get("tmnt") == nullptr);
- ASSERT_EQUAL(lastUrlParams.getList("tmnt").size(), 1);
- ASSERT_EQUAL(string(lastUrlParams.getList("tmnt")[0]), "leonardo");
- }
- // check multiple array value
- sendmsg =
- "GET /params?tmnt[]=leonardo&tmnt[]=donatello&tmnt[]=raphael\r\n\r\n";
- {
- asio::ip::tcp::socket c(is);
-
- c.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
- c.send(asio::buffer(sendmsg));
- c.receive(asio::buffer(buf, 2048));
- c.close();
-
- ASSERT_EQUAL(lastUrlParams.getList("tmnt").size(), 3);
- ASSERT_EQUAL(string(lastUrlParams.getList("tmnt")[0]), "leonardo");
- ASSERT_EQUAL(string(lastUrlParams.getList("tmnt")[1]), "donatello");
- ASSERT_EQUAL(string(lastUrlParams.getList("tmnt")[2]), "raphael");
- }
- server.stop();
+ ASSERT_EQUAL(string(lastUrlParams.get("hello")), "world");
+ }
+ // check multiple value
+ sendmsg = "GET /params?hello=world&left=right&up=down\r\n\r\n";
+ {
+ asio::ip::tcp::socket c(is);
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
+ c.send(asio::buffer(sendmsg));
+ c.receive(asio::buffer(buf, 2048));
+ c.close();
+
+ ASSERT_EQUAL(string(lastUrlParams.get("hello")), "world");
+ ASSERT_EQUAL(string(lastUrlParams.get("left")), "right");
+ ASSERT_EQUAL(string(lastUrlParams.get("up")), "down");
+ }
+ // check multiple value, multiple types
+ sendmsg = "GET /params?int=100&double=123.45&boolean=1\r\n\r\n";
+ {
+ asio::ip::tcp::socket c(is);
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
+ c.send(asio::buffer(sendmsg));
+ c.receive(asio::buffer(buf, 2048));
+ c.close();
+
+ ASSERT_EQUAL(boost::lexical_cast<int>(lastUrlParams.get("int")), 100);
+ ASSERT_EQUAL(boost::lexical_cast<double>(lastUrlParams.get("double")),
+ 123.45);
+ ASSERT_EQUAL(boost::lexical_cast<bool>(lastUrlParams.get("boolean")),
+ true);
+ }
+ // check single array value
+ sendmsg = "GET /params?tmnt[]=leonardo\r\n\r\n";
+ {
+ asio::ip::tcp::socket c(is);
+
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
+ c.send(asio::buffer(sendmsg));
+ c.receive(asio::buffer(buf, 2048));
+ c.close();
+
+ ASSERT_TRUE(lastUrlParams.get("tmnt") == nullptr);
+ ASSERT_EQUAL(lastUrlParams.getList("tmnt").size(), 1);
+ ASSERT_EQUAL(string(lastUrlParams.getList("tmnt")[0]), "leonardo");
+ }
+ // check multiple array value
+ sendmsg =
+ "GET /params?tmnt[]=leonardo&tmnt[]=donatello&tmnt[]=raphael\r\n\r\n";
+ {
+ asio::ip::tcp::socket c(is);
+
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string(LOCALHOST_ADDRESS), 45451));
+ c.send(asio::buffer(sendmsg));
+ c.receive(asio::buffer(buf, 2048));
+ c.close();
+
+ ASSERT_EQUAL(lastUrlParams.getList("tmnt").size(), 3);
+ ASSERT_EQUAL(string(lastUrlParams.getList("tmnt")[0]), "leonardo");
+ ASSERT_EQUAL(string(lastUrlParams.getList("tmnt")[1]), "donatello");
+ ASSERT_EQUAL(string(lastUrlParams.getList("tmnt")[2]), "raphael");
+ }
+ server.stop();
}
-TEST(Crow, routeDynamic) {
- SimpleApp app;
- int x = 1;
- app.routeDynamic("/")([&] {
- x = 2;
- return "";
- });
-
- app.routeDynamic("/set4")([&](const Request&) {
- x = 4;
- return "";
- });
- app.routeDynamic("/set5")([&](const Request&, Response& res) {
- x = 5;
- res.end();
- });
-
- app.routeDynamic("/set_int/<int>")([&](int y) {
- x = y;
- return "";
- });
-
- try {
- app.routeDynamic("/invalid_test/<double>/<path>")([]() { return ""; });
- fail();
- } catch (std::exception&) {
- }
-
- // app is in an invalid state when routeDynamic throws an exception.
- try {
- app.validate();
- fail();
- } catch (std::exception&) {
- }
+TEST(Crow, routeDynamic)
+{
+ SimpleApp app;
+ int x = 1;
+ app.routeDynamic("/")([&] {
+ x = 2;
+ return "";
+ });
+
+ app.routeDynamic("/set4")([&](const Request&) {
+ x = 4;
+ return "";
+ });
+ app.routeDynamic("/set5")([&](const Request&, Response& res) {
+ x = 5;
+ res.end();
+ });
+
+ app.routeDynamic("/set_int/<int>")([&](int y) {
+ x = y;
+ return "";
+ });
+
+ try
+ {
+ app.routeDynamic("/invalid_test/<double>/<path>")([]() { return ""; });
+ fail();
+ }
+ catch (std::exception&)
+ {
+ }
- {
- boost::beast::http::request<boost::beast::http::string_body> r{};
- Request req{r};
- Response res;
- req.url = "/";
- app.handle(req, res);
- ASSERT_EQUAL(x, 2);
- }
- {
- boost::beast::http::request<boost::beast::http::string_body> r{};
- Request req{r};
- Response res;
- req.url = "/set_int/42";
- app.handle(req, res);
- ASSERT_EQUAL(x, 42);
- }
- {
- boost::beast::http::request<boost::beast::http::string_body> r{};
- Request req{r};
- Response res;
- req.url = "/set5";
- app.handle(req, res);
- ASSERT_EQUAL(x, 5);
- }
- {
- boost::beast::http::request<boost::beast::http::string_body> r{};
- Request req{r};
- Response res;
- req.url = "/set4";
- app.handle(req, res);
- ASSERT_EQUAL(x, 4);
- }
+ // app is in an invalid state when routeDynamic throws an exception.
+ try
+ {
+ app.validate();
+ fail();
+ }
+ catch (std::exception&)
+ {
+ }
+
+ {
+ boost::beast::http::request<boost::beast::http::string_body> r{};
+ Request req{r};
+ Response res;
+ req.url = "/";
+ app.handle(req, res);
+ ASSERT_EQUAL(x, 2);
+ }
+ {
+ boost::beast::http::request<boost::beast::http::string_body> r{};
+ Request req{r};
+ Response res;
+ req.url = "/set_int/42";
+ app.handle(req, res);
+ ASSERT_EQUAL(x, 42);
+ }
+ {
+ boost::beast::http::request<boost::beast::http::string_body> r{};
+ Request req{r};
+ Response res;
+ req.url = "/set5";
+ app.handle(req, res);
+ ASSERT_EQUAL(x, 5);
+ }
+ {
+ boost::beast::http::request<boost::beast::http::string_body> r{};
+ Request req{r};
+ Response res;
+ req.url = "/set4";
+ app.handle(req, res);
+ ASSERT_EQUAL(x, 4);
+ }
}
diff --git a/src/getvideo_main.cpp b/src/getvideo_main.cpp
index 7055d35dfc..8d5f7afd3b 100644
--- a/src/getvideo_main.cpp
+++ b/src/getvideo_main.cpp
@@ -1,15 +1,15 @@
#include <fcntl.h>
#include <unistd.h>
+
#include <chrono>
+#include <cstdio>
+#include <cstdlib>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <thread>
#include <vector>
-#include <cstdio>
-#include <cstdlib>
-
//#define BUILD_CIMG
#ifdef BUILD_CIMG
#define cimg_display 0
@@ -19,52 +19,60 @@
#include <ast_jpeg_decoder.hpp>
#include <ast_video_puller.hpp>
-int main() {
- ast_video::RawVideoBuffer out;
- bool have_hardware = false;
- if (access("/dev/video", F_OK) != -1) {
- ast_video::SimpleVideoPuller p;
- p.initialize();
- out = p.readVideo();
- } else {
- FILE *fp = fopen("/home/ed/screendata.bin", "rb");
- if (fp != nullptr) {
- size_t newLen = fread(out.buffer.data(), sizeof(char),
- out.buffer.size() * sizeof(long), fp);
- if (ferror(fp) != 0) {
- fputs("Error reading file", stderr);
- }
- fclose(fp);
- out.buffer.resize(newLen);
- out.mode = ast_video::YuvMode::YUV444;
- out.width = 800;
- out.height = 600;
- out.ySelector = 0;
- out.uvSelector = 0;
+int main()
+{
+ ast_video::RawVideoBuffer out;
+ bool have_hardware = false;
+ if (access("/dev/video", F_OK) != -1)
+ {
+ ast_video::SimpleVideoPuller p;
+ p.initialize();
+ out = p.readVideo();
+ }
+ else
+ {
+ FILE *fp = fopen("/home/ed/screendata.bin", "rb");
+ if (fp != nullptr)
+ {
+ size_t newLen = fread(out.buffer.data(), sizeof(char),
+ out.buffer.size() * sizeof(long), fp);
+ if (ferror(fp) != 0)
+ {
+ fputs("Error reading file", stderr);
+ }
+ fclose(fp);
+ out.buffer.resize(newLen);
+ out.mode = ast_video::YuvMode::YUV444;
+ out.width = 800;
+ out.height = 600;
+ out.ySelector = 0;
+ out.uvSelector = 0;
+ }
}
- }
- FILE *fp = fopen("/tmp/screendata.bin", "wb");
- fwrite(out.buffer.data(), sizeof(char), out.buffer.size(), fp);
+ FILE *fp = fopen("/tmp/screendata.bin", "wb");
+ fwrite(out.buffer.data(), sizeof(char), out.buffer.size(), fp);
- ast_video::AstJpegDecoder d;
- d.decode(out.buffer, out.width, out.height, out.mode, out.ySelector,
- out.uvSelector);
+ ast_video::AstJpegDecoder d;
+ d.decode(out.buffer, out.width, out.height, out.mode, out.ySelector,
+ out.uvSelector);
#ifdef BUILD_CIMG
- cimg_library::CImg<unsigned char> image(out.width, out.height, 1,
- 3 /*numchannels*/);
- for (int y = 0; y < out.height; y++) {
- for (int x = 0; x < out.width; x++) {
- auto pixel = d.outBuffer[x + (y * out.width)];
- image(x, y, 0) = pixel.r;
- image(x, y, 1) = pixel.g;
- image(x, y, 2) = pixel.b;
+ cimg_library::CImg<unsigned char> image(out.width, out.height, 1,
+ 3 /*numchannels*/);
+ for (int y = 0; y < out.height; y++)
+ {
+ for (int x = 0; x < out.width; x++)
+ {
+ auto pixel = d.outBuffer[x + (y * out.width)];
+ image(x, y, 0) = pixel.r;
+ image(x, y, 1) = pixel.g;
+ image(x, y, 2) = pixel.b;
+ }
}
- }
- image.save("/tmp/file2.bmp");
+ image.save("/tmp/file2.bmp");
#endif
- std::cout << "Done!\n";
+ std::cout << "Done!\n";
- return 1;
+ return 1;
}
diff --git a/src/gtest_main.cpp b/src/gtest_main.cpp
index eec00675a3..77e70aac1d 100644
--- a/src/gtest_main.cpp
+++ b/src/gtest_main.cpp
@@ -1,7 +1,8 @@
#include "gmock/gmock.h"
#include "gtest/gtest.h"
-int main(int argc, char **argv) {
- ::testing::InitGoogleTest(&argc, argv);
- return RUN_ALL_TESTS();
+int main(int argc, char **argv)
+{
+ ::testing::InitGoogleTest(&argc, argv);
+ return RUN_ALL_TESTS();
} \ No newline at end of file
diff --git a/src/kvm_websocket_test.cpp b/src/kvm_websocket_test.cpp
index b5e1bdcffd..1ddaad9b35 100644
--- a/src/kvm_websocket_test.cpp
+++ b/src/kvm_websocket_test.cpp
@@ -1,9 +1,12 @@
+#include "gzip_helper.hpp"
+#include "web_kvm.hpp"
+
#include <iostream>
#include <sstream>
#include <vector>
-#include "gzip_helper.hpp"
-#include "web_kvm.hpp"
+
#include "crow.h"
+
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -11,93 +14,101 @@ using namespace crow;
using namespace testing;
// Tests static files are loaded correctly
-TEST(Kvm, BasicRfb) {
- return; // TODO(ed) Make hte code below work again
- SimpleApp app;
-
- crow::kvm::requestRoutes(app);
- app.bindaddr("127.0.0.1").port(45451);
- BMCWEB_ROUTE(app, "/")([]() { return boost::beast::http::status::ok; });
- auto _ = async(std::launch::async, [&] { app.run(); });
- auto routes = app.getRoutes();
- asio::io_service is;
-
- {
- // Retry a couple of times waiting for the server to come up
- // TODO(ed) This is really unfortunate, and should use some form of mock
- asio::ip::tcp::socket c(is);
- for (int i = 0; i < 200; i++) {
- try {
- c.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string("127.0.0.1"), 45451));
- c.close();
- break;
- } catch (std::exception e) {
- // do nothing. We expect this to fail while the server is starting up
- }
+TEST(Kvm, BasicRfb)
+{
+ return; // TODO(ed) Make hte code below work again
+ SimpleApp app;
+
+ crow::kvm::requestRoutes(app);
+ app.bindaddr("127.0.0.1").port(45451);
+ BMCWEB_ROUTE(app, "/")([]() { return boost::beast::http::status::ok; });
+ auto _ = async(std::launch::async, [&] { app.run(); });
+ auto routes = app.getRoutes();
+ asio::io_service is;
+
+ {
+ // Retry a couple of times waiting for the server to come up
+ // TODO(ed) This is really unfortunate, and should use some form of
+ // mock
+ asio::ip::tcp::socket c(is);
+ for (int i = 0; i < 200; i++)
+ {
+ try
+ {
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string("127.0.0.1"), 45451));
+ c.close();
+ break;
+ }
+ catch (std::exception e)
+ {
+ // do nothing. We expect this to fail while the server is
+ // starting up
+ }
+ }
+ }
+
+ // Get the websocket
+ std::string sendmsg = ("GET /kvmws HTTP/1.1\r\n"
+ "Host: localhost:45451\r\n"
+ "Connection: Upgrade\r\n"
+ "Upgrade: websocket\r\n"
+ "Sec-WebSocket-Version: 13\r\n"
+ "Sec-WebSocket-Key: aLeGkmLPZmdv5tTyEpJ3jQ==\r\n"
+ "Sec-WebSocket-Extensions: permessage-deflate; "
+ "client_max_window_bits\r\n"
+ "Sec-WebSocket-Protocol: binary\r\n"
+ "\r\n");
+
+ asio::ip::tcp::socket socket(is);
+ socket.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string("127.0.0.1"), 45451));
+ socket.send(asio::buffer(sendmsg));
+
+ // Read the Response status line. The Response streambuf will automatically
+ // grow to accommodate the entire line. The growth may be limited by passing
+ // a maximum size to the streambuf constructor.
+ boost::asio::streambuf response;
+ boost::asio::read_until(socket, response, "\r\n");
+
+ // Check that Response is OK.
+ std::istream response_stream(&response);
+ std::string http_response;
+ std::getline(response_stream, http_response);
+
+ EXPECT_EQ(http_response, "HTTP/1.1 101 Switching Protocols\r");
+
+ // Read the Response headers, which are terminated by a blank line.
+ boost::asio::read_until(socket, response, "\r\n\r\n");
+
+ // Process the Response headers.
+ std::string header;
+ std::vector<std::string> headers;
+ while (std::getline(response_stream, header) && header != "\r")
+ {
+ headers.push_back(header);
}
- }
-
- // Get the websocket
- std::string sendmsg =
- ("GET /kvmws HTTP/1.1\r\n"
- "Host: localhost:45451\r\n"
- "Connection: Upgrade\r\n"
- "Upgrade: websocket\r\n"
- "Sec-WebSocket-Version: 13\r\n"
- "Sec-WebSocket-Key: aLeGkmLPZmdv5tTyEpJ3jQ==\r\n"
- "Sec-WebSocket-Extensions: permessage-deflate; "
- "client_max_window_bits\r\n"
- "Sec-WebSocket-Protocol: binary\r\n"
- "\r\n");
-
- asio::ip::tcp::socket socket(is);
- socket.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string("127.0.0.1"), 45451));
- socket.send(asio::buffer(sendmsg));
-
- // Read the Response status line. The Response streambuf will automatically
- // grow to accommodate the entire line. The growth may be limited by passing
- // a maximum size to the streambuf constructor.
- boost::asio::streambuf response;
- boost::asio::read_until(socket, response, "\r\n");
-
- // Check that Response is OK.
- std::istream response_stream(&response);
- std::string http_response;
- std::getline(response_stream, http_response);
-
- EXPECT_EQ(http_response, "HTTP/1.1 101 Switching Protocols\r");
-
- // Read the Response headers, which are terminated by a blank line.
- boost::asio::read_until(socket, response, "\r\n\r\n");
-
- // Process the Response headers.
- std::string header;
- std::vector<std::string> headers;
- while (std::getline(response_stream, header) && header != "\r") {
- headers.push_back(header);
- }
-
- EXPECT_THAT(headers, Contains("Upgrade: websocket\r"));
- EXPECT_THAT(headers, Contains("Connection: Upgrade\r"));
- EXPECT_THAT(headers, Contains("Sec-WebSocket-Protocol: binary\r"));
- // TODO(ed) This is the result that it gives today. Need to check websocket
- // docs and make
- // sure that this calclution is actually being done to spec
- EXPECT_THAT(headers,
- Contains("Sec-WebSocket-Accept: /CnDM3l79rIxniLNyxMryXbtLEU=\r"));
- std::array<char, 13> rfb_open_string;
-
- //
- // socket.receive(rfb_open_string.data(), rfb_open_string.size());
- boost::asio::read(socket, boost::asio::buffer(rfb_open_string));
- auto open_string =
- std::string(std::begin(rfb_open_string), std::end(rfb_open_string));
- // Todo(ed) find out what the two characters at the end of the websocket
- // stream are
- open_string = open_string.substr(2);
- EXPECT_EQ(open_string, "RFB 003.008");
-
- app.stop();
+
+ EXPECT_THAT(headers, Contains("Upgrade: websocket\r"));
+ EXPECT_THAT(headers, Contains("Connection: Upgrade\r"));
+ EXPECT_THAT(headers, Contains("Sec-WebSocket-Protocol: binary\r"));
+ // TODO(ed) This is the result that it gives today. Need to check websocket
+ // docs and make
+ // sure that this calclution is actually being done to spec
+ EXPECT_THAT(
+ headers,
+ Contains("Sec-WebSocket-Accept: /CnDM3l79rIxniLNyxMryXbtLEU=\r"));
+ std::array<char, 13> rfb_open_string;
+
+ //
+ // socket.receive(rfb_open_string.data(), rfb_open_string.size());
+ boost::asio::read(socket, boost::asio::buffer(rfb_open_string));
+ auto open_string =
+ std::string(std::begin(rfb_open_string), std::end(rfb_open_string));
+ // Todo(ed) find out what the two characters at the end of the websocket
+ // stream are
+ open_string = open_string.substr(2);
+ EXPECT_EQ(open_string, "RFB 003.008");
+
+ app.stop();
} \ No newline at end of file
diff --git a/src/msan_test.cpp b/src/msan_test.cpp
index 9fcb9d530c..7e42e48659 100644
--- a/src/msan_test.cpp
+++ b/src/msan_test.cpp
@@ -1,7 +1,9 @@
#include <string>
+
#include "gtest/gtest.h"
-TEST(MemorySanitizer, TestIsWorking) {
- std::string foo("foo");
- EXPECT_STREQ("foo", foo.c_str());
+TEST(MemorySanitizer, TestIsWorking)
+{
+ std::string foo("foo");
+ EXPECT_STREQ("foo", foo.c_str());
}
diff --git a/src/openbmc_jtag_rest_test.cpp b/src/openbmc_jtag_rest_test.cpp
index 7e40d6ddee..42504d3895 100644
--- a/src/openbmc_jtag_rest_test.cpp
+++ b/src/openbmc_jtag_rest_test.cpp
@@ -1,51 +1,53 @@
#include "openbmc_dbus_rest.hpp"
+
#include "gmock/gmock.h"
#include "gtest/gtest.h"
-TEST(OpenBmcDbusTest, TestArgSplit) {
- // test the basic types
- EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("x"),
- ::testing::ElementsAre("x"));
- EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("y"),
- ::testing::ElementsAre("y"));
- EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("b"),
- ::testing::ElementsAre("b"));
- EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("n"),
- ::testing::ElementsAre("n"));
- EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("q"),
- ::testing::ElementsAre("q"));
- EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("i"),
- ::testing::ElementsAre("i"));
- EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("u"),
- ::testing::ElementsAre("u"));
- EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("x"),
- ::testing::ElementsAre("x"));
- EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("t"),
- ::testing::ElementsAre("t"));
- EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("d"),
- ::testing::ElementsAre("d"));
- EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("h"),
- ::testing::ElementsAre("h"));
- // test arrays
- EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("ai"),
- ::testing::ElementsAre("ai"));
- EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("ax"),
- ::testing::ElementsAre("ax"));
- // test tuples
- EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("(sss)"),
- ::testing::ElementsAre("(sss)"));
- EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("(sss)b"),
- ::testing::ElementsAre("(sss)", "b"));
- EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("b(sss)"),
- ::testing::ElementsAre("b", "(sss)"));
+TEST(OpenBmcDbusTest, TestArgSplit)
+{
+ // test the basic types
+ EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("x"),
+ ::testing::ElementsAre("x"));
+ EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("y"),
+ ::testing::ElementsAre("y"));
+ EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("b"),
+ ::testing::ElementsAre("b"));
+ EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("n"),
+ ::testing::ElementsAre("n"));
+ EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("q"),
+ ::testing::ElementsAre("q"));
+ EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("i"),
+ ::testing::ElementsAre("i"));
+ EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("u"),
+ ::testing::ElementsAre("u"));
+ EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("x"),
+ ::testing::ElementsAre("x"));
+ EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("t"),
+ ::testing::ElementsAre("t"));
+ EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("d"),
+ ::testing::ElementsAre("d"));
+ EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("h"),
+ ::testing::ElementsAre("h"));
+ // test arrays
+ EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("ai"),
+ ::testing::ElementsAre("ai"));
+ EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("ax"),
+ ::testing::ElementsAre("ax"));
+ // test tuples
+ EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("(sss)"),
+ ::testing::ElementsAre("(sss)"));
+ EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("(sss)b"),
+ ::testing::ElementsAre("(sss)", "b"));
+ EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("b(sss)"),
+ ::testing::ElementsAre("b", "(sss)"));
- // Test nested types
- EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("a{si}b"),
- ::testing::ElementsAre("a{si}", "b"));
- EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("a(sss)b"),
- ::testing::ElementsAre("a(sss)", "b"));
- EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("aa{si}b"),
- ::testing::ElementsAre("aa{si}", "b"));
- EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("i{si}b"),
- ::testing::ElementsAre("b", "aa{si}"));
+ // Test nested types
+ EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("a{si}b"),
+ ::testing::ElementsAre("a{si}", "b"));
+ EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("a(sss)b"),
+ ::testing::ElementsAre("a(sss)", "b"));
+ EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("aa{si}b"),
+ ::testing::ElementsAre("aa{si}", "b"));
+ EXPECT_THAT(crow::openbmc_mapper::dbus_arg_split("i{si}b"),
+ ::testing::ElementsAre("b", "aa{si}"));
}
diff --git a/src/security_headers_middleware_test.cpp b/src/security_headers_middleware_test.cpp
index e7008cb165..2af15c6d07 100644
--- a/src/security_headers_middleware_test.cpp
+++ b/src/security_headers_middleware_test.cpp
@@ -1,5 +1,7 @@
-#include <security_headers_middleware.hpp>
#include <crow/app.h>
+
+#include <security_headers_middleware.hpp>
+
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -7,68 +9,78 @@ using namespace crow;
using namespace std;
// Tests that the security headers are added correctly
-TEST(SecurityHeaders, TestHeadersExist) {
- App<SecurityHeadersMiddleware> app;
- app.bindaddr("127.0.0.1").port(45451);
- BMCWEB_ROUTE(app, "/")([]() { return boost::beast::http::status::ok; });
- auto _ = async(launch::async, [&] { app.run(); });
+TEST(SecurityHeaders, TestHeadersExist)
+{
+ App<SecurityHeadersMiddleware> app;
+ app.bindaddr("127.0.0.1").port(45451);
+ BMCWEB_ROUTE(app, "/")([]() { return boost::beast::http::status::ok; });
+ auto _ = async(launch::async, [&] { app.run(); });
- asio::io_service is;
- std::array<char, 2048> buf;
- std::string sendmsg;
+ asio::io_service is;
+ std::array<char, 2048> buf;
+ std::string sendmsg;
- {
- // Retry a couple of times waiting for the server to come up
- // TODO(ed) This is really unfortunate, and should use some form of mock
- asio::ip::tcp::socket c(is);
- for (int i = 0; i < 200; i++) {
- try {
- c.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string("127.0.0.1"), 45451));
- c.close();
- break;
- } catch (std::exception e) {
- // do nothing. We expect this to fail while the server is starting up
- }
+ {
+ // Retry a couple of times waiting for the server to come up
+ // TODO(ed) This is really unfortunate, and should use some form of
+ // mock
+ asio::ip::tcp::socket c(is);
+ for (int i = 0; i < 200; i++)
+ {
+ try
+ {
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string("127.0.0.1"), 45451));
+ c.close();
+ break;
+ }
+ catch (std::exception e)
+ {
+ // do nothing. We expect this to fail while the server is
+ // starting up
+ }
+ }
}
- }
- // Test correct login credentials
- sendmsg = "GET /\r\n\r\n";
+ // Test correct login credentials
+ sendmsg = "GET /\r\n\r\n";
- asio::ip::tcp::socket c(is);
- c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string("127.0.0.1"),
- 45451));
- c.send(asio::buffer(sendmsg));
- c.receive(asio::buffer(buf));
- c.close();
- auto return_code = std::string(&buf[9], &buf[12]);
- EXPECT_EQ("200", return_code);
- std::string response(std::begin(buf), std::end(buf));
+ asio::ip::tcp::socket c(is);
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string("127.0.0.1"), 45451));
+ c.send(asio::buffer(sendmsg));
+ c.receive(asio::buffer(buf));
+ c.close();
+ auto return_code = std::string(&buf[9], &buf[12]);
+ EXPECT_EQ("200", return_code);
+ std::string response(std::begin(buf), std::end(buf));
- // This is a routine to split strings until a blank is hit
- // TODO(ed) this should really use the HTTP parser
- std::vector<std::string> headers;
- std::string::size_type pos = 0;
- std::string::size_type prev = 0;
- while ((pos = response.find("\r\n", prev)) != std::string::npos) {
- auto this_string = response.substr(prev, pos - prev);
- if (this_string == "") {
- break;
+ // This is a routine to split strings until a blank is hit
+ // TODO(ed) this should really use the HTTP parser
+ std::vector<std::string> headers;
+ std::string::size_type pos = 0;
+ std::string::size_type prev = 0;
+ while ((pos = response.find("\r\n", prev)) != std::string::npos)
+ {
+ auto this_string = response.substr(prev, pos - prev);
+ if (this_string == "")
+ {
+ break;
+ }
+ headers.push_back(this_string);
+ prev = pos + 2;
}
- headers.push_back(this_string);
- prev = pos + 2;
- }
- headers.push_back(response.substr(prev));
+ headers.push_back(response.substr(prev));
- EXPECT_EQ(headers[0], "HTTP/1.1 200 OK");
- EXPECT_THAT(headers, ::testing::Contains("Strict-Transport-Security: "
- "max-age=31536000; "
- "includeSubdomains; preload"));
- EXPECT_THAT(headers, ::testing::Contains("X-UA-Compatible: IE=11"));
- EXPECT_THAT(headers, ::testing::Contains("X-Frame-Options: DENY"));
- EXPECT_THAT(headers, ::testing::Contains("X-XSS-Protection: 1; mode=block"));
- EXPECT_THAT(headers, ::testing::Contains(
- "X-Content-Security-Policy: default-src 'self'"));
- app.stop();
+ EXPECT_EQ(headers[0], "HTTP/1.1 200 OK");
+ EXPECT_THAT(headers, ::testing::Contains("Strict-Transport-Security: "
+ "max-age=31536000; "
+ "includeSubdomains; preload"));
+ EXPECT_THAT(headers, ::testing::Contains("X-UA-Compatible: IE=11"));
+ EXPECT_THAT(headers, ::testing::Contains("X-Frame-Options: DENY"));
+ EXPECT_THAT(headers,
+ ::testing::Contains("X-XSS-Protection: 1; mode=block"));
+ EXPECT_THAT(headers, ::testing::Contains(
+ "X-Content-Security-Policy: default-src 'self'"));
+ app.stop();
}
diff --git a/src/token_authorization_middleware_test.cpp b/src/token_authorization_middleware_test.cpp
index ab735b3a52..812a6d193e 100644
--- a/src/token_authorization_middleware_test.cpp
+++ b/src/token_authorization_middleware_test.cpp
@@ -1,287 +1,322 @@
#include "token_authorization_middleware.hpp"
+#include "webserver_common.hpp"
+
#include <condition_variable>
#include <future>
#include <mutex>
-#include "webserver_common.hpp"
+
#include "gmock/gmock.h"
#include "gtest/gtest.h"
using namespace crow;
-class TokenAuth : public ::testing::Test {
- public:
- TokenAuth()
- : lk(std::unique_lock<std::mutex>(m)),
- io(std::make_shared<boost::asio::io_service>()) {}
-
- std::mutex m;
- std::condition_variable cv;
- std::unique_lock<std::mutex> lk;
- std::shared_ptr<boost::asio::io_service> io;
- int testPort = 45451;
+class TokenAuth : public ::testing::Test
+{
+ public:
+ TokenAuth() :
+ lk(std::unique_lock<std::mutex>(m)),
+ io(std::make_shared<boost::asio::io_service>())
+ {
+ }
+
+ std::mutex m;
+ std::condition_variable cv;
+ std::unique_lock<std::mutex> lk;
+ std::shared_ptr<boost::asio::io_service> io;
+ int testPort = 45451;
};
-TEST_F(TokenAuth, SpecialResourcesAreAcceptedWithoutAuth) {
- CrowApp app(io);
- crow::token_authorization::requestRoutes(app);
- BMCWEB_ROUTE(app, "/redfish/v1")
- ([]() { return boost::beast::http::status::ok; });
- auto _ = std::async(std::launch::async, [&] {
- app.port(testPort).run();
- cv.notify_one();
- io->run();
- });
-
- asio::io_service is;
- std::string sendmsg;
-
- static char buf[2048];
-
- // Homepage should be passed with no credentials
- sendmsg = "GET /\r\n\r\n";
- {
- asio::ip::tcp::socket c(is);
- c.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string("127.0.0.1"), 45451));
- c.send(asio::buffer(sendmsg));
- c.receive(asio::buffer(buf, 2048));
- c.close();
- EXPECT_EQ("200", std::string(buf + 9, buf + 12));
- }
+TEST_F(TokenAuth, SpecialResourcesAreAcceptedWithoutAuth)
+{
+ CrowApp app(io);
+ crow::token_authorization::requestRoutes(app);
+ BMCWEB_ROUTE(app, "/redfish/v1")
+ ([]() { return boost::beast::http::status::ok; });
+ auto _ = std::async(std::launch::async, [&] {
+ app.port(testPort).run();
+ cv.notify_one();
+ io->run();
+ });
+
+ asio::io_service is;
+ std::string sendmsg;
+
+ static char buf[2048];
+
+ // Homepage should be passed with no credentials
+ sendmsg = "GET /\r\n\r\n";
+ {
+ asio::ip::tcp::socket c(is);
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string("127.0.0.1"), 45451));
+ c.send(asio::buffer(sendmsg));
+ c.receive(asio::buffer(buf, 2048));
+ c.close();
+ EXPECT_EQ("200", std::string(buf + 9, buf + 12));
+ }
- // static should be passed with no credentials
- sendmsg = "GET /static/index.html\r\n\r\n";
- {
- asio::ip::tcp::socket c(is);
- c.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string("127.0.0.1"), 45451));
- c.send(asio::buffer(sendmsg));
- c.receive(asio::buffer(buf, 2048));
- c.close();
- EXPECT_EQ("404", std::string(buf + 9, buf + 12));
- }
+ // static should be passed with no credentials
+ sendmsg = "GET /static/index.html\r\n\r\n";
+ {
+ asio::ip::tcp::socket c(is);
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string("127.0.0.1"), 45451));
+ c.send(asio::buffer(sendmsg));
+ c.receive(asio::buffer(buf, 2048));
+ c.close();
+ EXPECT_EQ("404", std::string(buf + 9, buf + 12));
+ }
- app.stop();
+ app.stop();
}
// Tests that Base64 basic strings work
-TEST(TokenAuthentication, TestRejectedResource) {
- App<crow::persistent_data::Middleware, crow::token_authorization::Middleware>
- app;
- app.bindaddr("127.0.0.1").port(45451);
- BMCWEB_ROUTE(app, "/")([]() { return boost::beast::http::status::ok; });
- auto _ = async(std::launch::async, [&] { app.run(); });
-
- asio::io_service is;
- static char buf[2048];
-
- // Other resources should not be passed
- std::string sendmsg = "GET /foo\r\n\r\n";
- asio::ip::tcp::socket c(is);
- for (int i = 0; i < 200; i++) {
- try {
- c.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string("127.0.0.1"), 45451));
- } catch (std::exception e) {
- // do nothing
+TEST(TokenAuthentication, TestRejectedResource)
+{
+ App<crow::persistent_data::Middleware,
+ crow::token_authorization::Middleware>
+ app;
+ app.bindaddr("127.0.0.1").port(45451);
+ BMCWEB_ROUTE(app, "/")([]() { return boost::beast::http::status::ok; });
+ auto _ = async(std::launch::async, [&] { app.run(); });
+
+ asio::io_service is;
+ static char buf[2048];
+
+ // Other resources should not be passed
+ std::string sendmsg = "GET /foo\r\n\r\n";
+ asio::ip::tcp::socket c(is);
+ for (int i = 0; i < 200; i++)
+ {
+ try
+ {
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string("127.0.0.1"), 45451));
+ }
+ catch (std::exception e)
+ {
+ // do nothing
+ }
}
- }
- c.send(asio::buffer(sendmsg));
- c.receive(asio::buffer(buf, 2048));
- c.close();
- EXPECT_EQ("401", std::string(buf + 9, buf + 12));
+ c.send(asio::buffer(sendmsg));
+ c.receive(asio::buffer(buf, 2048));
+ c.close();
+ EXPECT_EQ("401", std::string(buf + 9, buf + 12));
- app.stop();
+ app.stop();
}
// Tests that Base64 basic strings work
-TEST(TokenAuthentication, TestGetLoginUrl) {
- App<crow::persistent_data::Middleware, crow::token_authorization::Middleware>
- app;
- app.bindaddr("127.0.0.1").port(45451);
- BMCWEB_ROUTE(app, "/")([]() { return boost::beast::http::status::ok; });
- auto _ = async(std::launch::async, [&] { app.run(); });
-
- asio::io_service is;
- static char buf[2048];
-
- // Other resources should not be passed
- std::string sendmsg = "GET /login\r\n\r\n";
- asio::ip::tcp::socket c(is);
- for (int i = 0; i < 200; i++) {
- try {
- c.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string("127.0.0.1"), 45451));
- } catch (std::exception e) {
- // do nothing
+TEST(TokenAuthentication, TestGetLoginUrl)
+{
+ App<crow::persistent_data::Middleware,
+ crow::token_authorization::Middleware>
+ app;
+ app.bindaddr("127.0.0.1").port(45451);
+ BMCWEB_ROUTE(app, "/")([]() { return boost::beast::http::status::ok; });
+ auto _ = async(std::launch::async, [&] { app.run(); });
+
+ asio::io_service is;
+ static char buf[2048];
+
+ // Other resources should not be passed
+ std::string sendmsg = "GET /login\r\n\r\n";
+ asio::ip::tcp::socket c(is);
+ for (int i = 0; i < 200; i++)
+ {
+ try
+ {
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string("127.0.0.1"), 45451));
+ }
+ catch (std::exception e)
+ {
+ // do nothing
+ }
}
- }
- c.send(asio::buffer(sendmsg));
- c.receive(asio::buffer(buf, 2048));
- c.close();
- EXPECT_EQ("401", std::string(buf + 9, buf + 12));
+ c.send(asio::buffer(sendmsg));
+ c.receive(asio::buffer(buf, 2048));
+ c.close();
+ EXPECT_EQ("401", std::string(buf + 9, buf + 12));
- app.stop();
+ app.stop();
}
// Tests boundary conditions on login
-TEST(TokenAuthentication, TestPostBadLoginUrl) {
- App<crow::persistent_data::Middleware, crow::token_authorization::Middleware>
- app;
- app.bindaddr("127.0.0.1").port(45451);
- BMCWEB_ROUTE(app, "/")([]() { return boost::beast::http::status::ok; });
- auto _ = async(std::launch::async, [&] { app.run(); });
-
- asio::io_service is;
- std::array<char, 2048> buf;
- std::string sendmsg;
-
- auto send_to_localhost = [&is, &buf](std::string sendmsg) {
- asio::ip::tcp::socket c(is);
- c.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string("127.0.0.1"), 45451));
- c.send(asio::buffer(sendmsg));
- c.receive(asio::buffer(buf));
- c.close();
- };
-
- {
- // Retry a couple of times waiting for the server to come up
- asio::ip::tcp::socket c(is);
- for (int i = 0; i < 200; i++) {
- try {
+TEST(TokenAuthentication, TestPostBadLoginUrl)
+{
+ App<crow::persistent_data::Middleware,
+ crow::token_authorization::Middleware>
+ app;
+ app.bindaddr("127.0.0.1").port(45451);
+ BMCWEB_ROUTE(app, "/")([]() { return boost::beast::http::status::ok; });
+ auto _ = async(std::launch::async, [&] { app.run(); });
+
+ asio::io_service is;
+ std::array<char, 2048> buf;
+ std::string sendmsg;
+
+ auto send_to_localhost = [&is, &buf](std::string sendmsg) {
+ asio::ip::tcp::socket c(is);
c.connect(asio::ip::tcp::endpoint(
asio::ip::address::from_string("127.0.0.1"), 45451));
+ c.send(asio::buffer(sendmsg));
+ c.receive(asio::buffer(buf));
c.close();
- break;
- } catch (std::exception e) {
- // do nothing. We expect this to fail while the server is starting up
- }
+ };
+
+ {
+ // Retry a couple of times waiting for the server to come up
+ asio::ip::tcp::socket c(is);
+ for (int i = 0; i < 200; i++)
+ {
+ try
+ {
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string("127.0.0.1"), 45451));
+ c.close();
+ break;
+ }
+ catch (std::exception e)
+ {
+ // do nothing. We expect this to fail while the server is
+ // starting up
+ }
+ }
}
- }
-
- // Test blank login credentials
- sendmsg = "POST /login\r\nContent-Length:0\r\n\r\n\r\n";
- {
- send_to_localhost(sendmsg);
- auto return_code = std::string(&buf[9], &buf[12]);
- EXPECT_EQ("400", return_code);
- }
-
- // Test wrong login credentials
- sendmsg =
- "POST /login\r\nContent-Length:38\r\n\r\n{\"username\": \"foo\", "
- "\"password\": \"bar\"}\r\n";
- {
- send_to_localhost(sendmsg);
- auto return_code = std::string(&buf[9], &buf[12]);
- EXPECT_EQ("401", return_code);
- // TODO(ed) need to test more here. Response string?
- }
-
- // Test only sending a username
- sendmsg =
- "POST /login\r\nContent-Length:19\r\n\r\n{\"username\": \"foo\"}\r\n";
- {
- send_to_localhost(sendmsg);
- auto return_code = std::string(&buf[9], &buf[12]);
- EXPECT_EQ("400", return_code);
- }
-
- // Test only sending a password
- sendmsg =
- "POST /login\r\nContent-Length:19\r\n\r\n{\"password\": \"foo\"}\r\n";
- {
- send_to_localhost(sendmsg);
- auto return_code = std::string(&buf[9], &buf[12]);
- EXPECT_EQ("400", return_code);
- }
-
- app.stop();
-}
-// Test class that allows login for a fixed password.
-class KnownLoginAuthenticator {
- public:
- inline bool authenticate(const std::string& username,
- const std::string& password) {
- return (username == "dude") && (password == "foo");
- }
-};
+ // Test blank login credentials
+ sendmsg = "POST /login\r\nContent-Length:0\r\n\r\n\r\n";
+ {
+ send_to_localhost(sendmsg);
+ auto return_code = std::string(&buf[9], &buf[12]);
+ EXPECT_EQ("400", return_code);
+ }
-TEST(TokenAuthentication, TestSuccessfulLogin) {
- App<crow::persistent_data::Middleware, crow::token_authorization::Middleware>
- app;
- app.bindaddr("127.0.0.1").port(45451);
- BMCWEB_ROUTE(app, "/")([]() { return boost::beast::http::status::ok; });
- auto _ = async(std::launch::async, [&] { app.run(); });
+ // Test wrong login credentials
+ sendmsg = "POST /login\r\nContent-Length:38\r\n\r\n{\"username\": \"foo\", "
+ "\"password\": \"bar\"}\r\n";
+ {
+ send_to_localhost(sendmsg);
+ auto return_code = std::string(&buf[9], &buf[12]);
+ EXPECT_EQ("401", return_code);
+ // TODO(ed) need to test more here. Response string?
+ }
- asio::io_service is;
- std::array<char, 2048> buf;
- std::string sendmsg;
+ // Test only sending a username
+ sendmsg =
+ "POST /login\r\nContent-Length:19\r\n\r\n{\"username\": \"foo\"}\r\n";
+ {
+ send_to_localhost(sendmsg);
+ auto return_code = std::string(&buf[9], &buf[12]);
+ EXPECT_EQ("400", return_code);
+ }
- auto send_to_localhost = [&is, &buf](std::string sendmsg) {
- asio::ip::tcp::socket c(is);
- c.connect(asio::ip::tcp::endpoint(
- asio::ip::address::from_string("127.0.0.1"), 45451));
- c.send(asio::buffer(sendmsg));
- c.receive(asio::buffer(buf));
- c.close();
- };
+ // Test only sending a password
+ sendmsg =
+ "POST /login\r\nContent-Length:19\r\n\r\n{\"password\": \"foo\"}\r\n";
+ {
+ send_to_localhost(sendmsg);
+ auto return_code = std::string(&buf[9], &buf[12]);
+ EXPECT_EQ("400", return_code);
+ }
- {
- // Retry a couple of times waiting for the server to come up
- asio::ip::tcp::socket c(is);
- for (int i = 0; i < 200; i++) {
- try {
+ app.stop();
+}
+
+// Test class that allows login for a fixed password.
+class KnownLoginAuthenticator
+{
+ public:
+ inline bool authenticate(const std::string& username,
+ const std::string& password)
+ {
+ return (username == "dude") && (password == "foo");
+ }
+};
+
+TEST(TokenAuthentication, TestSuccessfulLogin)
+{
+ App<crow::persistent_data::Middleware,
+ crow::token_authorization::Middleware>
+ app;
+ app.bindaddr("127.0.0.1").port(45451);
+ BMCWEB_ROUTE(app, "/")([]() { return boost::beast::http::status::ok; });
+ auto _ = async(std::launch::async, [&] { app.run(); });
+
+ asio::io_service is;
+ std::array<char, 2048> buf;
+ std::string sendmsg;
+
+ auto send_to_localhost = [&is, &buf](std::string sendmsg) {
+ asio::ip::tcp::socket c(is);
c.connect(asio::ip::tcp::endpoint(
asio::ip::address::from_string("127.0.0.1"), 45451));
+ c.send(asio::buffer(sendmsg));
+ c.receive(asio::buffer(buf));
c.close();
- break;
- } catch (std::exception e) {
- // do nothing. We expect this to fail while the server is starting up
- }
+ };
+
+ {
+ // Retry a couple of times waiting for the server to come up
+ asio::ip::tcp::socket c(is);
+ for (int i = 0; i < 200; i++)
+ {
+ try
+ {
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string("127.0.0.1"), 45451));
+ c.close();
+ break;
+ }
+ catch (std::exception e)
+ {
+ // do nothing. We expect this to fail while the server is
+ // starting up
+ }
+ }
}
- }
-
- // Test correct login credentials
- sendmsg =
- "POST /login\r\nContent-Length:40\r\n\r\n{\"username\": \"dude\", "
- "\"password\": \"foo\"}\r\n";
- {
- send_to_localhost(sendmsg);
- std::string response(std::begin(buf), std::end(buf));
- // This is a routine to split strings until a newline is hit
- // TODO(ed) this should really use the HTTP parser
- std::vector<std::string> headers;
- std::string::size_type pos = 0;
- std::string::size_type prev = 0;
- int content_length = 0;
- std::string content_encoding("");
- while ((pos = response.find("\r\n", prev)) != std::string::npos) {
- auto this_string = response.substr(prev, pos - prev);
- if (this_string == "") {
- prev = pos + 2;
- break;
- }
-
- headers.push_back(this_string);
- prev = pos + 2;
+
+ // Test correct login credentials
+ sendmsg =
+ "POST /login\r\nContent-Length:40\r\n\r\n{\"username\": \"dude\", "
+ "\"password\": \"foo\"}\r\n";
+ {
+ send_to_localhost(sendmsg);
+ std::string response(std::begin(buf), std::end(buf));
+ // This is a routine to split strings until a newline is hit
+ // TODO(ed) this should really use the HTTP parser
+ std::vector<std::string> headers;
+ std::string::size_type pos = 0;
+ std::string::size_type prev = 0;
+ int content_length = 0;
+ std::string content_encoding("");
+ while ((pos = response.find("\r\n", prev)) != std::string::npos)
+ {
+ auto this_string = response.substr(prev, pos - prev);
+ if (this_string == "")
+ {
+ prev = pos + 2;
+ break;
+ }
+
+ headers.push_back(this_string);
+ prev = pos + 2;
+ }
+ EXPECT_EQ(headers[0], "HTTP/1.1 200 OK");
+ EXPECT_THAT(headers,
+ testing::Contains("Content-Type: application/json"));
+ auto http_content = response.substr(prev);
}
- EXPECT_EQ(headers[0], "HTTP/1.1 200 OK");
- EXPECT_THAT(headers, testing::Contains("Content-Type: application/json"));
- auto http_content = response.substr(prev);
- }
-
- // Try to use those login credentials to access a resource
- sendmsg =
- "GET /\r\nAuthorization: token\r\n\r\n{\"username\": \"dude\", "
- "\"password\": \"dude\"}\r\n";
- {
- send_to_localhost(sendmsg);
- auto return_code = std::string(&buf[9], &buf[12]);
- EXPECT_EQ("200", return_code);
- }
-
- app.stop();
+
+ // Try to use those login credentials to access a resource
+ sendmsg = "GET /\r\nAuthorization: token\r\n\r\n{\"username\": \"dude\", "
+ "\"password\": \"dude\"}\r\n";
+ {
+ send_to_localhost(sendmsg);
+ auto return_code = std::string(&buf[9], &buf[12]);
+ EXPECT_EQ("200", return_code);
+ }
+
+ app.stop();
} \ No newline at end of file
diff --git a/src/webassets_test.cpp b/src/webassets_test.cpp
index 2633c9b65b..a3106f2796 100644
--- a/src/webassets_test.cpp
+++ b/src/webassets_test.cpp
@@ -1,135 +1,145 @@
#include <crow/app.h>
-#include <gmock/gmock.h>
-#include <gzip_helper.hpp>
-#include <webassets.hpp>
-#include <sstream>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/lexical_cast.hpp>
+#include <gzip_helper.hpp>
+#include <sstream>
+#include <webassets.hpp>
+
#include "gtest/gtest.h"
+#include <gmock/gmock.h>
using namespace crow;
using namespace std;
using namespace testing;
// Tests static files are loaded correctly
-TEST(Webassets, StaticFilesFixedRoutes) {
- std::array<char, 2048> buf;
- SimpleApp app;
- webassets::requestRoutes(app);
- Server<SimpleApp> server(&app, "127.0.0.1", 45451);
- auto _ = async(launch::async, [&] { server.run(); });
-
- // get the homepage
- std::string sendmsg = "GET /\r\n\r\n";
-
- asio::io_service is;
-
- asio::ip::tcp::socket c(is);
- c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string("127.0.0.1"),
- 45451));
-
- c.send(asio::buffer(sendmsg));
-
- c.receive(asio::buffer(buf, 2048));
- c.close();
-
- std::string response(std::begin(buf), std::end(buf));
- // This is a routine to split strings until a newline is hit
- // TODO(ed) this should really use the HTTP parser
- std::vector<std::string> headers;
- std::string::size_type pos = 0;
- std::string::size_type prev = 0;
- int content_length = 0;
- std::string content_encoding("");
- while ((pos = response.find("\r\n", prev)) != std::string::npos) {
- auto this_string = response.substr(prev, pos - prev);
- if (this_string == "") {
- prev = pos + 2;
- break;
+TEST(Webassets, StaticFilesFixedRoutes)
+{
+ std::array<char, 2048> buf;
+ SimpleApp app;
+ webassets::requestRoutes(app);
+ Server<SimpleApp> server(&app, "127.0.0.1", 45451);
+ auto _ = async(launch::async, [&] { server.run(); });
+
+ // get the homepage
+ std::string sendmsg = "GET /\r\n\r\n";
+
+ asio::io_service is;
+
+ asio::ip::tcp::socket c(is);
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string("127.0.0.1"), 45451));
+
+ c.send(asio::buffer(sendmsg));
+
+ c.receive(asio::buffer(buf, 2048));
+ c.close();
+
+ std::string response(std::begin(buf), std::end(buf));
+ // This is a routine to split strings until a newline is hit
+ // TODO(ed) this should really use the HTTP parser
+ std::vector<std::string> headers;
+ std::string::size_type pos = 0;
+ std::string::size_type prev = 0;
+ int content_length = 0;
+ std::string content_encoding("");
+ while ((pos = response.find("\r\n", prev)) != std::string::npos)
+ {
+ auto this_string = response.substr(prev, pos - prev);
+ if (this_string == "")
+ {
+ prev = pos + 2;
+ break;
+ }
+
+ if (boost::starts_with(this_string, "Content-Length: "))
+ {
+ content_length = boost::lexical_cast<int>(this_string.substr(16));
+ // TODO(ed) This is an unfortunate test, but it's all we have at
+ // this point Realistically, the index.html will be more than 500
+ // bytes. This test will need to be improved at some point
+ EXPECT_GT(content_length, 500);
+ }
+ if (boost::starts_with(this_string, "Content-Encoding: "))
+ {
+ content_encoding = this_string.substr(18);
+ }
+
+ headers.push_back(this_string);
+ prev = pos + 2;
}
- if (boost::starts_with(this_string, "Content-Length: ")) {
- content_length = boost::lexical_cast<int>(this_string.substr(16));
- // TODO(ed) This is an unfortunate test, but it's all we have at this
- // point
- // Realistically, the index.html will be more than 500 bytes. This
- // test will need to be improved at some point
- EXPECT_GT(content_length, 500);
- }
- if (boost::starts_with(this_string, "Content-Encoding: ")) {
- content_encoding = this_string.substr(18);
+ auto http_content = response.substr(prev);
+ // TODO(ed) ideally the server should support non-compressed gzip assets.
+ // Once this occurs, this line will be obsolete
+ std::string ungziped_content = http_content;
+ if (content_encoding == "gzip")
+ {
+ EXPECT_TRUE(gzipInflate(http_content, ungziped_content));
}
- headers.push_back(this_string);
- prev = pos + 2;
- }
-
- auto http_content = response.substr(prev);
- // TODO(ed) ideally the server should support non-compressed gzip assets.
- // Once this occurs, this line will be obsolete
- std::string ungziped_content = http_content;
- if (content_encoding == "gzip") {
- EXPECT_TRUE(gzipInflate(http_content, ungziped_content));
- }
-
- EXPECT_EQ(headers[0], "HTTP/1.1 200 OK");
- EXPECT_THAT(headers,
- ::testing::Contains("Content-Type: text/html;charset=UTF-8"));
+ EXPECT_EQ(headers[0], "HTTP/1.1 200 OK");
+ EXPECT_THAT(headers,
+ ::testing::Contains("Content-Type: text/html;charset=UTF-8"));
- EXPECT_EQ(ungziped_content.substr(0, 21), "<!DOCTYPE html>\n<html");
+ EXPECT_EQ(ungziped_content.substr(0, 21), "<!DOCTYPE html>\n<html");
- server.stop();
+ server.stop();
}
// Tests static files are loaded correctly
-TEST(Webassets, EtagIsSane) {
- std::array<char, 2048> buf;
- SimpleApp app;
- webassets::requestRoutes(app);
- Server<SimpleApp> server(&app, "127.0.0.1", 45451);
- auto _ = async(launch::async, [&] { server.run(); });
-
- // get the homepage
- std::string sendmsg = "GET /\r\n\r\n";
-
- asio::io_service is;
-
- asio::ip::tcp::socket c(is);
- c.connect(asio::ip::tcp::endpoint(asio::ip::address::from_string("127.0.0.1"),
- 45451));
-
- c.send(asio::buffer(sendmsg));
-
- c.receive(asio::buffer(buf, 2048));
- c.close();
-
- std::string response(std::begin(buf), std::end(buf));
- // This is a routine to split strings until a newline is hit
- // TODO(ed) this should really use the HTTP parser
- std::vector<std::string> headers;
- std::string::size_type pos = 0;
- std::string::size_type prev = 0;
- int content_length = 0;
- std::string content_encoding("");
- while ((pos = response.find("\r\n", prev)) != std::string::npos) {
- auto this_string = response.substr(prev, pos - prev);
- if (this_string == "") {
- break;
+TEST(Webassets, EtagIsSane)
+{
+ std::array<char, 2048> buf;
+ SimpleApp app;
+ webassets::requestRoutes(app);
+ Server<SimpleApp> server(&app, "127.0.0.1", 45451);
+ auto _ = async(launch::async, [&] { server.run(); });
+
+ // get the homepage
+ std::string sendmsg = "GET /\r\n\r\n";
+
+ asio::io_service is;
+
+ asio::ip::tcp::socket c(is);
+ c.connect(asio::ip::tcp::endpoint(
+ asio::ip::address::from_string("127.0.0.1"), 45451));
+
+ c.send(asio::buffer(sendmsg));
+
+ c.receive(asio::buffer(buf, 2048));
+ c.close();
+
+ std::string response(std::begin(buf), std::end(buf));
+ // This is a routine to split strings until a newline is hit
+ // TODO(ed) this should really use the HTTP parser
+ std::vector<std::string> headers;
+ std::string::size_type pos = 0;
+ std::string::size_type prev = 0;
+ int content_length = 0;
+ std::string content_encoding("");
+ while ((pos = response.find("\r\n", prev)) != std::string::npos)
+ {
+ auto this_string = response.substr(prev, pos - prev);
+ if (this_string == "")
+ {
+ break;
+ }
+
+ if (boost::starts_with(this_string, "ETag: "))
+ {
+ auto etag = this_string.substr(6);
+ // ETAG should not be blank
+ EXPECT_NE(etag, "");
+ // SHa1 is 20 characters long
+ EXPECT_EQ(etag.size(), 40);
+ EXPECT_THAT(etag, MatchesRegex("^[a-f0-9]+$"));
+ }
+
+ headers.push_back(this_string);
+ prev = pos + 2;
}
- if (boost::starts_with(this_string, "ETag: ")) {
- auto etag = this_string.substr(6);
- // ETAG should not be blank
- EXPECT_NE(etag, "");
- // SHa1 is 20 characters long
- EXPECT_EQ(etag.size(), 40);
- EXPECT_THAT(etag, MatchesRegex("^[a-f0-9]+$"));
- }
-
- headers.push_back(this_string);
- prev = pos + 2;
- }
-
- server.stop();
+ server.stop();
}
diff --git a/src/webserver_main.cpp b/src/webserver_main.cpp
index 2f89ad4269..051b1fed61 100644
--- a/src/webserver_main.cpp
+++ b/src/webserver_main.cpp
@@ -1,8 +1,12 @@
+#include <crow/app.h>
#include <systemd/sd-daemon.h>
+
#include <bmcweb/settings.hpp>
+#include <boost/asio.hpp>
#include <dbus_monitor.hpp>
#include <dbus_singleton.hpp>
#include <image_upload.hpp>
+#include <memory>
#include <openbmc_dbus_rest.hpp>
#include <persistent_data_middleware.hpp>
#include <redfish.hpp>
@@ -12,84 +16,91 @@
#include <sdbusplus/server.hpp>
#include <security_headers_middleware.hpp>
#include <ssl_key_handler.hpp>
+#include <string>
#include <token_authorization_middleware.hpp>
#include <web_kvm.hpp>
#include <webassets.hpp>
#include <webserver_common.hpp>
-#include <memory>
-#include <string>
-#include <crow/app.h>
-#include <boost/asio.hpp>
constexpr int defaultPort = 18080;
template <typename... Middlewares>
-void setupSocket(crow::Crow<Middlewares...>& app) {
- int listenFd = sd_listen_fds(0);
- if (1 == listenFd) {
- BMCWEB_LOG_INFO << "attempting systemd socket activation";
- if (sd_is_socket_inet(SD_LISTEN_FDS_START, AF_UNSPEC, SOCK_STREAM, 1, 0)) {
- BMCWEB_LOG_INFO << "Starting webserver on socket handle "
- << SD_LISTEN_FDS_START;
- app.socket(SD_LISTEN_FDS_START);
- } else {
- BMCWEB_LOG_INFO << "bad incoming socket, starting webserver on port "
- << defaultPort;
- app.port(defaultPort);
+void setupSocket(crow::Crow<Middlewares...>& app)
+{
+ int listenFd = sd_listen_fds(0);
+ if (1 == listenFd)
+ {
+ BMCWEB_LOG_INFO << "attempting systemd socket activation";
+ if (sd_is_socket_inet(SD_LISTEN_FDS_START, AF_UNSPEC, SOCK_STREAM, 1,
+ 0))
+ {
+ BMCWEB_LOG_INFO << "Starting webserver on socket handle "
+ << SD_LISTEN_FDS_START;
+ app.socket(SD_LISTEN_FDS_START);
+ }
+ else
+ {
+ BMCWEB_LOG_INFO
+ << "bad incoming socket, starting webserver on port "
+ << defaultPort;
+ app.port(defaultPort);
+ }
+ }
+ else
+ {
+ BMCWEB_LOG_INFO << "Starting webserver on port " << defaultPort;
+ app.port(defaultPort);
}
- } else {
- BMCWEB_LOG_INFO << "Starting webserver on port " << defaultPort;
- app.port(defaultPort);
- }
}
-int main(int argc, char** argv) {
- crow::logger::setLogLevel(crow::LogLevel::DEBUG);
+int main(int argc, char** argv)
+{
+ crow::logger::setLogLevel(crow::LogLevel::DEBUG);
- auto io = std::make_shared<boost::asio::io_service>();
- CrowApp app(io);
+ auto io = std::make_shared<boost::asio::io_service>();
+ CrowApp app(io);
#ifdef BMCWEB_ENABLE_SSL
- std::string sslPemFile("server.pem");
- std::cout << "Building SSL Context\n";
+ std::string sslPemFile("server.pem");
+ std::cout << "Building SSL Context\n";
- ensuressl::ensureOpensslKeyPresentAndValid(sslPemFile);
- std::cout << "SSL Enabled\n";
- auto sslContext = ensuressl::getSslContext(sslPemFile);
- app.ssl(std::move(sslContext));
+ ensuressl::ensureOpensslKeyPresentAndValid(sslPemFile);
+ std::cout << "SSL Enabled\n";
+ auto sslContext = ensuressl::getSslContext(sslPemFile);
+ app.ssl(std::move(sslContext));
#endif
- // Static assets need to be initialized before Authorization, because auth
- // needs to build the whitelist from the static routes
+ // Static assets need to be initialized before Authorization, because auth
+ // needs to build the whitelist from the static routes
#ifdef BMCWEB_ENABLE_STATIC_HOSTING
- crow::webassets::requestRoutes(app);
+ crow::webassets::requestRoutes(app);
#endif
#ifdef BMCWEB_ENABLE_KVM
- crow::kvm::requestRoutes(app);
+ crow::kvm::requestRoutes(app);
#endif
#ifdef BMCWEB_ENABLE_REDFISH
- crow::redfish::requestRoutes(app);
+ crow::redfish::requestRoutes(app);
#endif
#ifdef BMCWEB_ENABLE_DBUS_REST
- crow::dbus_monitor::requestRoutes(app);
- crow::image_upload::requestRoutes(app);
- crow::openbmc_mapper::requestRoutes(app);
+ crow::dbus_monitor::requestRoutes(app);
+ crow::image_upload::requestRoutes(app);
+ crow::openbmc_mapper::requestRoutes(app);
#endif
- crow::token_authorization::requestRoutes(app);
+ crow::token_authorization::requestRoutes(app);
- BMCWEB_LOG_INFO << "bmcweb (" << __DATE__ << ": " << __TIME__ << ')';
- setupSocket(app);
+ BMCWEB_LOG_INFO << "bmcweb (" << __DATE__ << ": " << __TIME__ << ')';
+ setupSocket(app);
- crow::connections::systemBus =
- std::make_shared<sdbusplus::asio::connection>(*io);
- redfish::RedfishService redfish(app);
+ crow::connections::systemBus =
+ std::make_shared<sdbusplus::asio::connection>(*io);
+ redfish::RedfishService redfish(app);
- app.run();
- io->run();
+ app.run();
+ io->run();
- crow::connections::systemBus.reset();
+ crow::connections::systemBus.reset();
}