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-17 18:32:17 +0300
commit88a03c55257786d1c3e659b00531ffce071ea324 (patch)
tree69fe2f9db6bc3041164b7887ee3602b4ef5b33b1 /http/routing.hpp
parent32ca38afffa7cd91a4bd6be19b415e93cc89d224 (diff)
downloadbmcweb-88a03c55257786d1c3e659b00531ffce071ea324.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. This was reverted once here: https://gerrit.openbmc-project.xyz/c/openbmc/bmcweb/+/53637 Due to a redfish validator failure. With the previous patches workaround, this error has now been resolved. 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. Redfish service validator is now passing. Signed-off-by: Ed Tanous <edtanous@google.com> Change-Id: Ibd52a7c2babe19020a0e27fa1ac79a9d33463f25
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;