Skip to content

Commit fb299aa

Browse files
author
José Manuel Sánchez Fernández
committed
Refined exception cases for HTTP transport issues detection
1 parent fbae738 commit fb299aa

File tree

13 files changed

+254
-160
lines changed

13 files changed

+254
-160
lines changed

include/InfluxDBException.h

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
///
2+
/// \author Adam Wegrzynek <adam.wegrzynek@cern.ch>
3+
///
4+
5+
#ifndef INFLUXDATA_EXCEPTION_H
6+
#define INFLUXDATA_EXCEPTION_H
7+
8+
#include <stdexcept>
9+
#include <string>
10+
11+
namespace influxdb {
12+
13+
class InfluxDBException : public std::runtime_error {
14+
public:
15+
InfluxDBException(const std::string &source, const std::string &message) : std::runtime_error::runtime_error(
16+
"influx-cxx [" + source + "]: " + message) {}
17+
};
18+
19+
class NonExistentDatabase : public InfluxDBException {
20+
public:
21+
NonExistentDatabase(const std::string &source, const std::string &message) : InfluxDBException(source, message) {}
22+
};
23+
24+
class BadRequest : public InfluxDBException {
25+
public:
26+
BadRequest(const std::string &source, const std::string &message) : InfluxDBException(source, message) {}
27+
};
28+
29+
class ServerError : public InfluxDBException {
30+
public:
31+
ServerError(const std::string &source, const std::string &message) : InfluxDBException(source, message) {}
32+
};
33+
34+
class ConnectionError : public InfluxDBException {
35+
public:
36+
ConnectionError(const std::string &source, const std::string &message) : InfluxDBException(source, message) {};
37+
};
38+
39+
40+
} // namespace influxdb
41+
42+
#endif // INFLUXDATA_EXCEPTION_H

include/InfluxDBFactory.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ class InfluxDBFactory
2525
/// Provides InfluxDB instance with given transport
2626
/// \param url URL defining transport details
2727
/// \throw InfluxDBException if unrecognised backend or missing protocol
28-
static std::unique_ptr<InfluxDB> Get(std::string url) noexcept(false);
28+
static std::unique_ptr<InfluxDB> Get(const std::string& url) noexcept(false);
2929

3030
private:
3131
///\return backend based on provided URL
32-
static std::unique_ptr<Transport> GetTransport(std::string url);
32+
static std::unique_ptr<Transport> GetTransport(const std::string& url);
3333

3434
/// Private constructor disallows to create instance of Factory
3535
InfluxDBFactory() = default;

src/HTTP.cxx

