Skip to content

Commit bacb776

Browse files
committed
CacheDB: Fix URL parser bugs with multiple hosts
Although support for CACHEDB_ID_MULTIPLE_HOSTS has been in there for a long time, URLs such as "redis:ha://h1,h2,h3:6379" were not correctly parsed.
1 parent 60c1d54 commit bacb776

File tree

2 files changed

+212
-19
lines changed

2 files changed

+212
-19
lines changed

cachedb/cachedb_id.c

Lines changed: 47 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@ static int dupl_string(char** dst, const char* begin, const char* end)
4444

4545
*dst = pkg_malloc(end - begin + 1);
4646
if ((*dst) == NULL) {
47+
LM_ERR("pkg malloc failed on %p/%p\n", begin, end);
4748
return -1;
4849
}
4950

@@ -81,7 +82,7 @@ static int parse_cachedb_url(struct cachedb_id* id, const str* url)
8182
};
8283

8384
enum state st;
84-
unsigned int len, i, ipv6_flag=0;
85+
unsigned int len, i, ipv6_flag=0, multi_hosts=0;
8586
char* begin;
8687
char* prev_token,*start_host=NULL,*start_prev=NULL,*ptr;
8788

@@ -159,11 +160,15 @@ static int parse_cachedb_url(struct cachedb_id* id, const str* url)
159160
switch(url->s[i]) {
160161
case '@':
161162
st = ST_HOST;
163+
multi_hosts = 0;
162164
if (dupl_string(&id->username, begin, url->s + i) < 0) goto err;
163165
begin = url->s + i + 1;
164166
break;
165167

166168
case ':':
169+
if (multi_hosts)
170+
continue;
171+
167172
st = ST_PASS_PORT;
168173
if (dupl_string(&prev_token, begin, url->s + i) < 0) goto err;
169174
start_prev = begin;
@@ -180,6 +185,10 @@ static int parse_cachedb_url(struct cachedb_id* id, const str* url)
180185
begin = url->s + i + 1;
181186
st = ST_DB;
182187
break;
188+
189+
case ',':
190+
multi_hosts = 1;
191+
break;
183192
}
184193
break;
185194

@@ -190,6 +199,7 @@ static int parse_cachedb_url(struct cachedb_id* id, const str* url)
190199
id->username = prev_token;
191200
if (dupl_string(&id->password, begin, url->s + i) < 0) goto err;
192201
begin = url->s + i + 1;
202+
start_host = begin;
193203
break;
194204

195205
case '/':
@@ -237,6 +247,10 @@ static int parse_cachedb_url(struct cachedb_id* id, const str* url)
237247
begin = url->s + i + 1;
238248
st = ST_DB;
239249
break;
250+
251+
case ',':
252+
id->flags |= CACHEDB_ID_MULTIPLE_HOSTS;
253+
break;
240254
}
241255
break;
242256

@@ -286,11 +300,23 @@ static int parse_cachedb_url(struct cachedb_id* id, const str* url)
286300
}
287301
}
288302

289-
if (st == ST_PORT) {
303+
LM_DBG("final st: %d, begin: %s, start_host: %s\n", st, begin, start_host);
304+
305+
if (multi_hosts)
306+
id->flags |= CACHEDB_ID_MULTIPLE_HOSTS;
307+
308+
if (st == ST_PORT || st == ST_PASS_PORT) {
309+
int rc;
290310
if (url->s + i - begin == 0)
291311
goto err;
292312

293-
id->port = str2s(begin, url->s + i - begin, 0);
313+
id->port = str2s(begin, url->s + i - begin, &rc);
314+
if (rc != 0)
315+
goto err;
316+
317+
if (prev_token && !id->host)
318+
id->host = prev_token;
319+
294320
return 0;
295321
}
296322

@@ -300,11 +326,24 @@ static int parse_cachedb_url(struct cachedb_id* id, const str* url)
300326
return 0;
301327
}
302328

