xref: /openbmc/bmcweb/http/http_client.hpp (revision 84b35604)
1bd030d0aSAppaRao Puli /*
2bd030d0aSAppaRao Puli // Copyright (c) 2020 Intel Corporation
3bd030d0aSAppaRao Puli //
4bd030d0aSAppaRao Puli // Licensed under the Apache License, Version 2.0 (the "License");
5bd030d0aSAppaRao Puli // you may not use this file except in compliance with the License.
6bd030d0aSAppaRao Puli // You may obtain a copy of the License at
7bd030d0aSAppaRao Puli //
8bd030d0aSAppaRao Puli //      http://www.apache.org/licenses/LICENSE-2.0
9bd030d0aSAppaRao Puli //
10bd030d0aSAppaRao Puli // Unless required by applicable law or agreed to in writing, software
11bd030d0aSAppaRao Puli // distributed under the License is distributed on an "AS IS" BASIS,
12bd030d0aSAppaRao Puli // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bd030d0aSAppaRao Puli // See the License for the specific language governing permissions and
14bd030d0aSAppaRao Puli // limitations under the License.
15bd030d0aSAppaRao Puli */
16bd030d0aSAppaRao Puli #pragma once
1729a82b08SSunitha Harish #include <boost/asio/ip/address.hpp>
1829a82b08SSunitha Harish #include <boost/asio/ip/basic_endpoint.hpp>
19d43cd0caSEd Tanous #include <boost/asio/steady_timer.hpp>
20d43cd0caSEd Tanous #include <boost/beast/core/flat_buffer.hpp>
21d43cd0caSEd Tanous #include <boost/beast/core/tcp_stream.hpp>
22d43cd0caSEd Tanous #include <boost/beast/http/message.hpp>
23bd030d0aSAppaRao Puli #include <boost/beast/version.hpp>
2429a82b08SSunitha Harish #include <include/async_resolve.hpp>
251214b7e7SGunnar Mills 
26bd030d0aSAppaRao Puli #include <cstdlib>
27bd030d0aSAppaRao Puli #include <functional>
28bd030d0aSAppaRao Puli #include <iostream>
29bd030d0aSAppaRao Puli #include <memory>
302a5689a7SAppaRao Puli #include <queue>
31bd030d0aSAppaRao Puli #include <string>
32bd030d0aSAppaRao Puli 
33bd030d0aSAppaRao Puli namespace crow
34bd030d0aSAppaRao Puli {
35bd030d0aSAppaRao Puli 
362a5689a7SAppaRao Puli static constexpr uint8_t maxRequestQueueSize = 50;
377de9f811SSunitha Harish static constexpr unsigned int httpReadBodyLimit = 8192;
382a5689a7SAppaRao Puli 
39bd030d0aSAppaRao Puli enum class ConnState
40bd030d0aSAppaRao Puli {
412a5689a7SAppaRao Puli     initialized,
4229a82b08SSunitha Harish     resolveInProgress,
4329a82b08SSunitha Harish     resolveFailed,
442a5689a7SAppaRao Puli     connectInProgress,
452a5689a7SAppaRao Puli     connectFailed,
46bd030d0aSAppaRao Puli     connected,
472a5689a7SAppaRao Puli     sendInProgress,
482a5689a7SAppaRao Puli     sendFailed,
496eaa1d2fSSunitha Harish     recvInProgress,
502a5689a7SAppaRao Puli     recvFailed,
512a5689a7SAppaRao Puli     idle,
526eaa1d2fSSunitha Harish     closeInProgress,
53fe44eb0bSAyushi Smriti     closed,
546eaa1d2fSSunitha Harish     suspended,
556eaa1d2fSSunitha Harish     terminated,
566eaa1d2fSSunitha Harish     abortConnection,
576eaa1d2fSSunitha Harish     retry
58bd030d0aSAppaRao Puli };
59bd030d0aSAppaRao Puli 
60bd030d0aSAppaRao Puli class HttpClient : public std::enable_shared_from_this<HttpClient>
61bd030d0aSAppaRao Puli {
62bd030d0aSAppaRao Puli   private:
6329a82b08SSunitha Harish     crow::async_resolve::Resolver resolver;
64bd030d0aSAppaRao Puli     boost::beast::tcp_stream conn;
65fe44eb0bSAyushi Smriti     boost::asio::steady_timer timer;
667de9f811SSunitha Harish     boost::beast::flat_static_buffer<httpReadBodyLimit> buffer;
67bd030d0aSAppaRao Puli     boost::beast::http::request<boost::beast::http::string_body> req;
686eaa1d2fSSunitha Harish     std::optional<
696eaa1d2fSSunitha Harish         boost::beast::http::response_parser<boost::beast::http::string_body>>
706eaa1d2fSSunitha Harish         parser;
717de9f811SSunitha Harish     boost::circular_buffer_space_optimized<std::string> requestDataQueue{};
726eaa1d2fSSunitha Harish 
73*84b35604SEd Tanous     ConnState state = ConnState::initialized;
74*84b35604SEd Tanous 
75fe44eb0bSAyushi Smriti     std::string subId;
76bd030d0aSAppaRao Puli     std::string host;
77bd030d0aSAppaRao Puli     std::string port;
78*84b35604SEd Tanous     uint32_t retryCount = 0;
79*84b35604SEd Tanous     uint32_t maxRetryAttempts = 5;
80*84b35604SEd Tanous     uint32_t retryIntervalSecs = 0;
81*84b35604SEd Tanous     std::string retryPolicyAction = "TerminateAfterRetries";
82*84b35604SEd Tanous     bool runningTimer = false;
83bd030d0aSAppaRao Puli 
8429a82b08SSunitha Harish     void doResolve()
8529a82b08SSunitha Harish     {
8629a82b08SSunitha Harish         state = ConnState::resolveInProgress;
8729a82b08SSunitha Harish         BMCWEB_LOG_DEBUG << "Trying to resolve: " << host << ":" << port;
8829a82b08SSunitha Harish 
8929a82b08SSunitha Harish         auto respHandler =
9029a82b08SSunitha Harish             [self(shared_from_this())](
9129a82b08SSunitha Harish                 const boost::beast::error_code ec,
9229a82b08SSunitha Harish                 const std::vector<boost::asio::ip::tcp::endpoint>&
9329a82b08SSunitha Harish                     endpointList) {
946eaa1d2fSSunitha Harish                 if (ec || (endpointList.size() == 0))
9529a82b08SSunitha Harish                 {
9629a82b08SSunitha Harish                     BMCWEB_LOG_ERROR << "Resolve failed: " << ec.message();
9729a82b08SSunitha Harish                     self->state = ConnState::resolveFailed;
986eaa1d2fSSunitha Harish                     self->handleConnState();
9929a82b08SSunitha Harish                     return;
10029a82b08SSunitha Harish                 }
10129a82b08SSunitha Harish                 BMCWEB_LOG_DEBUG << "Resolved";
10229a82b08SSunitha Harish                 self->doConnect(endpointList);
10329a82b08SSunitha Harish             };
10429a82b08SSunitha Harish         resolver.asyncResolve(host, port, std::move(respHandler));
10529a82b08SSunitha Harish     }
10629a82b08SSunitha Harish 
10729a82b08SSunitha Harish     void doConnect(
10829a82b08SSunitha Harish         const std::vector<boost::asio::ip::tcp::endpoint>& endpointList)
109bd030d0aSAppaRao Puli     {
1102a5689a7SAppaRao Puli         state = ConnState::connectInProgress;
1112a5689a7SAppaRao Puli 
1122a5689a7SAppaRao Puli         BMCWEB_LOG_DEBUG << "Trying to connect to: " << host << ":" << port;
113b00dcc27SEd Tanous 
11429a82b08SSunitha Harish         conn.expires_after(std::chrono::seconds(30));
11529a82b08SSunitha Harish         conn.async_connect(
11629a82b08SSunitha Harish             endpointList, [self(shared_from_this())](
11729a82b08SSunitha Harish                               const boost::beast::error_code ec,
11829a82b08SSunitha Harish                               const boost::asio::ip::tcp::endpoint& endpoint) {
1192a5689a7SAppaRao Puli                 if (ec)
1202a5689a7SAppaRao Puli                 {
12129a82b08SSunitha Harish                     BMCWEB_LOG_ERROR << "Connect " << endpoint
1222a5689a7SAppaRao Puli                                      << " failed: " << ec.message();
1232a5689a7SAppaRao Puli                     self->state = ConnState::connectFailed;
1246eaa1d2fSSunitha Harish                     self->handleConnState();
1252a5689a7SAppaRao Puli                     return;
1262a5689a7SAppaRao Puli                 }
12729a82b08SSunitha Harish                 BMCWEB_LOG_DEBUG << "Connected to: " << endpoint;
1286eaa1d2fSSunitha Harish                 self->state = ConnState::connected;
1296eaa1d2fSSunitha Harish                 self->handleConnState();
1302a5689a7SAppaRao Puli             });
1312a5689a7SAppaRao Puli     }
1322a5689a7SAppaRao Puli 
1332a5689a7SAppaRao Puli     void sendMessage(const std::string& data)
1342a5689a7SAppaRao Puli     {
1352a5689a7SAppaRao Puli         state = ConnState::sendInProgress;
1362a5689a7SAppaRao Puli 
1372a5689a7SAppaRao Puli         req.body() = data;
1382a5689a7SAppaRao Puli         req.prepare_payload();
139bd030d0aSAppaRao Puli 
140bd030d0aSAppaRao Puli         // Set a timeout on the operation
141bd030d0aSAppaRao Puli         conn.expires_after(std::chrono::seconds(30));
142bd030d0aSAppaRao Puli 
143bd030d0aSAppaRao Puli         // Send the HTTP request to the remote host
144bd030d0aSAppaRao Puli         boost::beast::http::async_write(
145bd030d0aSAppaRao Puli             conn, req,
1462a5689a7SAppaRao Puli             [self(shared_from_this())](const boost::beast::error_code& ec,
147bd030d0aSAppaRao Puli                                        const std::size_t& bytesTransferred) {
148bd030d0aSAppaRao Puli                 if (ec)
149bd030d0aSAppaRao Puli                 {
150bd030d0aSAppaRao Puli                     BMCWEB_LOG_ERROR << "sendMessage() failed: "
151bd030d0aSAppaRao Puli                                      << ec.message();
1522a5689a7SAppaRao Puli                     self->state = ConnState::sendFailed;
1536eaa1d2fSSunitha Harish                     self->handleConnState();
154bd030d0aSAppaRao Puli                     return;
155bd030d0aSAppaRao Puli                 }
156bd030d0aSAppaRao Puli                 BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: "
157bd030d0aSAppaRao Puli                                  << bytesTransferred;
158bd030d0aSAppaRao Puli                 boost::ignore_unused(bytesTransferred);
159bd030d0aSAppaRao Puli 
1602a5689a7SAppaRao Puli                 self->recvMessage();
161bd030d0aSAppaRao Puli             });
162bd030d0aSAppaRao Puli     }
163bd030d0aSAppaRao Puli 
164bd030d0aSAppaRao Puli     void recvMessage()
165bd030d0aSAppaRao Puli     {
1666eaa1d2fSSunitha Harish         state = ConnState::recvInProgress;
1676eaa1d2fSSunitha Harish 
1686eaa1d2fSSunitha Harish         parser.emplace(std::piecewise_construct, std::make_tuple());
1696eaa1d2fSSunitha Harish         parser->body_limit(httpReadBodyLimit);
1706eaa1d2fSSunitha Harish 
1716eaa1d2fSSunitha Harish         // Check only for the response header
1726eaa1d2fSSunitha Harish         parser->skip(true);
1736eaa1d2fSSunitha Harish 
174bd030d0aSAppaRao Puli         // Receive the HTTP response
175bd030d0aSAppaRao Puli         boost::beast::http::async_read(
1766eaa1d2fSSunitha Harish             conn, buffer, *parser,
1772a5689a7SAppaRao Puli             [self(shared_from_this())](const boost::beast::error_code& ec,
178bd030d0aSAppaRao Puli                                        const std::size_t& bytesTransferred) {
179bd030d0aSAppaRao Puli                 if (ec)
180bd030d0aSAppaRao Puli                 {
181bd030d0aSAppaRao Puli                     BMCWEB_LOG_ERROR << "recvMessage() failed: "
182bd030d0aSAppaRao Puli                                      << ec.message();
1832a5689a7SAppaRao Puli                     self->state = ConnState::recvFailed;
1846eaa1d2fSSunitha Harish                     self->handleConnState();
185bd030d0aSAppaRao Puli                     return;
186bd030d0aSAppaRao Puli                 }
187bd030d0aSAppaRao Puli                 BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: "
188bd030d0aSAppaRao Puli                                  << bytesTransferred;
1896eaa1d2fSSunitha Harish                 BMCWEB_LOG_DEBUG << "recvMessage() data: "
1906eaa1d2fSSunitha Harish                                  << self->parser->get();
191bd030d0aSAppaRao Puli 
1926eaa1d2fSSunitha Harish                 unsigned int respCode = self->parser->get().result_int();
1936eaa1d2fSSunitha Harish                 BMCWEB_LOG_DEBUG << "recvMessage() Header Response Code: "
1946eaa1d2fSSunitha Harish                                  << respCode;
1956eaa1d2fSSunitha Harish 
1966eaa1d2fSSunitha Harish                 // 2XX response is considered to be successful
1976eaa1d2fSSunitha Harish                 if ((respCode < 200) || (respCode >= 300))
1986eaa1d2fSSunitha Harish                 {
1996eaa1d2fSSunitha Harish                     // The listener failed to receive the Sent-Event
2006eaa1d2fSSunitha Harish                     BMCWEB_LOG_ERROR << "recvMessage() Listener Failed to "
2016eaa1d2fSSunitha Harish                                         "receive Sent-Event";
2026eaa1d2fSSunitha Harish                     self->state = ConnState::recvFailed;
2036eaa1d2fSSunitha Harish                     self->handleConnState();
2046eaa1d2fSSunitha Harish                     return;
2056eaa1d2fSSunitha Harish                 }
206bd030d0aSAppaRao Puli 
2072a5689a7SAppaRao Puli                 // Send is successful, Lets remove data from queue
2082a5689a7SAppaRao Puli                 // check for next request data in queue.
2097de9f811SSunitha Harish                 if (!self->requestDataQueue.empty())
2107de9f811SSunitha Harish                 {
2117de9f811SSunitha Harish                     self->requestDataQueue.pop_front();
2127de9f811SSunitha Harish                 }
2132a5689a7SAppaRao Puli                 self->state = ConnState::idle;
2146eaa1d2fSSunitha Harish 
2156eaa1d2fSSunitha Harish                 // Keep the connection alive if server supports it
2166eaa1d2fSSunitha Harish                 // Else close the connection
2176eaa1d2fSSunitha Harish                 BMCWEB_LOG_DEBUG << "recvMessage() keepalive : "
2186eaa1d2fSSunitha Harish                                  << self->parser->keep_alive();
2196eaa1d2fSSunitha Harish                 if (!self->parser->keep_alive())
2206eaa1d2fSSunitha Harish                 {
2216eaa1d2fSSunitha Harish                     // Abort the connection since server is not keep-alive
2226eaa1d2fSSunitha Harish                     // enabled
2236eaa1d2fSSunitha Harish                     self->state = ConnState::abortConnection;
2246eaa1d2fSSunitha Harish                 }
2256eaa1d2fSSunitha Harish 
2266eaa1d2fSSunitha Harish                 self->handleConnState();
227bd030d0aSAppaRao Puli             });
228bd030d0aSAppaRao Puli     }
229bd030d0aSAppaRao Puli 
230bd030d0aSAppaRao Puli     void doClose()
231bd030d0aSAppaRao Puli     {
2326eaa1d2fSSunitha Harish         state = ConnState::closeInProgress;
233bd030d0aSAppaRao Puli         boost::beast::error_code ec;
234bd030d0aSAppaRao Puli         conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
2356eaa1d2fSSunitha Harish         conn.close();
236bd030d0aSAppaRao Puli 
237bd030d0aSAppaRao Puli         // not_connected happens sometimes so don't bother reporting it.
238bd030d0aSAppaRao Puli         if (ec && ec != boost::beast::errc::not_connected)
239bd030d0aSAppaRao Puli         {
240bd030d0aSAppaRao Puli             BMCWEB_LOG_ERROR << "shutdown failed: " << ec.message();
241bd030d0aSAppaRao Puli             return;
242bd030d0aSAppaRao Puli         }
243bd030d0aSAppaRao Puli         BMCWEB_LOG_DEBUG << "Connection closed gracefully";
2446eaa1d2fSSunitha Harish         if ((state != ConnState::suspended) && (state != ConnState::terminated))
2456eaa1d2fSSunitha Harish         {
2466eaa1d2fSSunitha Harish             state = ConnState::closed;
2476eaa1d2fSSunitha Harish             handleConnState();
2486eaa1d2fSSunitha Harish         }
249bd030d0aSAppaRao Puli     }
250bd030d0aSAppaRao Puli 
2516eaa1d2fSSunitha Harish     void waitAndRetry()
252bd030d0aSAppaRao Puli     {
2532a5689a7SAppaRao Puli         if (retryCount >= maxRetryAttempts)
2542a5689a7SAppaRao Puli         {
2556eaa1d2fSSunitha Harish             BMCWEB_LOG_ERROR << "Maximum number of retries reached.";
2562a5689a7SAppaRao Puli 
2572a5689a7SAppaRao Puli             // Clear queue.
2582a5689a7SAppaRao Puli             while (!requestDataQueue.empty())
2592a5689a7SAppaRao Puli             {
2607de9f811SSunitha Harish                 requestDataQueue.pop_front();
2612a5689a7SAppaRao Puli             }
2622a5689a7SAppaRao Puli 
2636eaa1d2fSSunitha Harish             BMCWEB_LOG_DEBUG << "Retry policy: " << retryPolicyAction;
264fe44eb0bSAyushi Smriti             if (retryPolicyAction == "TerminateAfterRetries")
265fe44eb0bSAyushi Smriti             {
266fe44eb0bSAyushi Smriti                 // TODO: delete subscription
267fe44eb0bSAyushi Smriti                 state = ConnState::terminated;
268fe44eb0bSAyushi Smriti             }
2693174e4dfSEd Tanous             if (retryPolicyAction == "SuspendRetries")
270fe44eb0bSAyushi Smriti             {
2712a5689a7SAppaRao Puli                 state = ConnState::suspended;
2722a5689a7SAppaRao Puli             }
2736eaa1d2fSSunitha Harish             // Reset the retrycount to zero so that client can try connecting
2746eaa1d2fSSunitha Harish             // again if needed
275fe44eb0bSAyushi Smriti             retryCount = 0;
2766eaa1d2fSSunitha Harish             handleConnState();
2772a5689a7SAppaRao Puli             return;
2782a5689a7SAppaRao Puli         }
2792a5689a7SAppaRao Puli 
280fe44eb0bSAyushi Smriti         if (runningTimer)
281fe44eb0bSAyushi Smriti         {
282fe44eb0bSAyushi Smriti             BMCWEB_LOG_DEBUG << "Retry timer is already running.";
283fe44eb0bSAyushi Smriti             return;
284fe44eb0bSAyushi Smriti         }
285fe44eb0bSAyushi Smriti         runningTimer = true;
286fe44eb0bSAyushi Smriti 
2872a5689a7SAppaRao Puli         retryCount++;
288fe44eb0bSAyushi Smriti 
289fe44eb0bSAyushi Smriti         BMCWEB_LOG_DEBUG << "Attempt retry after " << retryIntervalSecs
290fe44eb0bSAyushi Smriti                          << " seconds. RetryCount = " << retryCount;
291fe44eb0bSAyushi Smriti         timer.expires_after(std::chrono::seconds(retryIntervalSecs));
292cb13a392SEd Tanous         timer.async_wait(
2936eaa1d2fSSunitha Harish             [self = shared_from_this()](const boost::system::error_code ec) {
2946eaa1d2fSSunitha Harish                 if (ec == boost::asio::error::operation_aborted)
2956eaa1d2fSSunitha Harish                 {
2966eaa1d2fSSunitha Harish                     BMCWEB_LOG_DEBUG
2976eaa1d2fSSunitha Harish                         << "async_wait failed since the operation is aborted"
2986eaa1d2fSSunitha Harish                         << ec.message();
2996eaa1d2fSSunitha Harish                 }
3006eaa1d2fSSunitha Harish                 else if (ec)
3016eaa1d2fSSunitha Harish                 {
3026eaa1d2fSSunitha Harish                     BMCWEB_LOG_ERROR << "async_wait failed: " << ec.message();
3036eaa1d2fSSunitha Harish                     // Ignore the error and continue the retry loop to attempt
3046eaa1d2fSSunitha Harish                     // sending the event as per the retry policy
3056eaa1d2fSSunitha Harish                 }
306fe44eb0bSAyushi Smriti                 self->runningTimer = false;
3076eaa1d2fSSunitha Harish 
3086eaa1d2fSSunitha Harish                 // Lets close connection and start from resolve.
3096eaa1d2fSSunitha Harish                 self->doClose();
310fe44eb0bSAyushi Smriti             });
311fe44eb0bSAyushi Smriti         return;
3122a5689a7SAppaRao Puli     }
3132a5689a7SAppaRao Puli 
3146eaa1d2fSSunitha Harish     void handleConnState()
315fe44eb0bSAyushi Smriti     {
3162a5689a7SAppaRao Puli         switch (state)
3172a5689a7SAppaRao Puli         {
31829a82b08SSunitha Harish             case ConnState::resolveInProgress:
3192a5689a7SAppaRao Puli             case ConnState::connectInProgress:
3202a5689a7SAppaRao Puli             case ConnState::sendInProgress:
3216eaa1d2fSSunitha Harish             case ConnState::recvInProgress:
3226eaa1d2fSSunitha Harish             case ConnState::closeInProgress:
3236eaa1d2fSSunitha Harish             {
3246eaa1d2fSSunitha Harish                 BMCWEB_LOG_DEBUG << "Async operation is already in progress";
3252a5689a7SAppaRao Puli                 break;
3266eaa1d2fSSunitha Harish             }
3272a5689a7SAppaRao Puli             case ConnState::initialized:
3282a5689a7SAppaRao Puli             case ConnState::closed:
3296eaa1d2fSSunitha Harish             {
3306eaa1d2fSSunitha Harish                 if (requestDataQueue.empty())
3316eaa1d2fSSunitha Harish                 {
3326eaa1d2fSSunitha Harish                     BMCWEB_LOG_DEBUG << "requestDataQueue is empty";
3336eaa1d2fSSunitha Harish                     return;
3346eaa1d2fSSunitha Harish                 }
3356eaa1d2fSSunitha Harish                 doResolve();
3366eaa1d2fSSunitha Harish                 break;
3376eaa1d2fSSunitha Harish             }
3386eaa1d2fSSunitha Harish             case ConnState::suspended:
3396eaa1d2fSSunitha Harish             case ConnState::terminated:
3406eaa1d2fSSunitha Harish             {
3416eaa1d2fSSunitha Harish                 doClose();
3426eaa1d2fSSunitha Harish                 break;
3436eaa1d2fSSunitha Harish             }
3446eaa1d2fSSunitha Harish             case ConnState::resolveFailed:
3452a5689a7SAppaRao Puli             case ConnState::connectFailed:
3462a5689a7SAppaRao Puli             case ConnState::sendFailed:
34792a74e56SAppaRao Puli             case ConnState::recvFailed:
3486eaa1d2fSSunitha Harish             case ConnState::retry:
34992a74e56SAppaRao Puli             {
3506eaa1d2fSSunitha Harish                 // In case of failures during connect and handshake
3516eaa1d2fSSunitha Harish                 // the retry policy will be applied
3526eaa1d2fSSunitha Harish                 waitAndRetry();
3532a5689a7SAppaRao Puli                 break;
3542a5689a7SAppaRao Puli             }
3552a5689a7SAppaRao Puli             case ConnState::connected:
35692a74e56SAppaRao Puli             case ConnState::idle:
35792a74e56SAppaRao Puli             {
3586eaa1d2fSSunitha Harish                 // State idle means, previous attempt is successful
3596eaa1d2fSSunitha Harish                 // State connected means, client connection is established
3606eaa1d2fSSunitha Harish                 // successfully
3616eaa1d2fSSunitha Harish                 if (requestDataQueue.empty())
3626eaa1d2fSSunitha Harish                 {
3636eaa1d2fSSunitha Harish                     BMCWEB_LOG_DEBUG << "requestDataQueue is empty";
3646eaa1d2fSSunitha Harish                     return;
3656eaa1d2fSSunitha Harish                 }
3662a5689a7SAppaRao Puli                 std::string data = requestDataQueue.front();
3672a5689a7SAppaRao Puli                 sendMessage(data);
3682a5689a7SAppaRao Puli                 break;
3692a5689a7SAppaRao Puli             }
3706eaa1d2fSSunitha Harish             case ConnState::abortConnection:
3716eaa1d2fSSunitha Harish             {
3726eaa1d2fSSunitha Harish                 // Server did not want to keep alive the session
3736eaa1d2fSSunitha Harish                 doClose();
3746eaa1d2fSSunitha Harish                 break;
3756eaa1d2fSSunitha Harish             }
3766eaa1d2fSSunitha Harish             default:
3776eaa1d2fSSunitha Harish                 break;
3782a5689a7SAppaRao Puli         }
379bd030d0aSAppaRao Puli     }
380bd030d0aSAppaRao Puli 
381bd030d0aSAppaRao Puli   public:
382fe44eb0bSAyushi Smriti     explicit HttpClient(boost::asio::io_context& ioc, const std::string& id,
383fe44eb0bSAyushi Smriti                         const std::string& destIP, const std::string& destPort,
3844da04455SEd Tanous                         const std::string& destUri,
3854da04455SEd Tanous                         const boost::beast::http::fields& httpHeader) :
386bd030d0aSAppaRao Puli         conn(ioc),
3874da04455SEd Tanous         timer(ioc),
3884da04455SEd Tanous         req(boost::beast::http::verb::post, destUri, 11, "", httpHeader),
389*84b35604SEd Tanous         subId(id), host(destIP), port(destPort)
390bd030d0aSAppaRao Puli     {
3914da04455SEd Tanous         req.set(boost::beast::http::field::host, host);
3924da04455SEd Tanous         req.keep_alive(true);
393bd030d0aSAppaRao Puli     }
394bd030d0aSAppaRao Puli 
3952a5689a7SAppaRao Puli     void sendData(const std::string& data)
396bd030d0aSAppaRao Puli     {
3976eaa1d2fSSunitha Harish         if ((state == ConnState::suspended) || (state == ConnState::terminated))
398bd030d0aSAppaRao Puli         {
399bd030d0aSAppaRao Puli             return;
400bd030d0aSAppaRao Puli         }
401bd030d0aSAppaRao Puli 
4022a5689a7SAppaRao Puli         if (requestDataQueue.size() <= maxRequestQueueSize)
4032a5689a7SAppaRao Puli         {
4047de9f811SSunitha Harish             requestDataQueue.push_back(data);
4056eaa1d2fSSunitha Harish             handleConnState();
4062a5689a7SAppaRao Puli         }
4072a5689a7SAppaRao Puli         else
4082a5689a7SAppaRao Puli         {
4092a5689a7SAppaRao Puli             BMCWEB_LOG_ERROR << "Request queue is full. So ignoring data.";
4102a5689a7SAppaRao Puli         }
4112a5689a7SAppaRao Puli 
4122a5689a7SAppaRao Puli         return;
413bd030d0aSAppaRao Puli     }
414bd030d0aSAppaRao Puli 
415fe44eb0bSAyushi Smriti     void setRetryConfig(const uint32_t retryAttempts,
416fe44eb0bSAyushi Smriti                         const uint32_t retryTimeoutInterval)
417fe44eb0bSAyushi Smriti     {
418fe44eb0bSAyushi Smriti         maxRetryAttempts = retryAttempts;
419fe44eb0bSAyushi Smriti         retryIntervalSecs = retryTimeoutInterval;
420fe44eb0bSAyushi Smriti     }
421fe44eb0bSAyushi Smriti 
422fe44eb0bSAyushi Smriti     void setRetryPolicy(const std::string& retryPolicy)
423fe44eb0bSAyushi Smriti     {
424fe44eb0bSAyushi Smriti         retryPolicyAction = retryPolicy;
425fe44eb0bSAyushi Smriti     }
426bd030d0aSAppaRao Puli };
427bd030d0aSAppaRao Puli 
428bd030d0aSAppaRao Puli } // namespace crow
429