Add asyncResp support to handleUpgrade
This commit enables passing down the asyncResp (of the connection) to
the handler of upgraded connections. This is already in place for normal
requests (i.e. Class Router -> handle())
This change would enable any async calls that would be required before
upgrade of the connection. For example, as on today, we have only
Authentication of user in place for upgraded connection, but not
Authorization. So, this asyncResp could further be used for such dbus
calls to return informative response.
This commit updates the signature of all the handleUpgrade() functions
present in router.hpp to take in asyncResp object instead of normal
response.
Tested :
- websocket_test.py Passed
- KVM was functional in WebUI.
Change-Id: I1c6c91f126b734e1b5573d5ef204fe2bf6ed6c26
Signed-off-by: P Dheeraj Srujan Kumar <p.dheeraj.srujan.kumar@intel.com>
diff --git a/http/app.hpp b/http/app.hpp
index d3afe60..a2892ce 100644
--- a/http/app.hpp
+++ b/http/app.hpp
@@ -58,9 +58,11 @@
App& operator=(const App&&) = delete;
template <typename Adaptor>
- void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor)
+ void handleUpgrade(const Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ Adaptor&& adaptor)
{
- router.handleUpgrade(req, res, std::forward<Adaptor>(adaptor));
+ router.handleUpgrade(req, asyncResp, std::forward<Adaptor>(adaptor));
}
void handle(Request& req,
diff --git a/http/http_connection.hpp b/http/http_connection.hpp
index c28cde3..d5d02e5 100644
--- a/http/http_connection.hpp
+++ b/http/http_connection.hpp
@@ -249,10 +249,21 @@
thisReq.getHeaderValue(boost::beast::http::field::upgrade),
"websocket"))
{
- handler->handleUpgrade(thisReq, res, std::move(adaptor));
- // delete lambda with self shared_ptr
- // to enable connection destruction
- asyncResp->res.setCompleteRequestHandler(nullptr);
+ asyncResp->res.setCompleteRequestHandler(
+ [self(shared_from_this())](crow::Response& thisRes) {
+ if (thisRes.result() != boost::beast::http::status::ok)
+ {
+ // When any error occurs before handle upgradation,
+ // the result in response will be set to respective
+ // error. By default the Result will be OK (200),
+ // which implies successful handle upgrade. Response
+ // needs to be sent over this connection only on
+ // failure.
+ self->completeRequest(thisRes);
+ return;
+ }
+ });
+ handler->handleUpgrade(thisReq, asyncResp, std::move(adaptor));
return;
}
std::string_view expected =
diff --git a/http/routing.hpp b/http/routing.hpp
index 5ebc11f..a85bd3a 100644
--- a/http/routing.hpp
+++ b/http/routing.hpp
@@ -55,19 +55,20 @@
virtual void handle(const Request& /*req*/,
const std::shared_ptr<bmcweb::AsyncResp>&,
const RoutingParams&) = 0;
- virtual void handleUpgrade(const Request& /*req*/, Response& res,
- boost::asio::ip::tcp::socket&& /*adaptor*/)
+ virtual void
+ handleUpgrade(const Request& /*req*/,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ boost::asio::ip::tcp::socket&& /*adaptor*/)
{
- res.result(boost::beast::http::status::not_found);
- res.end();
+ asyncResp->res.result(boost::beast::http::status::not_found);
}
#ifdef BMCWEB_ENABLE_SSL
virtual void handleUpgrade(
- const Request& /*req*/, Response& res,
+ const Request& /*req*/,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&& /*adaptor*/)
{
- res.result(boost::beast::http::status::not_found);
- res.end();
+ asyncResp->res.result(boost::beast::http::status::not_found);
}
#endif
@@ -345,7 +346,8 @@
asyncResp->res.result(boost::beast::http::status::not_found);
}
- void handleUpgrade(const Request& req, Response& /*res*/,
+ void handleUpgrade(const Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/,
boost::asio::ip::tcp::socket&& adaptor) override
{
BMCWEB_LOG_DEBUG << "Websocket handles upgrade";
@@ -358,7 +360,8 @@
myConnection->start();
}
#ifdef BMCWEB_ENABLE_SSL
- void handleUpgrade(const Request& req, Response& /*res*/,
+ void handleUpgrade(const Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& /*asyncResp*/,
boost::beast::ssl_stream<boost::asio::ip::tcp::socket>&&
adaptor) override
{
@@ -1239,13 +1242,14 @@
}
template <typename Adaptor>
- void handleUpgrade(const Request& req, Response& res, Adaptor&& adaptor)
+ void handleUpgrade(const Request& req,
+ const std::shared_ptr<bmcweb::AsyncResp>& asyncResp,
+ Adaptor&& adaptor)
{
std::optional<HttpVerb> verb = httpVerbFromBoost(req.method());
if (!verb || static_cast<size_t>(*verb) >= perMethods.size())
{
- res.result(boost::beast::http::status::not_found);
- res.end();
+ asyncResp->res.result(boost::beast::http::status::not_found);
return;
}
PerMethod& perMethod = perMethods[static_cast<size_t>(*verb)];
@@ -1259,8 +1263,7 @@
{
BMCWEB_LOG_DEBUG << "Cannot match rules "
<< req.url().encoded_path();
- res.result(boost::beast::http::status::not_found);
- res.end();
+ asyncResp->res.result(boost::beast::http::status::not_found);
return;
}
@@ -1277,8 +1280,7 @@
<< req.methodString() << "("
<< static_cast<uint32_t>(*verb) << ") / "
<< rules[ruleIndex]->getMethods();
- res.result(boost::beast::http::status::not_found);
- res.end();
+ asyncResp->res.result(boost::beast::http::status::not_found);
return;
}
@@ -1289,14 +1291,14 @@
// any uncaught exceptions become 500s
try
{
- rules[ruleIndex]->handleUpgrade(req, res,
+ rules[ruleIndex]->handleUpgrade(req, asyncResp,
std::forward<Adaptor>(adaptor));
}
catch (const std::exception& e)
{
BMCWEB_LOG_ERROR << "An uncaught exception occurred: " << e.what();
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
return;
}
catch (...)
@@ -1304,8 +1306,8 @@
BMCWEB_LOG_ERROR
<< "An uncaught exception occurred. The type was unknown "
"so no information was available.";
- res.result(boost::beast::http::status::internal_server_error);
- res.end();
+ asyncResp->res.result(
+ boost::beast::http::status::internal_server_error);
return;
}
}