303-
if (st == ST_USER_HOST && begin == url->s+url->len) {
304-
/* Not considered an error - to cope with modules that
305-
* offer cacheDB functionality backed up by OpenSIPS mem */
306-
id->flags |= CACHEDB_ID_NO_URL;
307-
LM_DBG("Just scheme, no actual url\n");
329+
if (st == ST_HOST || st == ST_USER_HOST) {
330+
if (begin == url->s+url->len) {
331+
if (st == ST_USER_HOST) {
332+
/* Not considered an error - to cope with modules that
333+
* offer cacheDB functionality backed up by OpenSIPS mem */
334+
id->flags |= CACHEDB_ID_NO_URL;
335+
LM_DBG("Just scheme, no actual url\n");
336+
return 0;
337+
} else {
338+
goto err;
339+
}
340+
}
341+
342+
if (start_host)
343+
begin = start_host;
344+
345+
if (begin < url->s + len &&
346+
dupl_string(&id->host, begin, url->s + len) < 0) goto err;
308347
return 0;
309348
}
310349

cachedb/test/test_cachedb.c

Lines changed: 165 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -688,37 +688,191 @@ static void test_cachedb_backends(void)
688688

689689
static void test_cachedb_url(void)
690690
{
691+
#define CDB_PARSE(__url) db = new_cachedb_id(_str(__url)); if (!ok(db != NULL)) return;
691692
struct cachedb_id *db;
692693

693694
/* invalid URLs */
694695
ok(!new_cachedb_id(_str("d:g://@")));
695696
ok(!new_cachedb_id(_str("d:g://u:@")));
696697
ok(!new_cachedb_id(_str("d:g://u:p@")));
697-
ok(!new_cachedb_id(_str("d:g://u:p@h")));
698698
ok(!new_cachedb_id(_str("d:g://u:p@h:")));
699699

700-
db = new_cachedb_id(_str("redis:group1://:[email protected]:6379"));
701-
if (!ok(db != NULL))
702-
return;
700+
CDB_PARSE("redis:group1://");
701+
ok(db->flags == CACHEDB_ID_NO_URL);
702+
ok(!strcmp(db->scheme, "redis"));
703+
ok(!strcmp(db->group_name, "group1"));
704+
ok(!db->username);
705+
ok(!db->password);
706+
ok(!db->host);
707+
ok(db->port == 0);
708+
ok(!db->database);
709+
ok(!db->extra_options);
710+
711+
CDB_PARSE("redis:group1://172.31.180.127");
712+
ok(db->flags == 0);
713+
ok(!strcmp(db->scheme, "redis"));
714+
ok(!strcmp(db->group_name, "group1"));
715+
ok(!db->username);
716+
ok(!db->password);
717+
ok(!strcmp(db->host, "172.31.180.127"));
718+
ok(db->port == 0);
719+
ok(!db->database);
720+
ok(!db->extra_options);
721+
722+
CDB_PARSE("redis:group1://172.31.180.127:6379");
723+
ok(db->flags == 0);
724+
ok(!strcmp(db->scheme, "redis"));
725+
ok(!strcmp(db->group_name, "group1"));
726+
ok(!db->username);
727+
ok(!db->password);
728+
ok(!strcmp(db->host, "172.31.180.127"));
729+
ok(db->port == 6379);
730+
ok(!db->database);
731+
ok(!db->extra_options);
732+
733+
CDB_PARSE("redis:group1://[email protected]:6379");
734+
ok(db->flags == 0);
735+
ok(!strcmp(db->username, "user"));
736+
ok(!db->password);
737+
ok(!strcmp(db->host, "172.31.180.127"));
738+
ok(db->port == 6379);
739+
ok(!db->database);
740+
ok(!db->extra_options);
741+
742+
CDB_PARSE("redis:group1://:[email protected]:6379");
743+
ok(db->flags == 0);
703744
ok(!strcmp(db->scheme, "redis"));
704745
ok(!strcmp(db->group_name, "group1"));
705746
ok(!strcmp(db->username, ""));
706-
ok(!strcmp(db->password, "devxxxxxx"));
747+
ok(!strcmp(db->password, "pwd"));
707748
ok(!strcmp(db->host, "172.31.180.127"));
708749
ok(db->port == 6379);
709750
ok(!db->database);
710751
ok(!db->extra_options);
711752

712-
db = new_cachedb_id(_str("redis:group1://:[email protected]:6379/"));
713-
if (!ok(db != NULL))
714-
return;
753+
CDB_PARSE("redis:group1://user:@172.31.180.127:6379");
754+
ok(!strcmp(db->username, "user"));
755+
ok(!strcmp(db->password, ""));
756+
ok(!strcmp(db->host, "172.31.180.127"));
757+
ok(db->port == 6379);
758+
759+
CDB_PARSE("redis:group1://:[email protected]:6379/");
760+
ok(db->flags == 0);
761+
ok(!strcmp(db->username, ""));
762+
ok(!strcmp(db->password, "pwd"));
715763
ok(db->port == 6379);
716764
ok(!db->database);
717765
ok(!db->extra_options);
718766

719-
db = new_cachedb_id(_str("redis:group1://:[email protected]:6379/d?x=1&q=2"));
720-
if (!ok(db != NULL))
721-
return;
767+
CDB_PARSE("redis:group1://:[email protected]:6379/d?x=1&q=2");
768+
ok(db->flags == 0);
769+
ok(!strcmp(db->username, ""));
770+
ok(!strcmp(db->password, "pwd"));
771+
ok(db->port == 6379);
722772
ok(!strcmp(db->database, "d"));
723773
ok(!strcmp(db->extra_options, "x=1&q=2"));
774+
775+
/* multiple hosts tests */
776+
777+
CDB_PARSE("redis:group1://h1,h2,h3");
778+
ok(db->flags == CACHEDB_ID_MULTIPLE_HOSTS);
779+
ok(!db->username);
780+
ok(!db->password);
781+
ok(!strcmp(db->host, "h1,h2,h3"));
782+
ok(db->port == 0);
783+
ok(!db->database);
784+
785+
CDB_PARSE("redis:group1://h1:1,h2:22,h3:333");
786+
ok(db->flags == CACHEDB_ID_MULTIPLE_HOSTS);
787+
ok(!db->username);
788+
ok(!db->password);
789+
ok(!strcmp(db->host, "h1:1,h2:22,h3:333"));
790+
ok(db->port == 0);
791+
ok(!db->database);
792+
793+
CDB_PARSE("redis:group1://h1,h2:22,h3:333");
794+
ok(db->flags == CACHEDB_ID_MULTIPLE_HOSTS);
795+
ok(!db->username);
796+
ok(!db->password);
797+
ok(!strcmp(db->host, "h1,h2:22,h3:333"));
798+
ok(db->port == 0);
799+
ok(!db->database);
800+
801+
CDB_PARSE("redis:group1://h1,h2:22,h3");
802+
ok(db->flags == CACHEDB_ID_MULTIPLE_HOSTS);
803+
ok(!db->username);
804+
ok(!db->password);
805+
ok(!strcmp(db->host, "h1,h2:22,h3"));
806+
ok(db->port == 0);
807+
ok(!db->database);
808+
809+
CDB_PARSE("redis:group1://h1,h2,h3:333");
810+
ok(db->flags == CACHEDB_ID_MULTIPLE_HOSTS);
811+
ok(!db->username);
812+
ok(!db->password);
813+
ok(!strcmp(db->host, "h1,h2,h3:333"));
814+
ok(db->port == 0);
815+
ok(!db->database);
816+
817+
CDB_PARSE("redis:group1://h1,h2,h3:333/");
818+
ok(db->flags == CACHEDB_ID_MULTIPLE_HOSTS);
819+
ok(!db->username);
820+
ok(!db->password);
821+
ok(!strcmp(db->host, "h1,h2,h3:333"));
822+
ok(db->port == 0);
823+
ok(!db->database);
824+
825+
CDB_PARSE("redis:group1://user@h1,h2,h3");
826+
ok(db->flags == CACHEDB_ID_MULTIPLE_HOSTS);
827+
ok(!strcmp(db->username, "user"));
828+
ok(!db->password);
829+
ok(!strcmp(db->host, "h1,h2,h3"));
830+
ok(db->port == 0);
831+
ok(!db->database);
832+
833+
CDB_PARSE("redis:group1://user:pwd@h1,h2,h3");
834+
ok(db->flags == CACHEDB_ID_MULTIPLE_HOSTS);
835+
ok(!strcmp(db->username, "user"));
836+
ok(!strcmp(db->password, "pwd"));
837+
ok(!strcmp(db->host, "h1,h2,h3"));
838+
ok(db->port == 0);
839+
ok(!db->database);
840+
841+
CDB_PARSE("redis:group1://:pwd@h1,h2,h3");
842+
ok(db->flags == CACHEDB_ID_MULTIPLE_HOSTS);
843+
ok(!strcmp(db->username, ""));
844+
ok(!strcmp(db->password, "pwd"));
845+
ok(!strcmp(db->host, "h1,h2,h3"));
846+
ok(db->port == 0);
847+
ok(!db->database);
848+
849+
CDB_PARSE("redis:group1://h1,h2,h3/db");
850+
ok(db->flags == CACHEDB_ID_MULTIPLE_HOSTS);
851+
ok(!db->username);
852+
ok(!db->password);
853+
ok(!strcmp(db->host, "h1,h2,h3"));
854+
ok(db->port == 0);
855+
ok(!strcmp(db->database, "db"));
856+
857+
CDB_PARSE("redis:group1://user:pwd@h1,h2,h3/db");
858+
ok(db->flags == CACHEDB_ID_MULTIPLE_HOSTS);
859+
ok(!strcmp(db->username, "user"));
860+
ok(!strcmp(db->password, "pwd"));
861+
ok(!strcmp(db->host, "h1,h2,h3"));
862+
ok(db->port == 0);
863+
ok(!strcmp(db->database, "db"));
864+
865+
CDB_PARSE("redis:ha://localhost,host_a:6380,host_b:6381,host_c/db");
866+
ok(db->flags == CACHEDB_ID_MULTIPLE_HOSTS);
867+
ok(!strcmp(db->host, "localhost,host_a:6380,host_b:6381,host_c"));
868+
ok(!strcmp(db->database, "db"));
869+
ok(db->port == 0);
870+
871+
CDB_PARSE("redis:group1://:pwd@h1,h2,h3:6379/d");
872+
ok(db->flags == CACHEDB_ID_MULTIPLE_HOSTS);
873+
ok(!strcmp(db->username, ""));
874+
ok(!strcmp(db->password, "pwd"));
875+
ok(!strcmp(db->host, "h1,h2,h3:6379"));
876+
ok(!strcmp(db->database, "d"));
877+
ok(db->port == 0);
724878
}

0 commit comments

Comments
 (0)