11#include " databento/detail/http_client.hpp"
22
3- #include < chrono> // seconds
3+ #include < chrono> // seconds
4+ #include < sstream> // ostringstream
45
56#include " databento/exceptions.hpp" // HttpResponseError, HttpRequestError, JsonResponseError
7+ #include " databento/log.hpp" // ILogReceiver, LogLevel
68#include " databento/version.hpp" // DATABENTO_VERSION
79
810using databento::detail::HttpClient;
@@ -13,17 +15,19 @@ const httplib::Headers HttpClient::kHeaders{
1315 {" user-agent" , " Databento/" DATABENTO_VERSION " C++" },
1416};
1517
16- HttpClient::HttpClient (const std::string& key, const std::string& gateway)
17- : client_{gateway} {
18+ HttpClient::HttpClient (databento::ILogReceiver* log_receiver,
19+ const std::string& key, const std::string& gateway)
20+ : log_receiver_{log_receiver}, client_{gateway} {
1821 client_.set_default_headers (HttpClient::kHeaders );
1922 client_.set_basic_auth (key, " " );
2023 client_.set_read_timeout (kTimeout );
2124 client_.set_write_timeout (kTimeout );
2225}
2326
24- HttpClient::HttpClient (const std::string& key, const std::string& gateway,
27+ HttpClient::HttpClient (databento::ILogReceiver* log_receiver,
28+ const std::string& key, const std::string& gateway,
2529 std::uint16_t port)
26- : client_{gateway, port} {
30+ : log_receiver_{log_receiver}, client_{gateway, port} {
2731 client_.set_default_headers (HttpClient::kHeaders );
2832 client_.set_basic_auth (key, " " );
2933 client_.set_read_timeout (kTimeout );
@@ -79,19 +83,45 @@ void HttpClient::GetRawStream(const std::string& path,
7983}
8084
8185nlohmann::json HttpClient::CheckAndParseResponse (const std::string& path,
82- httplib::Result&& res) {
86+ httplib::Result&& res) const {
8387 if (res.error () != httplib::Error::Success) {
8488 throw HttpRequestError{path, res.error ()};
8589 }
86- const auto status_code = res.value ().status ;
90+ auto & response = res.value ();
91+ const auto status_code = response.status ;
8792 if (HttpClient::IsErrorStatus (status_code)) {
88- throw HttpResponseError{path, status_code, std::move (res. value () .body )};
93+ throw HttpResponseError{path, status_code, std::move (response .body )};
8994 }
95+ CheckWarnings (response);
9096 try {
91- return nlohmann::json::parse (std::move (res. value () .body ));
97+ return nlohmann::json::parse (std::move (response .body ));
9298 } catch (const nlohmann::json::parse_error& parse_err) {
9399 throw JsonResponseError::ParseError (path, parse_err);
94100 }
95101}
96102
103+ void HttpClient::CheckWarnings (const httplib::Response& response) const {
104+ // Returns empty string if not found. `get_header_value` is case insensitive
105+ const auto raw = response.get_header_value (" X-Warning" );
106+ if (!raw.empty ()) {
107+ try {
108+ const auto json = nlohmann::json::parse (raw);
109+ if (json.is_array ()) {
110+ for (const auto & warning_json : json.items ()) {
111+ const std::string warning = warning_json.value ();
112+ std::ostringstream msg;
113+ msg << __PRETTY_FUNCTION__ << " Server " << warning;
114+ log_receiver_->Receive (LogLevel::Warning, msg.str ());
115+ }
116+ return ;
117+ }
118+ } catch (const std::exception&) {
119+ }
120+ std::ostringstream msg;
121+ msg << __PRETTY_FUNCTION__
122+ << " Failed to parse warnings from HTTP header. Raw contents: " << raw;
123+ log_receiver_->Receive (LogLevel::Warning, msg.str ());
124+ }
125+ }
126+
97127bool HttpClient::IsErrorStatus (int status_code) { return status_code >= 400 ; }
0 commit comments