summaryrefslogtreecommitdiff
path: root/http/routing.hpp
diff options
context:
space:
mode:
authorEd Tanous <edtanous@google.com>2022-08-01 02:36:52 +0300
committerEd Tanous <ed@tanous.net>2022-09-01 02:01:04 +0300
commit759cf1055aaf9be84ea08631578a1f3c712ecc61 (patch)
tree04df2ed591441d7aae1c810bb6fab27f57dc74c1 /http/routing.hpp
parent44e4518b700bd97cdca09d05e3c24712a4799788 (diff)
downloadbmcweb-759cf1055aaf9be84ea08631578a1f3c712ecc61.tar.xz
Add Method Not Allowed (405) handler
Similar to the 404 handler, add a 405 handler for registering custom 405 handlers for a given tree. The primary use case is for protocols like redfish that support specific messages for 405 handlers that don't have an empty body. Tested: Unit tests pass. PATCH /redfish/v1 returns 405 Method Not Allowed POST /redfish/v1/Chassis returns 405 Method Not Allowed POST /redfish/v1/Chassis/foo returns 405 Method Not Allowed PATCH /redfish/v1/foo/bar returns 404 Not Found GET /redfish/v1 returns ServiceRoot GET /redfish/v1/Chassis returns Chassis collection Signed-off-by: Ed Tanous <edtanous@google.com> Change-Id: Ib0afd23d46bb5b88f89cf1e3f4e0606a48ae47ca Signed-off-by: Carson Labrado <clabrado@google.com>
Diffstat (limited to 'http/routing.hpp')
-rw-r--r--http/routing.hpp84
1 files changed, 53 insertions, 31 deletions
diff --git a/http/routing.hpp b/http/routing.hpp
index 8852b304ab..870a62c9ed 100644
--- a/http/routing.hpp
+++ b/http/routing.hpp
@@ -39,6 +39,7 @@ static constexpr size_t maxVerbIndex =
// to keep the BaseRule as a single bitfield (thus keeping the struct small)
// while still having a way to declare a route a "not found" route.
static constexpr const size_t notFoundIndex = maxVerbIndex + 1;
+static constexpr const size_t methodNotAllowedIndex = notFoundIndex + 1;
class BaseRule
{
@@ -109,7 +110,7 @@ class BaseRule
size_t methodsBitfield{
1 << static_cast<size_t>(boost::beast::http::verb::get)};
static_assert(std::numeric_limits<decltype(methodsBitfield)>::digits >
- notFoundIndex,
+ methodNotAllowedIndex,
"Not enough bits to store bitfield");
std::vector<redfish::Privileges> privilegesSet;
@@ -464,6 +465,13 @@ struct RuleParameterTraits
return *self;
}
+ self_t& methodNotAllowed()
+ {
+ self_t* self = static_cast<self_t*>(this);
+ self->methodsBitfield = 1U << methodNotAllowedIndex;
+ return *self;
+ }
+
self_t& privileges(
const std::initializer_list<std::initializer_list<const char*>>& p)
{
@@ -1120,7 +1128,7 @@ class Router
{
return;
}
- for (size_t method = 0, methodBit = 1; method <= notFoundIndex;
+ for (size_t method = 0, methodBit = 1; method <= methodNotAllowedIndex;
method++, methodBit <<= 1)
{
if ((ruleObject->methodsBitfield & methodBit) > 0U)
@@ -1175,7 +1183,30 @@ class Router
FindRoute route;
};
- FindRouteResponse findRoute(const Request& req) const
+ FindRoute findRouteByIndex(std::string_view url, size_t index) const
+ {
+ FindRoute route;
+ if (index >= perMethods.size())
+ {
+ BMCWEB_LOG_CRITICAL << "Bad index???";
+ return route;
+ }
+ const PerMethod& perMethod = perMethods[index];
+ std::pair<unsigned, RoutingParams> found = perMethod.trie.find(url);
+ if (found.first >= perMethod.rules.size())
+ {
+ throw std::runtime_error("Trie internal structure corrupted!");
+ }
+ // Found a 404 route, switch that in
+ if (found.first != 0U)
+ {
+ route.rule = perMethod.rules[found.first];
+ route.params = std::move(found.second);
+ }
+ return route;
+ }
+
+ FindRouteResponse findRoute(Request& req) const
{
FindRouteResponse findRoute;
@@ -1187,11 +1218,8 @@ class Router
// Make sure it's safe to deference the array at that index
static_assert(maxVerbIndex <
std::tuple_size_v<decltype(perMethods)>);
-
- const PerMethod& perMethod = perMethods[perMethodIndex];
- std::pair<unsigned, RoutingParams> found2 =
- perMethod.trie.find(req.url);
- if (found2.first == 0)
+ FindRoute route = findRouteByIndex(req.url, perMethodIndex);
+ if (route.rule == nullptr)
{
continue;
}
@@ -1203,8 +1231,7 @@ class Router
static_cast<boost::beast::http::verb>(perMethodIndex));
if (perMethodIndex == reqMethodIndex)
{
- findRoute.route.rule = perMethod.rules[found2.first];
- findRoute.route.params = std::move(found2.second);
+ findRoute.route = route;
}
}
return findRoute;
@@ -1290,31 +1317,26 @@ class Router
FindRouteResponse foundRoute = findRoute(req);
- // Couldn't find a normal route with any verb, try looking for a 404
- // route
- if (foundRoute.allowHeader.empty())
+ if (foundRoute.route.rule == nullptr)
{
- if (foundRoute.route.rule == nullptr)
+ // Couldn't find a normal route with any verb, try looking for a 404
+ // route
+ if (foundRoute.allowHeader.empty())
{
- const PerMethod& perMethod = perMethods[notFoundIndex];
- std::pair<unsigned, RoutingParams> found =
- perMethod.trie.find(req.url);
- if (found.first >= perMethod.rules.size())
- {
- throw std::runtime_error(
- "Trie internal structure corrupted!");
- }
- // Found a 404 route, switch that in
- if (found.first != 0U)
- {
- foundRoute.route.rule = perMethod.rules[found.first];
- foundRoute.route.params = std::move(found.second);
- }
+ foundRoute.route = findRouteByIndex(req.url, notFoundIndex);
+ }
+ else
+ {
+ // See if we have a method not allowed (405) handler
+ foundRoute.route =
+ findRouteByIndex(req.url, methodNotAllowedIndex);
}
}
- else
+
+ // Fill in the allow header if it's valid
+ if (!foundRoute.allowHeader.empty())
{
- // Found at least one valid route, fill in the allow header
+
asyncResp->res.addHeader(boost::beast::http::field::allow,
foundRoute.allowHeader);
}
@@ -1491,7 +1513,7 @@ class Router
{}
};
- std::array<PerMethod, notFoundIndex + 1> perMethods;
+ std::array<PerMethod, methodNotAllowedIndex + 1> perMethods;
std::vector<std::unique_ptr<BaseRule>> allRules;
};
} // namespace crow