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)