| #include "subscription_backend_impl.hpp" | |
| #include <memory> | |
| #include <string> | |
| #include <system_error> // NOLINT | |
| #include <unordered_set> | |
| #include <utility> | |
| #include <vector> | |
| #include "absl/log/die_if_null.h" | |
| #include "absl/memory/memory.h" | |
| #include "absl/status/status.h" | |
| #include "absl/status/statusor.h" | |
| #include "absl/strings/string_view.h" | |
| #include "boost/beast/http/message.hpp" //NOLINT | |
| #include "boost/beast/http/string_body.hpp" //NOLINT | |
| #include "boost/beast/http/verb.hpp" // NOLINT | |
| #include "subscription.h" | |
| #include "g3/macros.h" | |
| #include "app.hpp" | |
| #include "http_request.hpp" | |
| #include "http_response.hpp" | |
| #include "async_resp.hpp" | |
| #include <nlohmann/json.hpp> | |
| namespace milotic { | |
| namespace { | |
| // Create Internal Request to query given `url`. | |
| absl::StatusOr<crow::Request> CreateInternalRedfishRequest( | |
| absl::string_view url, boost::beast::http::verb method, | |
| const std::unordered_set<std::string>& peer_privileges) { | |
| boost::beast::http::request<boost::beast::http::string_body> boost_request; | |
| boost_request.target(url); | |
| boost_request.method(method); | |
| std::error_code error; | |
| crow::Request crow_request(boost_request, error); | |
| if (error) { | |
| return absl::InternalError("Error creating crow_request."); | |
| } | |
| crow_request.fromGrpc = true; | |
| // At this moment, peer is authenticated for sure and BMC must have trust | |
| // bundle. These have been checked in the Subscription RPC handler. | |
| crow_request.peer_authenticated = true; | |
| crow_request.with_trust_bundle = true; | |
| crow_request.peer_privileges = peer_privileges; | |
| return crow_request; | |
| } | |
| } // namespace | |
| std::unique_ptr<BmcWebBackend> BmcWebBackend::Create(App* app) { | |
| return absl::WrapUnique(new BmcWebBackend(*ABSL_DIE_IF_NULL(app))); | |
| } | |
| absl::Status BmcWebBackend::Query( | |
| absl::string_view url, QueryCallback&& query_callback, | |
| const std::unordered_set<std::string>& peer_privileges) { | |
| // Strand is not needed for subscriptions. | |
| auto async_resp = std::make_shared<bmcweb::AsyncResp>(nullptr); | |
| async_resp->response_type = | |
| bmcweb::AsyncResp::ResponseType::kOriginOfCondition; | |
| ECCLESIA_ASSIGN_OR_RETURN( | |
| crow::Request crow_request, | |
| CreateInternalRedfishRequest(url, boost::beast::http::verb::get, | |
| peer_privileges)); | |
| async_resp->res.setCompleteRequestHandler( | |
| [query_callback(std::move(query_callback))](crow::Response& res) { | |
| if (!res.stringResponse) { | |
| query_callback(absl::InternalError("HTTP response is empty!"), {}); | |
| return; | |
| } | |
| query_callback(absl::OkStatus(), res.jsonValue); | |
| }); | |
| app_.handle(crow_request, async_resp); | |
| return absl::OkStatus(); | |
| } | |
| absl::Status BmcWebBackend::Subscribe( | |
| absl::string_view url, SubscribeCallback&& callback, | |
| const std::unordered_set<std::string>& peer_privileges) { | |
| // Strand is not needed for subscriptions. | |
| auto async_resp = std::make_shared<bmcweb::AsyncResp>(nullptr); | |
| async_resp->response_type = bmcweb::AsyncResp::ResponseType::kSubscription; | |
| ECCLESIA_ASSIGN_OR_RETURN( | |
| crow::Request crow_request, | |
| CreateInternalRedfishRequest(url, boost::beast::http::verb::get, | |
| peer_privileges)); | |
| async_resp->res.setCompleteRequestHandler( | |
| [subscribe_callback(std::move(callback))](crow::Response& res) { | |
| if (res.eventSourceIds.empty()) { | |
| subscribe_callback( | |
| absl::InternalError("EventSourceIds are not populated!"), {}); | |
| return; | |
| } | |
| subscribe_callback(absl::OkStatus(), res.eventSourceIds); | |
| }); | |
| app_.handle(crow_request, async_resp); | |
| return absl::OkStatus(); | |
| } | |
| } // namespace milotic |