Skip to content

Commit b422d73

Browse files
authored
Merge pull request #118 from bonitoo-io/fix/url_escape
fix: Adding encoding URL params
2 parents 62c51c9 + bb0402f commit b422d73

File tree

7 files changed

+122
-75
lines changed

7 files changed

+122
-75
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
### Fixes
77
- [#114](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/114) - Renamed `getRemaingRetryTime()`->`getRemainingRetryTime()`
88
- [#115](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/115) - Restored writing capability after a connection failure
9+
- [#118](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/118) - Added escaping of URL params (org, bucker, V1 username and pass)
910

1011
## 3.5.0 [2020-10-30]
1112
### Features

src/InfluxDbClient.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -233,25 +233,25 @@ void InfluxDBClient::setUrls() {
233233
if(_dbVersion == 2) {
234234
_writeUrl = _serverUrl;
235235
_writeUrl += "/api/v2/write?org=";
236-
_writeUrl += _org ;
236+
_writeUrl += urlEncode(_org.c_str());
237237
_writeUrl += "&bucket=";
238-
_writeUrl += _bucket;
238+
_writeUrl += urlEncode(_bucket.c_str());
239239
INFLUXDB_CLIENT_DEBUG(" writeUrl: %s\n", _writeUrl.c_str());
240240
_queryUrl = _serverUrl;
241241
_queryUrl += "/api/v2/query?org=";
242-
_queryUrl += _org;
242+
_queryUrl += urlEncode(_org.c_str());
243243
INFLUXDB_CLIENT_DEBUG(" queryUrl: %s\n", _queryUrl.c_str());
244244
} else {
245245
_writeUrl = _serverUrl;
246246
_writeUrl += "/write?db=";
247-
_writeUrl += _bucket;
247+
_writeUrl += urlEncode(_bucket.c_str());
248248
_queryUrl = _serverUrl;
249249
_queryUrl += "/api/v2/query";
250250
if(_user.length() > 0 && _password.length() > 0) {
251251
String auth = "&u=";
252-
auth += _user;
252+
auth += urlEncode(_user.c_str());
253253
auth += "&p=";
254-
auth += _password;
254+
auth += urlEncode(_password.c_str());
255255
_writeUrl += auth;
256256
_queryUrl += "?";
257257
_queryUrl += auth;

src/util/helpers.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,3 +118,32 @@ String escapeValue(const char *value) {
118118
}
119119
return ret;
120120
}
121+
122+
123+
static char invalidChars[] = "$&+,/:;=?@ <>#%{}|\\^~[]`";
124+
125+
static char hex_digit(char c) {
126+
return "0123456789ABCDEF"[c & 0x0F];
127+
}
128+
129+
String urlEncode(const char* src) {
130+
int n=0;
131+
char c,*s = (char *)src;
132+
while (c = *s++) {
133+
if(strchr(invalidChars, c)) {
134+
n++;
135+
}
136+
}
137+
String ret;
138+
ret.reserve(strlen(src)+2*n+1);
139+
s = (char *)src;
140+
while (c = *s++) {
141+
if (strchr(invalidChars,c)) {
142+
ret += '%';
143+
ret += hex_digit(c >> 4);
144+
ret += hex_digit(c);
145+
}
146+
else ret += c;
147+
}
148+
return ret;
149+
}

src/util/helpers.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ String escapeKey(String key, bool escapeEqual = true);
4646

4747
// Escape invalid chars in field value
4848
String escapeValue(const char *value);
49+
// Encode URL string for invalid chars
50+
String urlEncode(const char* src);
4951

5052

5153
#endif //_INFLUXDB_CLIENT_HELPERS_H

test/Test.cpp

Lines changed: 77 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ void Test::run() {
7373
testOptions();
7474
testPoint();
7575
testEcaping();
76+
testUrlEncode();
7677
testFluxTypes();
7778
testFluxParserEmpty();
7879
testFluxParserSingleTable();
@@ -104,69 +105,69 @@ void Test::run() {
104105
}
105106

106107
void Test::testOptions() {
107-
TEST_INIT("testOptions");
108-
WriteOptions defWO;
109-
TEST_ASSERT(defWO._writePrecision == WritePrecision::NoTime);
110-
TEST_ASSERT(defWO._batchSize == 1);
111-
TEST_ASSERT(defWO._bufferSize == 5);
112-
TEST_ASSERT(defWO._flushInterval == 60);
113-
TEST_ASSERT(defWO._retryInterval == 5);
114-
TEST_ASSERT(defWO._maxRetryInterval == 300);
115-
TEST_ASSERT(defWO._maxRetryAttempts == 3);
116-
TEST_ASSERT(defWO._defaultTags.length() == 0);
117-
118-
defWO = WriteOptions().writePrecision(WritePrecision::NS).batchSize(10).bufferSize(20).flushInterval(120).retryInterval(1).maxRetryInterval(20).maxRetryAttempts(5).addDefaultTag("tag1","val1").addDefaultTag("tag2","val2");
119-
TEST_ASSERT(defWO._writePrecision == WritePrecision::NS);
120-
TEST_ASSERT(defWO._batchSize == 10);
121-
TEST_ASSERT(defWO._bufferSize == 20);
122-
TEST_ASSERT(defWO._flushInterval == 120);
123-
TEST_ASSERT(defWO._retryInterval == 1);
124-
TEST_ASSERT(defWO._maxRetryInterval == 20);
125-
TEST_ASSERT(defWO._maxRetryAttempts == 5);
126-
TEST_ASSERT(defWO._defaultTags == "tag1=val1,tag2=val2");
127-
128-
HTTPOptions defHO;
129-
TEST_ASSERT(!defHO._connectionReuse);
130-
TEST_ASSERT(defHO._httpReadTimeout == 5000);
131-
132-
defHO = HTTPOptions().connectionReuse(true).httpReadTimeout(20000);
133-
TEST_ASSERT(defHO._connectionReuse);
134-
TEST_ASSERT(defHO._httpReadTimeout == 20000);
135-
136-
InfluxDBClient c;
137-
TEST_ASSERT(c._writeOptions._writePrecision == WritePrecision::NoTime);
138-
TEST_ASSERT(c._writeOptions._batchSize == 1);
139-
TEST_ASSERT(c._writeOptions._bufferSize == 5);
140-
TEST_ASSERT(c._writeOptions._flushInterval == 60);
141-
TEST_ASSERT(c._writeOptions._retryInterval == 5);
142-
TEST_ASSERT(c._writeOptions._maxRetryAttempts == 3);
143-
TEST_ASSERT(c._writeOptions._maxRetryInterval == 300);
144-
TEST_ASSERT(!c._httpOptions._connectionReuse);
145-
TEST_ASSERT(c._httpOptions._httpReadTimeout == 5000);
146-
147-
c.setWriteOptions(defWO);
148-
TEST_ASSERT(c._writeOptions._writePrecision == WritePrecision::NS);
149-
TEST_ASSERT(c._writeOptions._batchSize == 10);
150-
TEST_ASSERT(c._writeOptions._bufferSize == 20);
151-
TEST_ASSERT(c._writeOptions._flushInterval == 120);
152-
TEST_ASSERT(c._writeOptions._retryInterval == 1);
153-
TEST_ASSERT(c._writeOptions._maxRetryAttempts == 5);
154-
TEST_ASSERT(c._writeOptions._maxRetryInterval == 20);
155-
156-
c.setHTTPOptions(defHO);
157-
TEST_ASSERT(c._httpOptions._connectionReuse);
158-
TEST_ASSERT(c._httpOptions._httpReadTimeout == 20000);
159-
160-
c.setWriteOptions(WritePrecision::MS, 15, 14, 70, false);
161-
TEST_ASSERT(c._writeOptions._writePrecision == WritePrecision::MS);
162-
TEST_ASSERT(c._writeOptions._batchSize == 15);
163-
TEST_ASSERTM(c._writeOptions._bufferSize == 30, String(c._writeOptions._bufferSize));
164-
TEST_ASSERT(c._writeOptions._flushInterval == 70);
165-
TEST_ASSERT(!c._httpOptions._connectionReuse);
166-
TEST_ASSERT(c._httpOptions._httpReadTimeout == 20000);
167-
168-
TEST_END();
169-
}
108+
TEST_INIT("testOptions");
109+
WriteOptions defWO;
110+
TEST_ASSERT(defWO._writePrecision == WritePrecision::NoTime);
111+
TEST_ASSERT(defWO._batchSize == 1);
112+
TEST_ASSERT(defWO._bufferSize == 5);
113+
TEST_ASSERT(defWO._flushInterval == 60);
114+
TEST_ASSERT(defWO._retryInterval == 5);
115+
TEST_ASSERT(defWO._maxRetryInterval == 300);
116+
TEST_ASSERT(defWO._maxRetryAttempts == 3);
117+
TEST_ASSERT(defWO._defaultTags.length() == 0);
118+
119+
defWO = WriteOptions().writePrecision(WritePrecision::NS).batchSize(10).bufferSize(20).flushInterval(120).retryInterval(1).maxRetryInterval(20).maxRetryAttempts(5).addDefaultTag("tag1","val1").addDefaultTag("tag2","val2");
120+
TEST_ASSERT(defWO._writePrecision == WritePrecision::NS);
121+
TEST_ASSERT(defWO._batchSize == 10);
122+
TEST_ASSERT(defWO._bufferSize == 20);
123+
TEST_ASSERT(defWO._flushInterval == 120);
124+
TEST_ASSERT(defWO._retryInterval == 1);
125+
TEST_ASSERT(defWO._maxRetryInterval == 20);
126+
TEST_ASSERT(defWO._maxRetryAttempts == 5);
127+
TEST_ASSERT(defWO._defaultTags == "tag1=val1,tag2=val2");
128+
129+
HTTPOptions defHO;
130+
TEST_ASSERT(!defHO._connectionReuse);
131+
TEST_ASSERT(defHO._httpReadTimeout == 5000);
132+
133+
defHO = HTTPOptions().connectionReuse(true).httpReadTimeout(20000);
134+
TEST_ASSERT(defHO._connectionReuse);
135+
TEST_ASSERT(defHO._httpReadTimeout == 20000);
136+
137+
InfluxDBClient c;
138+
TEST_ASSERT(c._writeOptions._writePrecision == WritePrecision::NoTime);
139+
TEST_ASSERT(c._writeOptions._batchSize == 1);
140+
TEST_ASSERT(c._writeOptions._bufferSize == 5);
141+
TEST_ASSERT(c._writeOptions._flushInterval == 60);
142+
TEST_ASSERT(c._writeOptions._retryInterval == 5);
143+
TEST_ASSERT(c._writeOptions._maxRetryAttempts == 3);
144+
TEST_ASSERT(c._writeOptions._maxRetryInterval == 300);
145+
TEST_ASSERT(!c._httpOptions._connectionReuse);
146+
TEST_ASSERT(c._httpOptions._httpReadTimeout == 5000);
147+
148+
c.setWriteOptions(defWO);
149+
TEST_ASSERT(c._writeOptions._writePrecision == WritePrecision::NS);
150+
TEST_ASSERT(c._writeOptions._batchSize == 10);
151+
TEST_ASSERT(c._writeOptions._bufferSize == 20);
152+
TEST_ASSERT(c._writeOptions._flushInterval == 120);
153+
TEST_ASSERT(c._writeOptions._retryInterval == 1);
154+
TEST_ASSERT(c._writeOptions._maxRetryAttempts == 5);
155+
TEST_ASSERT(c._writeOptions._maxRetryInterval == 20);
156+
157+
c.setHTTPOptions(defHO);
158+
TEST_ASSERT(c._httpOptions._connectionReuse);
159+
TEST_ASSERT(c._httpOptions._httpReadTimeout == 20000);
160+
161+
c.setWriteOptions(WritePrecision::MS, 15, 14, 70, false);
162+
TEST_ASSERT(c._writeOptions._writePrecision == WritePrecision::MS);
163+
TEST_ASSERT(c._writeOptions._batchSize == 15);
164+
TEST_ASSERTM(c._writeOptions._bufferSize == 30, String(c._writeOptions._bufferSize));
165+
TEST_ASSERT(c._writeOptions._flushInterval == 70);
166+
TEST_ASSERT(!c._httpOptions._connectionReuse);
167+
TEST_ASSERT(c._httpOptions._httpReadTimeout == 20000);
168+
169+
TEST_END();
170+
}
170171

171172

172173
void Test::testEcaping() {
@@ -433,7 +434,7 @@ void Test::testHTTPReadTimeout() {
433434
InfluxDBClient client(Test::apiUrl, Test::orgName, Test::bucketName, Test::token);
434435
waitServer(Test::managementUrl, true);
435436
TEST_ASSERT(client.validateConnection());
436-
//set server delay for 6s (client has default timeout 5s)
437+
//set server delay on query for 6s (client has default timeout 5s)
437438
String rec = "a,direction=timeout,timeout=6 a=1";
438439
TEST_ASSERT(client.writeRecord(rec));
439440
rec = "a,tag=a, a=1i";
@@ -449,7 +450,7 @@ void Test::testHTTPReadTimeout() {
449450
TEST_ASSERT(client.writeRecord(rec));
450451
q = client.query(query);
451452
// should be ok
452-
TEST_ASSERT(q.next());
453+
TEST_ASSERTM(q.next(), q.getError());
453454
TEST_ASSERT(!q.next());
454455
TEST_ASSERTM(q.getError() == "", q.getError());
455456
q.close();
@@ -1089,10 +1090,11 @@ void Test::testTimestamp() {
10891090
}
10901091

10911092
void Test::testV1() {
1092-
10931093
TEST_INIT("testV1");
1094-
InfluxDBClient client(Test::apiUrl, Test::dbName);
1094+
InfluxDBClient client;
10951095

1096+
client.setConnectionParamsV1(Test::apiUrl, Test::dbName, "user","my secret password");
1097+
waitServer(Test::managementUrl, true);
10961098
TEST_ASSERTM(client.validateConnection(), client.getLastErrorMessage());
10971099
//test with no batching
10981100
for (int i = 0; i < 20; i++) {
@@ -1872,6 +1874,14 @@ void Test::testDefaultTags() {
18721874
deleteAll(Test::apiUrl);
18731875
}
18741876

1877+
void Test::testUrlEncode() {
1878+
TEST_INIT("testUrlEncode");
1879+
String res = "my%20%5Bsecret%5D%20pass%3A%2F%5Cw%60o%5Er%25d";
1880+
String urlEnc = urlEncode("my [secret] pass:/\\w`o^r%d");
1881+
TEST_ASSERTM(res == urlEnc, urlEnc);
1882+
TEST_END();
1883+
}
1884+
18751885
void Test::setServerUrl(InfluxDBClient &client, String serverUrl) {
18761886
client._serverUrl = serverUrl;
18771887
client.setUrls();

test/Test.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,6 +75,7 @@ class Test {
7575
static void testRetriesOnServerOverload();
7676
static void testRetryInterval();
7777
static void testDefaultTags();
78+
static void testUrlEncode();
7879
};
7980

8081
bool testAssertm(int line, bool state,String message);

test/server/server.js

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -427,14 +427,18 @@ function checkWriteParams(req, res) {
427427
const AllowedPrecisionsV1 = ['ns','u','ms','s'];
428428
function checkWriteParamsV1(req, res) {
429429
var db = req.query['db'];
430+
var user = req.query['u'];
431+
var pass = req.query['p'];
430432
var precision = req.query['precision'];
431433
if(db != 'my-db') {
432434
res.status(404).send(`{"code":"not found","message":"database \"${db}\" not found"}`);
433435
return false;
434436
} else if(typeof precision !== 'undefined' && AllowedPrecisionsV1.indexOf(precision)==-1) {
435-
res.status(400).send(`{"code":"bad request ","message":"precision \"${precision}\" is not valid"}`);
437+
res.status(400).send(`precision \"${precision}\" is not valid`);
436438
return false;
437-
}else {
439+
} else if (user !== 'user' && pass != 'my secret pass') {
440+
res.status(401).send("unauthorized")
441+
} else {
438442
return true;
439443
}
440444
}

0 commit comments

Comments
 (0)