bmcweb: Remove hardcoded HTTP verbs and headers
Modifies HttpClient so that the HTTP verb and headers can be set
for each individual message sent. Right now those fields are set
when a connection is first created and then reused by each
message sent using that connection.
Tested:
Launched two Event Listener servers that created 6 and 2
subscriptions. Sending a test event resulted in the servers
receiving 6 requests and 2 requests, respectively.
Change-Id: I8d7e2d54385bc2c403498293820adb584bff8b57
Signed-off-by: Carson Labrado <clabrado@google.com>
Signed-off-by: Ed Tanous <edtanous@google.com>
diff --git a/http/http_client.hpp b/http/http_client.hpp
index a672447..a6e1669 100644
--- a/http/http_client.hpp
+++ b/http/http_client.hpp
@@ -72,14 +72,14 @@
struct PendingRequest
{
- std::string requestData;
+ boost::beast::http::request<boost::beast::http::string_body> req;
std::function<void(bool, uint32_t, Response&)> callback;
RetryPolicyData retryPolicy;
PendingRequest(
- const std::string& requestData,
+ boost::beast::http::request<boost::beast::http::string_body>&& req,
const std::function<void(bool, uint32_t, Response&)>& callback,
const RetryPolicyData& retryPolicy) :
- requestData(requestData),
+ req(std::move(req)),
callback(callback), retryPolicy(retryPolicy)
{}
};
@@ -100,7 +100,6 @@
RetryPolicyData retryPolicy;
// Data buffers
- std::string data;
boost::beast::http::request<boost::beast::http::string_body> req;
std::optional<
boost::beast::http::response_parser<boost::beast::http::string_body>>
@@ -182,9 +181,6 @@
{
state = ConnState::sendInProgress;
- req.body() = data;
- req.prepare_payload();
-
// Set a timeout on the operation
conn.expires_after(std::chrono::seconds(30));
@@ -387,17 +383,10 @@
public:
explicit ConnectionInfo(boost::asio::io_context& ioc, const std::string& id,
const std::string& destIP, const uint16_t destPort,
- const std::string& destUri,
- const boost::beast::http::fields& httpHeader,
const unsigned int connId) :
subId(id),
- host(destIP), port(destPort), connId(connId),
- req(boost::beast::http::verb::post, destUri, 11, "", httpHeader),
- conn(ioc), timer(ioc)
- {
- req.set(boost::beast::http::field::host, host);
- req.keep_alive(true);
- }
+ host(destIP), port(destPort), connId(connId), conn(ioc), timer(ioc)
+ {}
};
class ConnectionPool : public std::enable_shared_from_this<ConnectionPool>
@@ -407,15 +396,13 @@
const std::string id;
const std::string destIP;
const uint16_t destPort;
- const std::string destUri;
- const boost::beast::http::fields httpHeader;
std::vector<std::shared_ptr<ConnectionInfo>> connections;
boost::container::devector<PendingRequest> requestQueue;
friend class HttpClient;
- // Configure a connections's data, callback, and retry info in preparation
- // to begin sending a request
+ // Configure a connections's request, callback, and retry info in
+ // preparation to begin sending the request
void setConnProps(ConnectionInfo& conn)
{
if (requestQueue.empty())
@@ -425,10 +412,10 @@
return;
}
- auto req = requestQueue.front();
- conn.retryPolicy = std::move(req.retryPolicy);
- conn.data = std::move(req.requestData);
- conn.callback = std::move(req.callback);
+ auto nextReq = requestQueue.front();
+ conn.retryPolicy = std::move(nextReq.retryPolicy);
+ conn.req = std::move(nextReq.req);
+ conn.callback = std::move(nextReq.callback);
BMCWEB_LOG_DEBUG << "Setting properties for connection " << conn.host
<< ":" << std::to_string(conn.port)
@@ -496,7 +483,10 @@
}
}
- void sendData(std::string& data, const RetryPolicyData& retryPolicy,
+ void sendData(std::string& data, const std::string& destUri,
+ const boost::beast::http::fields& httpHeader,
+ const boost::beast::http::verb verb,
+ const RetryPolicyData& retryPolicy,
std::function<void(Response&)>& resHandler)
{
std::weak_ptr<ConnectionPool> weakSelf = weak_from_this();
@@ -520,6 +510,14 @@
self->sendNext(keepAlive, connId);
};
+ // Construct the request to be sent
+ boost::beast::http::request<boost::beast::http::string_body> thisReq(
+ verb, destUri, 11, "", httpHeader);
+ thisReq.set(boost::beast::http::field::host, destIP);
+ thisReq.keep_alive(true);
+ thisReq.body() = std::move(data);
+ thisReq.prepare_payload();
+
// Reuse an existing connection if one is available
for (unsigned int i = 0; i < connections.size(); i++)
{
@@ -528,9 +526,8 @@
(conn->state == ConnState::initialized) ||
(conn->state == ConnState::closed))
{
- conn->data = std::move(data);
+ conn->req = std::move(thisReq);
conn->callback = std::move(cb);
- conn->retryPolicy = retryPolicy;
setConnRetryPolicy(*conn, retryPolicy);
std::string commonMsg = std::to_string(i) + " from pool " +
destIP + ":" + std::to_string(destPort);
@@ -558,7 +555,7 @@
BMCWEB_LOG_DEBUG << "Adding new connection to pool " << destIP
<< ":" << std::to_string(destPort);
auto conn = addConnection();
- conn->data = std::move(data);
+ conn->req = std::move(thisReq);
conn->callback = std::move(cb);
setConnRetryPolicy(*conn, retryPolicy);
conn->doResolve();
@@ -566,7 +563,7 @@
else if (requestQueue.size() < maxRequestQueueSize)
{
BMCWEB_LOG_ERROR << "Max pool size reached. Adding data to queue.";
- requestQueue.emplace_back(std::move(data), std::move(cb),
+ requestQueue.emplace_back(std::move(thisReq), std::move(cb),
retryPolicy);
}
else
@@ -580,8 +577,8 @@
{
unsigned int newId = static_cast<unsigned int>(connections.size());
- auto& ret = connections.emplace_back(std::make_shared<ConnectionInfo>(
- ioc, id, destIP, destPort, destUri, httpHeader, newId));
+ auto& ret = connections.emplace_back(
+ std::make_shared<ConnectionInfo>(ioc, id, destIP, destPort, newId));
BMCWEB_LOG_DEBUG << "Added connection "
<< std::to_string(connections.size() - 1)
@@ -593,12 +590,10 @@
public:
explicit ConnectionPool(boost::asio::io_context& ioc, const std::string& id,
- const std::string& destIP, const uint16_t destPort,
- const std::string& destUri,
- const boost::beast::http::fields& httpHeader) :
+ const std::string& destIP,
+ const uint16_t destPort) :
ioc(ioc),
- id(id), destIP(destIP), destPort(destPort), destUri(destUri),
- httpHeader(httpHeader)
+ id(id), destIP(destIP), destPort(destPort)
{
std::string clientKey = destIP + ":" + std::to_string(destPort);
BMCWEB_LOG_DEBUG << "Initializing connection pool for " << destIP << ":"
@@ -646,11 +641,12 @@
const std::string& destIP, const uint16_t destPort,
const std::string& destUri,
const boost::beast::http::fields& httpHeader,
- std::string& retryPolicyName)
+ const boost::beast::http::verb verb,
+ const std::string& retryPolicyName)
{
std::function<void(Response&)> cb = genericResHandler;
sendDataWithCallback(data, id, destIP, destPort, destUri, httpHeader,
- retryPolicyName, cb);
+ verb, retryPolicyName, cb);
}
// Send request to destIP:destPort and use the provided callback to
@@ -660,7 +656,8 @@
const uint16_t destPort,
const std::string& destUri,
const boost::beast::http::fields& httpHeader,
- std::string& retryPolicyName,
+ const boost::beast::http::verb verb,
+ const std::string& retryPolicyName,
std::function<void(Response&)>& resHandler)
{
std::string clientKey = destIP + ":" + std::to_string(destPort);
@@ -670,8 +667,8 @@
{
// Now actually create the ConnectionPool shared_ptr since it does
// not already exist
- result.first->second = std::make_shared<ConnectionPool>(
- ioc, id, destIP, destPort, destUri, httpHeader);
+ result.first->second =
+ std::make_shared<ConnectionPool>(ioc, id, destIP, destPort);
BMCWEB_LOG_DEBUG << "Created connection pool for " << clientKey;
}
else
@@ -691,7 +688,8 @@
// Send the data using either the existing connection pool or the newly
// created connection pool
- result.first->second->sendData(data, policy.first->second, resHandler);
+ result.first->second->sendData(data, destUri, httpHeader, verb,
+ policy.first->second, resHandler);
}
void setRetryConfig(const uint32_t retryAttempts,
diff --git a/redfish-core/include/event_service_manager.hpp b/redfish-core/include/event_service_manager.hpp
index 4e50e4b..52db9fb 100644
--- a/redfish-core/include/event_service_manager.hpp
+++ b/redfish-core/include/event_service_manager.hpp
@@ -392,8 +392,9 @@
}
// A connection pool will be created if one does not already exist
- crow::HttpClient::getInstance().sendData(msg, id, host, port, path,
- httpHeaders, retryPolicyName);
+ crow::HttpClient::getInstance().sendData(
+ msg, id, host, port, path, httpHeaders,
+ boost::beast::http::verb::post, retryPolicyName);
eventSeqNum++;
if (sseConn != nullptr)