Lines changed: 46 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -9,25 +9,27 @@
99
namespace influxdb::transports
1010
{
1111

12-
HTTP::HTTP(const std::string& url)
12+
HTTP::HTTP(const std::string &url)
1313
{
1414
initCurl(url);
1515
initCurlRead(url);
1616
obtainInfluxServiceUrl(url);
1717
obtainDatabaseName(url);
1818
}
1919

20-
void HTTP::initCurl(const std::string& url)
20+
void HTTP::initCurl(const std::string &url)
2121
{
2222
CURLcode globalInitResult = curl_global_init(CURL_GLOBAL_ALL);
23-
if (globalInitResult != CURLE_OK) {
24-
throw InfluxDBException("HTTP::initCurl", curl_easy_strerror(globalInitResult));
23+
if (globalInitResult != CURLE_OK)
24+
{
25+
throw InfluxDBException(__PRETTY_FUNCTION__, curl_easy_strerror(globalInitResult));
2526
}
2627

2728
std::string writeUrl = url;
2829
auto position = writeUrl.find("?");
29-
if (position == std::string::npos) {
30-
throw InfluxDBException("HTTP::initCurl", "Database not specified");
30+
if (position == std::string::npos)
31+
{
32+
throw InfluxDBException(__PRETTY_FUNCTION__, "Database not specified");
3133
}
3234
if (writeUrl.at(position - 1) != '/')
3335
{
@@ -38,7 +40,7 @@ void HTTP::initCurl(const std::string& url)
3840
writeUrl.insert(position, "write");
3941
}
4042
writeHandle = curl_easy_init();
41-
curl_easy_setopt(writeHandle, CURLOPT_URL, writeUrl.c_str());
43+
curl_easy_setopt(writeHandle, CURLOPT_URL, writeUrl.c_str());
4244
curl_easy_setopt(writeHandle, CURLOPT_SSL_VERIFYPEER, 0);
4345
curl_easy_setopt(writeHandle, CURLOPT_CONNECTTIMEOUT, 10);
4446
curl_easy_setopt(writeHandle, CURLOPT_TIMEOUT, 10);
@@ -51,44 +53,39 @@ void HTTP::initCurl(const std::string& url)
5153

5254
static size_t WriteCallback(void *contents, size_t size, size_t nmemb, void *userp)
5355
{
54-
((std::string*)userp)->append((char*)contents, size * nmemb);
55-
return size * nmemb;
56+
((std::string *) userp)->append((char *) contents, size * nmemb);
57+
return size * nmemb;
5658
}
5759

58-
void HTTP::initCurlRead(const std::string& url)
60+
void HTTP::initCurlRead(const std::string &url)
5961
{
6062
mReadUrl = url + "&q=";
6163
mReadUrl.insert(mReadUrl.find("?"), "/query");
6264
readHandle = curl_easy_init();
63-
curl_easy_setopt(readHandle, CURLOPT_SSL_VERIFYPEER, 0);
65+
curl_easy_setopt(readHandle, CURLOPT_SSL_VERIFYPEER, 0);
6466
curl_easy_setopt(readHandle, CURLOPT_CONNECTTIMEOUT, 10);
6567
curl_easy_setopt(readHandle, CURLOPT_TIMEOUT, 10);
6668
curl_easy_setopt(readHandle, CURLOPT_TCP_KEEPIDLE, 120L);
6769
curl_easy_setopt(readHandle, CURLOPT_TCP_KEEPINTVL, 60L);
6870
curl_easy_setopt(readHandle, CURLOPT_WRITEFUNCTION, WriteCallback);
6971
}
7072

71-
std::string HTTP::query(const std::string& query)
73+
std::string HTTP::query(const std::string &query)
7274
{
7375
CURLcode response;
7476
long responseCode;
7577
std::string buffer;
76-
char* encodedQuery = curl_easy_escape(readHandle, query.c_str(), query.size());
78+
char *encodedQuery = curl_easy_escape(readHandle, query.c_str(), query.size());
7779
auto fullUrl = mReadUrl + std::string(encodedQuery);
7880
curl_easy_setopt(readHandle, CURLOPT_URL, fullUrl.c_str());
7981
curl_easy_setopt(readHandle, CURLOPT_WRITEDATA, &buffer);
8082
response = curl_easy_perform(readHandle);
8183
curl_easy_getinfo(readHandle, CURLINFO_RESPONSE_CODE, &responseCode);
82-
if (response != CURLE_OK) {
83-
throw InfluxDBException("HTTP::query", curl_easy_strerror(response));
84-
}
85-
if (responseCode != 200) {
86-
throw InfluxDBException("HTTP::query", "Status code: " + std::to_string(responseCode));
87-
}
84+
treatCurlResponse(response, responseCode);
8885
return buffer;
8986
}
9087

91-
void HTTP::enableBasicAuth(const std::string& auth)
88+
void HTTP::enableBasicAuth(const std::string &auth)
9289
{
9390
curl_easy_setopt(writeHandle, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
9491
curl_easy_setopt(writeHandle, CURLOPT_USERPWD, auth.c_str());
@@ -109,19 +106,38 @@ HTTP::~HTTP()
109106
curl_global_cleanup();
110107
}
111108

112-
void HTTP::send(std::string&& post)
109+
void HTTP::send(std::string &&lineprotocol)
113110
{
114111
CURLcode response;
115112
long responseCode;
116-
curl_easy_setopt(writeHandle, CURLOPT_POSTFIELDS, post.c_str());
117-
curl_easy_setopt(writeHandle, CURLOPT_POSTFIELDSIZE, (long) post.length());
113+
curl_easy_setopt(writeHandle, CURLOPT_POSTFIELDS, lineprotocol.c_str());
114+
curl_easy_setopt(writeHandle, CURLOPT_POSTFIELDSIZE, (long) lineprotocol.length());
118115
response = curl_easy_perform(writeHandle);
119116
curl_easy_getinfo(writeHandle, CURLINFO_RESPONSE_CODE, &responseCode);
120-
if (response != CURLE_OK) {
121-
throw InfluxDBException("HTTP::send", curl_easy_strerror(response));
117+
treatCurlResponse(response, responseCode);
118+
}
119+
120+
void HTTP::treatCurlResponse(const CURLcode &response, long responseCode) const
121+
{
122+
if (response != CURLE_OK)
123+
{
124+
throw ConnectionError(__PRETTY_FUNCTION__, curl_easy_strerror(response));
122125
}
123-
if (responseCode < 200 || responseCode > 206) {
124-
throw InfluxDBException("HTTP::send", "Response code: " + std::to_string(responseCode));
126+
//
127+
// Influx API response codes:
128+
// https://docs.influxdata.com/influxdb/v1.7/tools/api/#status-codes-and-responses-2
129+
//
130+
if (responseCode == 404)
131+
{
132+
throw NonExistentDatabase(__PRETTY_FUNCTION__, "Nonexistent database: " + std::to_string(responseCode));
133+
}
134+
else if ((responseCode >= 400) && (responseCode < 500))
135+
{
136+
throw BadRequest(__PRETTY_FUNCTION__, "Bad request: " + std::to_string(responseCode));
137+
}
138+
else if (responseCode > 500)
139+
{
140+
throw ServerError(__PRETTY_FUNCTION__, "Influx server error:" + std::to_string(responseCode));
125141
}
126142
}
127143

@@ -152,8 +168,8 @@ void HTTP::createDatabase()
152168
std::string createUrl = mInfluxDbServiceUrl + "/query";
153169
std::string postFields = "q=CREATE DATABASE " + mDatabaseName;
154170

155-
CURL* createHandle = curl_easy_init();
156-
curl_easy_setopt(createHandle, CURLOPT_URL, createUrl.c_str());
171+
CURL *createHandle = curl_easy_init();
172+
curl_easy_setopt(createHandle, CURLOPT_URL, createUrl.c_str());
157173
curl_easy_setopt(createHandle, CURLOPT_SSL_VERIFYPEER, 0);
158174
curl_easy_setopt(createHandle, CURLOPT_CONNECTTIMEOUT, 10);
159175
curl_easy_setopt(createHandle, CURLOPT_TIMEOUT, 10);
@@ -169,14 +185,7 @@ void HTTP::createDatabase()
169185
CURLcode response = curl_easy_perform(createHandle);
170186
long responseCode;
171187
curl_easy_getinfo(createHandle, CURLINFO_RESPONSE_CODE, &responseCode);
172-
if (response != CURLE_OK)
173-
{
174-
throw InfluxDBException("HTTP::createDatabase", curl_easy_strerror(response));
175-
}
176-
if (responseCode < 200 || responseCode > 206)
177-
{
178-
throw InfluxDBException("HTTP::createDatabase", "Response code: " + std::to_string(responseCode));
179-
}
188+
treatCurlResponse(response,responseCode);
180189
}
181190

182191
} // namespace influxdb

src/HTTP.h

Lines changed: 47 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -16,67 +16,71 @@ namespace influxdb::transports
1616
/// \brief HTTP transport
1717
class HTTP : public Transport
1818
{
19-
public:
20-
/// Constructor
21-
HTTP(const std::string& url);
19+
public:
20+
/// Constructor
21+
HTTP(const std::string &url);
2222

23-
/// Default destructor
24-
~HTTP();
23+
/// Default destructor
24+
~HTTP() override;
2525

26-
/// Sends point via HTTP POST
27-
/// \throw InfluxDBException when CURL fails on POSTing or response code != 200
28-
void send(std::string&& post) override;
26+
/// Sends point via HTTP POST
27+
/// \throw InfluxDBException when CURL fails on POSTing or response code != 200
28+
void send(std::string &&lineprotocol) override;
2929

30-
/// Queries database
31-
/// \throw InfluxDBException when CURL GET fails
32-
std::string query(const std::string& query) override;
30+
/// Queries database
31+
/// \throw InfluxDBException when CURL GET fails
32+
std::string query(const std::string &query) override;
3333

34-
/// Creates database used at url if it does not exists
35-
/// \throw InfluxDBException when CURL POST fails
36-
void createDatabase();
34+
/// Creates database used at url if it does not exists
35+
/// \throw InfluxDBException when CURL POST fails
36+
void createDatabase() override;
3737

38-
/// Enable Basic Auth
39-
/// \param auth <username>:<password>
40-
void enableBasicAuth(const std::string& auth);
38+
/// Enable Basic Auth
39+
/// \param auth <username>:<password>
40+
void enableBasicAuth(const std::string &auth);
4141

42-
/// Enable SSL
43-
void enableSsl();
42+
/// Enable SSL
43+
void enableSsl();
4444

45-
/// Get the database name managed by this transport
46-
std::string databaseName() const;
45+
/// Get the database name managed by this transport
46+
[[nodiscard]] std::string databaseName() const;
4747

48-
/// Get the influx service url which transport connects to
49-
std::string influxDbServiceUrl() const;
48+
/// Get the influx service url which transport connects to
49+
[[nodiscard]] std::string influxDbServiceUrl() const;
5050

51-
private:
51+
private:
5252

53-
/// Obtain InfluxDB service url from the url passed
54-
void obtainInfluxServiceUrl(const std::string& url);
53+
/// Obtain InfluxDB service url from the url passed
54+
void obtainInfluxServiceUrl(const std::string &url);
5555

56-
/// Obtain database name from the url passed
57-
void obtainDatabaseName(const std::string& url);
56+
/// Obtain database name from the url passed
57+
void obtainDatabaseName(const std::string &url);
5858

59-
/// Initilizes CURL for writting and common options
60-
/// \throw InfluxDBException if database (?db=) not specified
61-
void initCurl(const std::string& url);
59+
/// Initilizes CURL for writting and common options
60+
/// \throw InfluxDBException if database (?db=) not specified
61+
void initCurl(const std::string &url);
6262

63-
/// Initializes CURL for reading
64-
void initCurlRead(const std::string& url);
63+
/// Initializes CURL for reading
64+
void initCurlRead(const std::string &url);
6565

66-
/// CURL pointer configured for writting points
67-
CURL* writeHandle;
66+
/// treats responses of CURL requests
67+
void treatCurlResponse(const CURLcode &response, long responseCode) const;
6868

69-
/// CURL pointer configured for querying
70-
CURL* readHandle;
69+
/// CURL pointer configured for writting points
70+
CURL *writeHandle;
7171

72-
/// InfluxDB read URL
73-
std::string mReadUrl;
72+
/// CURL pointer configured for querying
73+
CURL *readHandle;
7474

75-
/// InfluxDB service URL
76-
std::string mInfluxDbServiceUrl;
75+
/// InfluxDB read URL
76+
std::string mReadUrl;
77+
78+
/// InfluxDB service URL
79+
std::string mInfluxDbServiceUrl;
80+
81+
/// Database name used
82+
std::string mDatabaseName;
7783

78-
/// Database name used
79-
std::string mDatabaseName;
8084
};
8185

8286
} // namespace influxdb

0 commit comments

Comments
 (0)