xref: /openbmc/bmcweb/http/http_client.hpp (revision 26f6976f)
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>
245dfb5b2dSEd Tanous #include <boost/circular_buffer.hpp>
2529a82b08SSunitha Harish #include <include/async_resolve.hpp>
261214b7e7SGunnar Mills 
27bd030d0aSAppaRao Puli #include <cstdlib>
28bd030d0aSAppaRao Puli #include <functional>
29bd030d0aSAppaRao Puli #include <iostream>
30bd030d0aSAppaRao Puli #include <memory>
312a5689a7SAppaRao Puli #include <queue>
32bd030d0aSAppaRao Puli #include <string>
33bd030d0aSAppaRao Puli 
34bd030d0aSAppaRao Puli namespace crow
35bd030d0aSAppaRao Puli {
36bd030d0aSAppaRao Puli 
372a5689a7SAppaRao Puli static constexpr uint8_t maxRequestQueueSize = 50;
387de9f811SSunitha Harish static constexpr unsigned int httpReadBodyLimit = 8192;
392a5689a7SAppaRao Puli 
40bd030d0aSAppaRao Puli enum class ConnState
41bd030d0aSAppaRao Puli {
422a5689a7SAppaRao Puli     initialized,
4329a82b08SSunitha Harish     resolveInProgress,
4429a82b08SSunitha Harish     resolveFailed,
452a5689a7SAppaRao Puli     connectInProgress,
462a5689a7SAppaRao Puli     connectFailed,
47bd030d0aSAppaRao Puli     connected,
482a5689a7SAppaRao Puli     sendInProgress,
492a5689a7SAppaRao Puli     sendFailed,
506eaa1d2fSSunitha Harish     recvInProgress,
512a5689a7SAppaRao Puli     recvFailed,
522a5689a7SAppaRao Puli     idle,
536eaa1d2fSSunitha Harish     closeInProgress,
54fe44eb0bSAyushi Smriti     closed,
556eaa1d2fSSunitha Harish     suspended,
566eaa1d2fSSunitha Harish     terminated,
576eaa1d2fSSunitha Harish     abortConnection,
586eaa1d2fSSunitha Harish     retry
59bd030d0aSAppaRao Puli };
60bd030d0aSAppaRao Puli 
61bd030d0aSAppaRao Puli class HttpClient : public std::enable_shared_from_this<HttpClient>
62bd030d0aSAppaRao Puli {
63bd030d0aSAppaRao Puli   private:
6429a82b08SSunitha Harish     crow::async_resolve::Resolver resolver;
65bd030d0aSAppaRao Puli     boost::beast::tcp_stream conn;
66fe44eb0bSAyushi Smriti     boost::asio::steady_timer timer;
677de9f811SSunitha Harish     boost::beast::flat_static_buffer<httpReadBodyLimit> buffer;
68bd030d0aSAppaRao Puli     boost::beast::http::request<boost::beast::http::string_body> req;
696eaa1d2fSSunitha Harish     std::optional<
706eaa1d2fSSunitha Harish         boost::beast::http::response_parser<boost::beast::http::string_body>>
716eaa1d2fSSunitha Harish         parser;
72116c184bSKrzysztof Grobelny     boost::circular_buffer_space_optimized<std::string> requestDataQueue{
73116c184bSKrzysztof Grobelny         maxRequestQueueSize};
746eaa1d2fSSunitha Harish 
7584b35604SEd Tanous     ConnState state = ConnState::initialized;
7684b35604SEd Tanous 
77fe44eb0bSAyushi Smriti     std::string subId;
78bd030d0aSAppaRao Puli     std::string host;
79bd030d0aSAppaRao Puli     std::string port;
8084b35604SEd Tanous     uint32_t retryCount = 0;
8184b35604SEd Tanous     uint32_t maxRetryAttempts = 5;
8284b35604SEd Tanous     uint32_t retryIntervalSecs = 0;
8384b35604SEd Tanous     std::string retryPolicyAction = "TerminateAfterRetries";
8484b35604SEd Tanous     bool runningTimer = false;
85bd030d0aSAppaRao Puli 
8629a82b08SSunitha Harish     void doResolve()
8729a82b08SSunitha Harish     {
8829a82b08SSunitha Harish         state = ConnState::resolveInProgress;
8929a82b08SSunitha Harish         BMCWEB_LOG_DEBUG << "Trying to resolve: " << host << ":" << port;
9029a82b08SSunitha Harish 
9129a82b08SSunitha Harish         auto respHandler =
9229a82b08SSunitha Harish             [self(shared_from_this())](
9329a82b08SSunitha Harish                 const boost::beast::error_code ec,
9429a82b08SSunitha Harish                 const std::vector<boost::asio::ip::tcp::endpoint>&
9529a82b08SSunitha Harish                     endpointList) {
96*26f6976fSEd Tanous                 if (ec || (endpointList.empty()))
9729a82b08SSunitha Harish                 {
9829a82b08SSunitha Harish                     BMCWEB_LOG_ERROR << "Resolve failed: " << ec.message();
9929a82b08SSunitha Harish                     self->state = ConnState::resolveFailed;
1006eaa1d2fSSunitha Harish                     self->handleConnState();
10129a82b08SSunitha Harish                     return;
10229a82b08SSunitha Harish                 }
10329a82b08SSunitha Harish                 BMCWEB_LOG_DEBUG << "Resolved";
10429a82b08SSunitha Harish                 self->doConnect(endpointList);
10529a82b08SSunitha Harish             };
10629a82b08SSunitha Harish         resolver.asyncResolve(host, port, std::move(respHandler));
10729a82b08SSunitha Harish     }
10829a82b08SSunitha Harish 
10929a82b08SSunitha Harish     void doConnect(
11029a82b08SSunitha Harish         const std::vector<boost::asio::ip::tcp::endpoint>& endpointList)
111bd030d0aSAppaRao Puli     {
1122a5689a7SAppaRao Puli         state = ConnState::connectInProgress;
1132a5689a7SAppaRao Puli 
1142a5689a7SAppaRao Puli         BMCWEB_LOG_DEBUG << "Trying to connect to: " << host << ":" << port;
115b00dcc27SEd Tanous 
11629a82b08SSunitha Harish         conn.expires_after(std::chrono::seconds(30));
11729a82b08SSunitha Harish         conn.async_connect(
11829a82b08SSunitha Harish             endpointList, [self(shared_from_this())](
11929a82b08SSunitha Harish                               const boost::beast::error_code ec,
12029a82b08SSunitha Harish                               const boost::asio::ip::tcp::endpoint& endpoint) {
1212a5689a7SAppaRao Puli                 if (ec)
1222a5689a7SAppaRao Puli                 {
12329a82b08SSunitha Harish                     BMCWEB_LOG_ERROR << "Connect " << endpoint
1242a5689a7SAppaRao Puli                                      << " failed: " << ec.message();
1252a5689a7SAppaRao Puli                     self->state = ConnState::connectFailed;
1266eaa1d2fSSunitha Harish                     self->handleConnState();
1272a5689a7SAppaRao Puli                     return;
1282a5689a7SAppaRao Puli                 }
12929a82b08SSunitha Harish                 BMCWEB_LOG_DEBUG << "Connected to: " << endpoint;
1306eaa1d2fSSunitha Harish                 self->state = ConnState::connected;
1316eaa1d2fSSunitha Harish                 self->handleConnState();
1322a5689a7SAppaRao Puli             });
1332a5689a7SAppaRao Puli     }
1342a5689a7SAppaRao Puli 
1352a5689a7SAppaRao Puli     void sendMessage(const std::string& data)
1362a5689a7SAppaRao Puli     {
1372a5689a7SAppaRao Puli         state = ConnState::sendInProgress;
1382a5689a7SAppaRao Puli 
1392a5689a7SAppaRao Puli         req.body() = data;
1402a5689a7SAppaRao Puli         req.prepare_payload();
141bd030d0aSAppaRao Puli 
142bd030d0aSAppaRao Puli         // Set a timeout on the operation
143bd030d0aSAppaRao Puli         conn.expires_after(std::chrono::seconds(30));
144bd030d0aSAppaRao Puli 
145bd030d0aSAppaRao Puli         // Send the HTTP request to the remote host
146bd030d0aSAppaRao Puli         boost::beast::http::async_write(
147bd030d0aSAppaRao Puli             conn, req,
1482a5689a7SAppaRao Puli             [self(shared_from_this())](const boost::beast::error_code& ec,
149bd030d0aSAppaRao Puli                                        const std::size_t& bytesTransferred) {
150bd030d0aSAppaRao Puli                 if (ec)
151bd030d0aSAppaRao Puli                 {
152bd030d0aSAppaRao Puli                     BMCWEB_LOG_ERROR << "sendMessage() failed: "
153bd030d0aSAppaRao Puli                                      << ec.message();
1542a5689a7SAppaRao Puli                     self->state = ConnState::sendFailed;
1556eaa1d2fSSunitha Harish                     self->handleConnState();
156bd030d0aSAppaRao Puli                     return;
157bd030d0aSAppaRao Puli                 }
158bd030d0aSAppaRao Puli                 BMCWEB_LOG_DEBUG << "sendMessage() bytes transferred: "
159bd030d0aSAppaRao Puli                                  << bytesTransferred;
160bd030d0aSAppaRao Puli                 boost::ignore_unused(bytesTransferred);
161bd030d0aSAppaRao Puli 
1622a5689a7SAppaRao Puli                 self->recvMessage();
163bd030d0aSAppaRao Puli             });
164bd030d0aSAppaRao Puli     }
165bd030d0aSAppaRao Puli 
166bd030d0aSAppaRao Puli     void recvMessage()
167bd030d0aSAppaRao Puli     {
1686eaa1d2fSSunitha Harish         state = ConnState::recvInProgress;
1696eaa1d2fSSunitha Harish 
1706eaa1d2fSSunitha Harish         parser.emplace(std::piecewise_construct, std::make_tuple());
1716eaa1d2fSSunitha Harish         parser->body_limit(httpReadBodyLimit);
1726eaa1d2fSSunitha Harish 
173bd030d0aSAppaRao Puli         // Receive the HTTP response
174bd030d0aSAppaRao Puli         boost::beast::http::async_read(
1756eaa1d2fSSunitha Harish             conn, buffer, *parser,
1762a5689a7SAppaRao Puli             [self(shared_from_this())](const boost::beast::error_code& ec,
177bd030d0aSAppaRao Puli                                        const std::size_t& bytesTransferred) {
178bd030d0aSAppaRao Puli                 if (ec)
179bd030d0aSAppaRao Puli                 {
180bd030d0aSAppaRao Puli                     BMCWEB_LOG_ERROR << "recvMessage() failed: "
181bd030d0aSAppaRao Puli                                      << ec.message();
1822a5689a7SAppaRao Puli                     self->state = ConnState::recvFailed;
1836eaa1d2fSSunitha Harish                     self->handleConnState();
184bd030d0aSAppaRao Puli                     return;
185bd030d0aSAppaRao Puli                 }
186bd030d0aSAppaRao Puli                 BMCWEB_LOG_DEBUG << "recvMessage() bytes transferred: "
187bd030d0aSAppaRao Puli                                  << bytesTransferred;
1886eaa1d2fSSunitha Harish                 BMCWEB_LOG_DEBUG << "recvMessage() data: "
1896eaa1d2fSSunitha Harish                                  << self->parser->get();
190bd030d0aSAppaRao Puli 
1916eaa1d2fSSunitha Harish                 unsigned int respCode = self->parser->get().result_int();
1926eaa1d2fSSunitha Harish                 BMCWEB_LOG_DEBUG << "recvMessage() Header Response Code: "
1936eaa1d2fSSunitha Harish                                  << respCode;
1946eaa1d2fSSunitha Harish 
1956eaa1d2fSSunitha Harish                 // 2XX response is considered to be successful
1966eaa1d2fSSunitha Harish                 if ((respCode < 200) || (respCode >= 300))
1976eaa1d2fSSunitha Harish                 {
1986eaa1d2fSSunitha Harish                     // The listener failed to receive the Sent-Event
1997adb85acSSunitha Harish                     BMCWEB_LOG_ERROR
2007adb85acSSunitha Harish                         << "recvMessage() Listener Failed to "
2017adb85acSSunitha Harish                            "receive Sent-Event. Header Response Code: "
2027adb85acSSunitha Harish                         << respCode;
2036eaa1d2fSSunitha Harish                     self->state = ConnState::recvFailed;
2046eaa1d2fSSunitha Harish                     self->handleConnState();
2056eaa1d2fSSunitha Harish                     return;
2066eaa1d2fSSunitha Harish                 }
207bd030d0aSAppaRao Puli 
2082a5689a7SAppaRao Puli                 // Send is successful, Lets remove data from queue
2092a5689a7SAppaRao Puli                 // check for next request data in queue.
2107de9f811SSunitha Harish                 if (!self->requestDataQueue.empty())
2117de9f811SSunitha Harish                 {
2127de9f811SSunitha Harish                     self->requestDataQueue.pop_front();
2137de9f811SSunitha Harish                 }
2142a5689a7SAppaRao Puli                 self->state = ConnState::idle;
2156eaa1d2fSSunitha Harish 
2166eaa1d2fSSunitha Harish                 // Keep the connection alive if server supports it
2176eaa1d2fSSunitha Harish                 // Else close the connection
2186eaa1d2fSSunitha Harish                 BMCWEB_LOG_DEBUG << "recvMessage() keepalive : "
2196eaa1d2fSSunitha Harish                                  << self->parser->keep_alive();
2206eaa1d2fSSunitha Harish                 if (!self->parser->keep_alive())
2216eaa1d2fSSunitha Harish                 {
2226eaa1d2fSSunitha Harish                     // Abort the connection since server is not keep-alive
2236eaa1d2fSSunitha Harish                     // enabled
2246eaa1d2fSSunitha Harish                     self->state = ConnState::abortConnection;
2256eaa1d2fSSunitha Harish                 }
2266eaa1d2fSSunitha Harish 
2276eaa1d2fSSunitha Harish                 self->handleConnState();
228bd030d0aSAppaRao Puli             });
229bd030d0aSAppaRao Puli     }
230bd030d0aSAppaRao Puli 
231bd030d0aSAppaRao Puli     void doClose()
232bd030d0aSAppaRao Puli     {
2336eaa1d2fSSunitha Harish         state = ConnState::closeInProgress;
234bd030d0aSAppaRao Puli         boost::beast::error_code ec;
235bd030d0aSAppaRao Puli         conn.socket().shutdown(boost::asio::ip::tcp::socket::shutdown_both, ec);
2366eaa1d2fSSunitha Harish         conn.close();
237bd030d0aSAppaRao Puli 
238bd030d0aSAppaRao Puli         // not_connected happens sometimes so don't bother reporting it.
239bd030d0aSAppaRao Puli         if (ec && ec != boost::beast::errc::not_connected)
240bd030d0aSAppaRao Puli         {
241bd030d0aSAppaRao Puli             BMCWEB_LOG_ERROR << "shutdown failed: " << ec.message();
242bd030d0aSAppaRao Puli             return;
243bd030d0aSAppaRao Puli         }
244bd030d0aSAppaRao Puli         BMCWEB_LOG_DEBUG << "Connection closed gracefully";
2456eaa1d2fSSunitha Harish         if ((state != ConnState::suspended) && (state != ConnState::terminated))
2466eaa1d2fSSunitha Harish         {
2476eaa1d2fSSunitha Harish             state = ConnState::closed;
2486eaa1d2fSSunitha Harish             handleConnState();
2496eaa1d2fSSunitha Harish         }
250bd030d0aSAppaRao Puli     }
251bd030d0aSAppaRao Puli 
2526eaa1d2fSSunitha Harish     void waitAndRetry()
253bd030d0aSAppaRao Puli     {
2542a5689a7SAppaRao Puli         if (retryCount >= maxRetryAttempts)
2552a5689a7SAppaRao Puli         {
2566eaa1d2fSSunitha Harish             BMCWEB_LOG_ERROR << "Maximum number of retries reached.";
2572a5689a7SAppaRao Puli 
2582a5689a7SAppaRao Puli             // Clear queue.
2592a5689a7SAppaRao Puli             while (!requestDataQueue.empty())
2602a5689a7SAppaRao Puli             {
2617de9f811SSunitha Harish                 requestDataQueue.pop_front();
2622a5689a7SAppaRao Puli             }
2632a5689a7SAppaRao Puli 
2646eaa1d2fSSunitha Harish             BMCWEB_LOG_DEBUG << "Retry policy: " << retryPolicyAction;
265fe44eb0bSAyushi Smriti             if (retryPolicyAction == "TerminateAfterRetries")
266fe44eb0bSAyushi Smriti             {
267fe44eb0bSAyushi Smriti                 // TODO: delete subscription
268fe44eb0bSAyushi Smriti                 state = ConnState::terminated;
269fe44eb0bSAyushi Smriti             }
2703174e4dfSEd Tanous             if (retryPolicyAction == "SuspendRetries")
271fe44eb0bSAyushi Smriti             {
2722a5689a7SAppaRao Puli                 state = ConnState::suspended;
2732a5689a7SAppaRao Puli             }
2746eaa1d2fSSunitha Harish             // Reset the retrycount to zero so that client can try connecting
2756eaa1d2fSSunitha Harish             // again if needed
276fe44eb0bSAyushi Smriti             retryCount = 0;
2776eaa1d2fSSunitha Harish             handleConnState();
2782a5689a7SAppaRao Puli             return;
2792a5689a7SAppaRao Puli         }
2802a5689a7SAppaRao Puli 
281fe44eb0bSAyushi Smriti         if (runningTimer)
282fe44eb0bSAyushi Smriti         {
283fe44eb0bSAyushi Smriti             BMCWEB_LOG_DEBUG << "Retry timer is already running.";
284fe44eb0bSAyushi Smriti             return;
285fe44eb0bSAyushi Smriti         }
286fe44eb0bSAyushi Smriti         runningTimer = true;
287fe44eb0bSAyushi Smriti 
2882a5689a7SAppaRao Puli         retryCount++;
289fe44eb0bSAyushi Smriti 
290fe44eb0bSAyushi Smriti         BMCWEB_LOG_DEBUG << "Attempt retry after " << retryIntervalSecs
291fe44eb0bSAyushi Smriti                          << " seconds. RetryCount = " << retryCount;
292fe44eb0bSAyushi Smriti         timer.expires_after(std::chrono::seconds(retryIntervalSecs));
293cb13a392SEd Tanous         timer.async_wait(
2946eaa1d2fSSunitha Harish             [self = shared_from_this()](const boost::system::error_code ec) {
2956eaa1d2fSSunitha Harish                 if (ec == boost::asio::error::operation_aborted)
2966eaa1d2fSSunitha Harish                 {
2976eaa1d2fSSunitha Harish                     BMCWEB_LOG_DEBUG
2986eaa1d2fSSunitha Harish                         << "async_wait failed since the operation is aborted"
2996eaa1d2fSSunitha Harish                         << ec.message();
3006eaa1d2fSSunitha Harish                 }
3016eaa1d2fSSunitha Harish                 else if (ec)
3026eaa1d2fSSunitha Harish                 {
3036eaa1d2fSSunitha Harish                     BMCWEB_LOG_ERROR << "async_wait failed: " << ec.message();
3046eaa1d2fSSunitha Harish                     // Ignore the error and continue the retry loop to attempt
3056eaa1d2fSSunitha Harish                     // sending the event as per the retry policy
3066eaa1d2fSSunitha Harish                 }
307fe44eb0bSAyushi Smriti                 self->runningTimer = false;
3086eaa1d2fSSunitha Harish 
3096eaa1d2fSSunitha Harish                 // Lets close connection and start from resolve.
3106eaa1d2fSSunitha Harish                 self->doClose();
311fe44eb0bSAyushi Smriti             });
312fe44eb0bSAyushi Smriti         return;
3132a5689a7SAppaRao Puli     }
3142a5689a7SAppaRao Puli 
3156eaa1d2fSSunitha Harish     void handleConnState()
316fe44eb0bSAyushi Smriti     {
3172a5689a7SAppaRao Puli         switch (state)
3182a5689a7SAppaRao Puli         {
31929a82b08SSunitha Harish             case ConnState::resolveInProgress:
3202a5689a7SAppaRao Puli             case ConnState::connectInProgress:
3212a5689a7SAppaRao Puli             case ConnState::sendInProgress:
3226eaa1d2fSSunitha Harish             case ConnState::recvInProgress:
3236eaa1d2fSSunitha Harish             case ConnState::closeInProgress:
3246eaa1d2fSSunitha Harish             {
3256eaa1d2fSSunitha Harish                 BMCWEB_LOG_DEBUG << "Async operation is already in progress";
3262a5689a7SAppaRao Puli                 break;
3276eaa1d2fSSunitha Harish             }
3282a5689a7SAppaRao Puli             case ConnState::initialized:
3292a5689a7SAppaRao Puli             case ConnState::closed:
3306eaa1d2fSSunitha Harish             {
3316eaa1d2fSSunitha Harish                 if (requestDataQueue.empty())
3326eaa1d2fSSunitha Harish                 {
3336eaa1d2fSSunitha Harish                     BMCWEB_LOG_DEBUG << "requestDataQueue is empty";
3346eaa1d2fSSunitha Harish                     return;
3356eaa1d2fSSunitha Harish                 }
3366eaa1d2fSSunitha Harish                 doResolve();
3376eaa1d2fSSunitha Harish                 break;
3386eaa1d2fSSunitha Harish             }
3396eaa1d2fSSunitha Harish             case ConnState::suspended:
3406eaa1d2fSSunitha Harish             case ConnState::terminated:
3416eaa1d2fSSunitha Harish             {
3426eaa1d2fSSunitha Harish                 doClose();
3436eaa1d2fSSunitha Harish                 break;
3446eaa1d2fSSunitha Harish             }
3456eaa1d2fSSunitha Harish             case ConnState::resolveFailed:
3462a5689a7SAppaRao Puli             case ConnState::connectFailed:
3472a5689a7SAppaRao Puli             case ConnState::sendFailed:
34892a74e56SAppaRao Puli             case ConnState::recvFailed:
3496eaa1d2fSSunitha Harish             case ConnState::retry:
35092a74e56SAppaRao Puli             {
3516eaa1d2fSSunitha Harish                 // In case of failures during connect and handshake
3526eaa1d2fSSunitha Harish                 // the retry policy will be applied
3536eaa1d2fSSunitha Harish                 waitAndRetry();
3542a5689a7SAppaRao Puli                 break;
3552a5689a7SAppaRao Puli             }
3562a5689a7SAppaRao Puli             case ConnState::connected:
35792a74e56SAppaRao Puli             case ConnState::idle:
35892a74e56SAppaRao Puli             {
3596eaa1d2fSSunitha Harish                 // State idle means, previous attempt is successful
3606eaa1d2fSSunitha Harish                 // State connected means, client connection is established
3616eaa1d2fSSunitha Harish                 // successfully
3626eaa1d2fSSunitha Harish                 if (requestDataQueue.empty())
3636eaa1d2fSSunitha Harish                 {
3646eaa1d2fSSunitha Harish                     BMCWEB_LOG_DEBUG << "requestDataQueue is empty";
3656eaa1d2fSSunitha Harish                     return;
3666eaa1d2fSSunitha Harish                 }
3672a5689a7SAppaRao Puli                 std::string data = requestDataQueue.front();
3682a5689a7SAppaRao Puli                 sendMessage(data);
3692a5689a7SAppaRao Puli                 break;
3702a5689a7SAppaRao Puli             }
3716eaa1d2fSSunitha Harish             case ConnState::abortConnection:
3726eaa1d2fSSunitha Harish             {
3736eaa1d2fSSunitha Harish                 // Server did not want to keep alive the session
3746eaa1d2fSSunitha Harish                 doClose();
3756eaa1d2fSSunitha Harish                 break;
3766eaa1d2fSSunitha Harish             }
3772a5689a7SAppaRao Puli         }
378bd030d0aSAppaRao Puli     }
379bd030d0aSAppaRao Puli 
380bd030d0aSAppaRao Puli   public:
381fe44eb0bSAyushi Smriti     explicit HttpClient(boost::asio::io_context& ioc, const std::string& id,
382fe44eb0bSAyushi Smriti                         const std::string& destIP, const std::string& destPort,
3834da04455SEd Tanous                         const std::string& destUri,
3844da04455SEd Tanous                         const boost::beast::http::fields& httpHeader) :
385bd030d0aSAppaRao Puli         conn(ioc),
3864da04455SEd Tanous         timer(ioc),
3874da04455SEd Tanous         req(boost::beast::http::verb::post, destUri, 11, "", httpHeader),
38884b35604SEd Tanous         subId(id), host(destIP), port(destPort)
389bd030d0aSAppaRao Puli     {
3904da04455SEd Tanous         req.set(boost::beast::http::field::host, host);
3914da04455SEd Tanous         req.keep_alive(true);
392bd030d0aSAppaRao Puli     }
393bd030d0aSAppaRao Puli 
3942a5689a7SAppaRao Puli     void sendData(const std::string& data)
395bd030d0aSAppaRao Puli     {
3966eaa1d2fSSunitha Harish         if ((state == ConnState::suspended) || (state == ConnState::terminated))
397bd030d0aSAppaRao Puli         {
398bd030d0aSAppaRao Puli             return;
399bd030d0aSAppaRao Puli         }
400bd030d0aSAppaRao Puli 
4012a5689a7SAppaRao Puli         if (requestDataQueue.size() <= maxRequestQueueSize)
4022a5689a7SAppaRao Puli         {
4037de9f811SSunitha Harish             requestDataQueue.push_back(data);
4046eaa1d2fSSunitha Harish             handleConnState();
4052a5689a7SAppaRao Puli         }
4062a5689a7SAppaRao Puli         else
4072a5689a7SAppaRao Puli         {
4082a5689a7SAppaRao Puli             BMCWEB_LOG_ERROR << "Request queue is full. So ignoring data.";
4092a5689a7SAppaRao Puli         }
4102a5689a7SAppaRao Puli 
4112a5689a7SAppaRao Puli         return;
412bd030d0aSAppaRao Puli     }
413bd030d0aSAppaRao Puli 
414fe44eb0bSAyushi Smriti     void setRetryConfig(const uint32_t retryAttempts,
415fe44eb0bSAyushi Smriti                         const uint32_t retryTimeoutInterval)
416fe44eb0bSAyushi Smriti     {
417fe44eb0bSAyushi Smriti         maxRetryAttempts = retryAttempts;
418fe44eb0bSAyushi Smriti         retryIntervalSecs = retryTimeoutInterval;
419fe44eb0bSAyushi Smriti     }
420fe44eb0bSAyushi Smriti 
421fe44eb0bSAyushi Smriti     void setRetryPolicy(const std::string& retryPolicy)
422fe44eb0bSAyushi Smriti     {
423fe44eb0bSAyushi Smriti         retryPolicyAction = retryPolicy;
424fe44eb0bSAyushi Smriti     }
425bd030d0aSAppaRao Puli };
426bd030d0aSAppaRao Puli 
427bd030d0aSAppaRao Puli } // namespace crow
428