blob: 504dfc9c578b32d06d58f3a110257b0a5fcacaa0 [file] [log] [blame]
#include "smart_router.h"
#include <cstddef>
#include <iostream>
#include <memory>
#include <string>
#include <string_view>
#include <vector>
#include "absl/container/flat_hash_map.h"
#include "absl/container/flat_hash_set.h"
#include "absl/strings/str_split.h"
#include "absl/synchronization/mutex.h"
#include "http_request.hpp"
#include "async_resp.hpp"
#include "tlbmc/hal/shared_mem/server.h"
#include "tlbmc/redfish/verb.h"
#include "app_interface.h"
#include "routing.hpp"
// DO NOT MODIFY THIS FILE IN GERRIT. THIS FILE SHOULD ONLY BE MODIFIED IN G3
namespace crow {
using ::milotic_tlbmc::SharedMemoryServer;
namespace internal {
void SimpleTrie::AddSubtree(std::string_view subtree) {
std::vector<std::string_view> parts =
absl::StrSplit(subtree, '/', absl::SkipEmpty());
Node* node = &root_;
for (const auto& part : parts) {
node = &node->children[part];
}
node->is_leaf = true;
}
SimpleTrie::SimpleTrie(const absl::flat_hash_set<std::string>& subtrees)
: subtrees_(subtrees) {
for (const auto& subtree : subtrees) {
AddSubtree(subtree);
}
}
void SimpleTrie::DebugPrint() const {
std::cerr << "tlBMC owned subtrees: \n";
for (const auto& subtree : subtrees_) {
std::cerr << subtree << "\n";
}
}
bool SimpleTrie::IsUrlInSubtrees(std::string_view url) const {
const Node* node = &root_;
std::vector<std::string_view> parts =
absl::StrSplit(url, '/', absl::SkipEmpty());
for (const auto& part : parts) {
if (node->is_leaf) {
return true;
}
auto it = node->children.find(part);
if (it == node->children.end()) {
return false;
}
node = &it->second;
}
return node->is_leaf;
}
} // namespace internal
SmartRouter::SmartRouter(bool allow_session_empty, AppInterface* tlbmc_app)
: gbmcweb_router_(allow_session_empty),
tlbmc_app_(tlbmc_app),
tlbmc_owned_urls_(GetTlbmcOwnedUrls()),
tlbmc_owned_subtrees_(GetTlbmcOwnedSubtrees()) {
// We still need this logic to set the smart router for the tlbmc router.
if (tlbmc_app_ != nullptr) {
tlbmc_app_->SetSmartRouter(this);
std::cerr << "SmartRouter created! Owned URLs: \n";
for (const auto& [url, methods] : tlbmc_owned_urls_) {
std::cerr << "url: " << url
<< " methods: " << milotic_tlbmc::MethodFieldsToString(methods)
<< "\n";
}
}
}
void SmartRouter::Handle(crow::Request& req,
const std::shared_ptr<bmcweb::AsyncResp>& async_resp) {
boost::urls::url url(req.target());
// If the request is not owned by TLBMC, then we will forward it to gBMCWeb.
if (tlbmc_app_ == nullptr ||
!IsTlbmcOwnedUrl(url.encoded_path(), req.method())) {
gbmcweb_router_.handle(req, async_resp);
if (tlbmc_app_ != nullptr) {
SharedMemoryServer::GetInstance().UpdateMetricsRequestCount(false);
}
return;
}
// Otherwise we prepare for tlbmc to handle it.
SharedMemoryServer::GetInstance().UpdateMetricsRequestCount(true);
tlbmc_app_->HandleFromCrowRequest(req, async_resp);
}
std::vector<const std::string*> SmartRouter::GetRoutes(
const std::string& parent) {
return gbmcweb_router_.getRoutes(parent);
}
DynamicRule& SmartRouter::NewRuleDynamic(std::string&& rule) {
return gbmcweb_router_.newRuleDynamic(rule);
}
void SmartRouter::DebugPrint() {
gbmcweb_router_.debugPrint();
if (tlbmc_app_ != nullptr) {
tlbmc_app_->DebugPrint();
}
}
void SmartRouter::Validate() { gbmcweb_router_.validate(); }
absl::flat_hash_map<std::string, size_t> SmartRouter::GetTlbmcOwnedUrls() {
if (tlbmc_app_ == nullptr) {
return {};
}
return tlbmc_app_->GetOwnedUrls();
}
absl::flat_hash_set<std::string> SmartRouter::GetTlbmcOwnedSubtrees() {
if (tlbmc_app_ == nullptr) {
return {};
}
return tlbmc_app_->GetOwnedSubtrees();
}
bool SmartRouter::IsTlbmcOwnedUrl(std::string_view url,
boost::beast::http::verb verb) {
// Our `tlbmc_owned_urls_` do not have a trailing slash
if (url.ends_with('/')) {
url.remove_suffix(1);
}
if (tlbmc_owned_subtrees_.IsUrlInSubtrees(url)) {
return true;
}
// NOLINTNEXTLINE: Yocto's Abseil is old and only supports pointer type
absl::MutexLock lock(&tlbmc_owned_urls_mutex_);
auto it = tlbmc_owned_urls_.find(url);
if (it == tlbmc_owned_urls_.end()) {
return false;
}
return milotic_tlbmc::MethodFieldsContainBoostVerb(it->second, verb);
}
void SmartRouter::UpdateTlbmcOwnedUrls() {
// NOLINTNEXTLINE: Yocto's Abseil is old and only supports pointer type
absl::MutexLock lock(&tlbmc_owned_urls_mutex_);
tlbmc_owned_urls_ = GetTlbmcOwnedUrls();
}
} // namespace crow