summaryrefslogtreecommitdiff
path: root/http/routing.hpp
diff options
context:
space:
mode:
authorEd Tanous <edtanous@google.com>2022-03-14 20:16:07 +0300
committerEd Tanous <ed@tanous.net>2022-05-10 20:47:43 +0300
commit867b2056d44300db9769e0d0b8883435a179834c (patch)
tree3164329b8e49bd99c38261692df067e110881fcb /http/routing.hpp
parent2a68dc80d62482bfa886e78e536e223b84094ad3 (diff)
downloadbmcweb-867b2056d44300db9769e0d0b8883435a179834c.tar.xz
Handle HEAD and Allow headers per the spec
The Redfish specification calls out that the Allow header should be returned for all resources to give a client an indication of what actions are allowed on that resource. The router internally has all this data, so this patchset allows the router to construct an allow header value, as well as return early on a HEAD request. Tested: Called curl with various parameters and observed the Allow header curl -vvvv --insecure -X <VERB> --user root:0penBmc https://<bmc>/url HEAD /redfish/v1/SessionService/Sessions returned Allow: GET, POST HEAD /redfish/v1 returned Allow: GET HEAD /redfish/v1/SessionService returned Allow: GET, PATCH POST /redfish/v1 returned Allow: GET (method not allowed) GET /redfish/v1 returned Allow: GET GET /redfish/v1/SessionService returned Allow: GET, PATCH Redfish-Protocol-Validator now reports more tests passing. Prior to this patch: Pass: 255, Warning: 0, Fail: 27, Not tested: 45 After this patch: Pass: 262, Warning: 0, Fail: 21, Not tested: 43 Diff: 7 more tests passing All tests under RESP_HEADERS_ALLOW_METHOD_NOT_ALLOWED and RESP_HEADERS_ALLOW_GET_OR_HEAD are now passing Included unit tests passing. Change-Id: Ib99835050b15eb4f419bfd21375b26e4db74fa2c Signed-off-by: Ed Tanous <edtanous@google.com>
Diffstat (limited to 'http/routing.hpp')
-rw-r--r--http/routing.hpp53
1 files changed, 42 insertions, 11 deletions
diff --git a/http/routing.hpp b/http/routing.hpp
index 5f29761edd..7bac283437 100644
--- a/http/routing.hpp
+++ b/http/routing.hpp
@@ -12,6 +12,7 @@
#include "websocket.hpp"
#include <async_resp.hpp>
+#include <boost/beast/ssl/ssl_stream.hpp>
#include <boost/container/flat_map.hpp>
#include <cerrno>
@@ -1208,6 +1209,30 @@ class Router
}
}
+ std::string buildAllowHeader(Request& req)
+ {
+ std::string allowHeader;
+ // Check to see if this url exists at any verb
+ for (size_t perMethodIndex = 0; perMethodIndex < perMethods.size();
+ perMethodIndex++)
+ {
+ const PerMethod& p = perMethods[perMethodIndex];
+ const std::pair<unsigned, RoutingParams>& found2 =
+ p.trie.find(req.url);
+ if (found2.first == 0)
+ {
+ continue;
+ }
+ if (!allowHeader.empty())
+ {
+ allowHeader += ", ";
+ }
+ allowHeader += boost::beast::http::to_string(
+ static_cast<boost::beast::http::verb>(perMethodIndex));
+ }
+ return allowHeader;
+ }
+
void handle(Request& req,
const std::shared_ptr<bmcweb::AsyncResp>& asyncResp)
{
@@ -1219,25 +1244,31 @@ class Router
PerMethod& perMethod = perMethods[static_cast<size_t>(req.method())];
Trie& trie = perMethod.trie;
std::vector<BaseRule*>& rules = perMethod.rules;
+ std::string allowHeader = buildAllowHeader(req);
+ if (!allowHeader.empty())
+ {
+ asyncResp->res.addHeader(boost::beast::http::field::allow,
+ allowHeader);
+
+ // If this is a header request, we're done.
+ if (req.method() == boost::beast::http::verb::head)
+ {
+ return;
+ }
+ }
const std::pair<unsigned, RoutingParams>& found = trie.find(req.url);
unsigned ruleIndex = found.first;
-
if (ruleIndex == 0U)
{
- // Check to see if this url exists at any verb
- for (const PerMethod& p : perMethods)
+ if (!allowHeader.empty())
{
- const std::pair<unsigned, RoutingParams>& found2 =
- p.trie.find(req.url);
- if (found2.first > 0)
- {
- asyncResp->res.result(
- boost::beast::http::status::method_not_allowed);
- return;
- }
+ asyncResp->res.result(
+ boost::beast::http::status::method_not_allowed);
+ return;
}
+
BMCWEB_LOG_DEBUG << "Cannot match rules " << req.url;
asyncResp->res.result(boost::beast::http::status::not_found);
return;