| #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 |