Skip to content

Commit

Permalink
cachedb_mongodb: Allow specifying URL options
Browse files Browse the repository at this point in the history
This patch allows script writers to append essential connect string
options near the end of a cachedb_mongodb URL, such as:

    * ?replSet=mongo-set-1
    * ?readConcernLevel=local

Consult the MongoDB connect string docs for a full listing of available
URL options.

Reported by Vasilios Tzanoudakis
Fixes #1656

(cherry picked from commit 887f9f0)
  • Loading branch information
liviuchircu committed Apr 19, 2019
1 parent 32d3163 commit 9d82861
Show file tree
Hide file tree
Showing 4 changed files with 58 additions and 45 deletions.
64 changes: 37 additions & 27 deletions cachedb/cachedb_id.c
Expand Up @@ -55,7 +55,7 @@ static int dupl_string(char** dst, const char* begin, const char* end)

/**
* Parse a database URL of form
* scheme[:group]://[username[:password]@]hostname[:port]/database
* scheme[:group]://[username[:password]@]hostname[:port]/database[?options]
*
* \param id filled id struct
* \param url parsed URL
Expand All @@ -76,7 +76,8 @@ static int parse_cachedb_url(struct cachedb_id* id, const str* url)
ST_HOST, /* Hostname part */
ST_HOST6, /* Hostname part IPv6 */
ST_PORT, /* Port part */
ST_DB /* Database part */
ST_DB, /* Database part */
ST_OPTIONS /* Options part */
};

enum state st;
Expand Down Expand Up @@ -176,12 +177,9 @@ static int parse_cachedb_url(struct cachedb_id* id, const str* url)

case '/':
if (dupl_string(&id->host, begin, url->s + i) < 0) goto err;
if (url->s+i+1 == url->s + len) {
st = ST_DB;
break;
}
if (dupl_string(&id->database, url->s + i + 1, url->s + len) < 0) goto err;
return 0;
begin = url->s + i + 1;
st = ST_DB;
break;
}
break;

Expand All @@ -197,12 +195,10 @@ static int parse_cachedb_url(struct cachedb_id* id, const str* url)
case '/':
id->host = prev_token;
id->port = str2s(begin, url->s + i - begin, 0);
if (url->s+i+1 == url->s + len) {
st = ST_DB;
break;
}
if (dupl_string(&id->database, url->s + i + 1, url->s + len) < 0) goto err;
return 0;
begin = url->s + i + 1;
st = ST_DB;
break;

case ',':
st=ST_HOST;
start_host=start_prev;
Expand Down Expand Up @@ -238,12 +234,9 @@ static int parse_cachedb_url(struct cachedb_id* id, const str* url)
ptr = begin;

if (dupl_string(&id->host, ptr, url->s + i - ipv6_flag) < 0) goto err;
if (url->s+i+1 == url->s + len) {
st = ST_DB;
break;
}
if (dupl_string(&id->database, url->s + i + 1, url->s + len) < 0) goto err;
return 0;
begin = url->s + i + 1;
st = ST_DB;
break;
}
break;

Expand All @@ -260,12 +253,10 @@ static int parse_cachedb_url(struct cachedb_id* id, const str* url)
switch(url->s[i]) {
case '/':
id->port = str2s(begin, url->s + i - begin, 0);
if (url->s+i+1 == url->s + len) {
st = ST_DB;
break;
}
if (dupl_string(&id->database, url->s + i + 1, url->s + len) < 0) goto err;
return 0;
begin = url->s + i + 1;
st = ST_DB;
break;

case ',':
st = ST_HOST;
pkg_free(id->host);
Expand All @@ -274,12 +265,31 @@ static int parse_cachedb_url(struct cachedb_id* id, const str* url)
id->flags |= CACHEDB_ID_MULTIPLE_HOSTS;
break;
}
break;

case ST_DB:
switch(url->s[i]) {
case '?':
if (dupl_string(&id->database, begin, url->s + i) < 0) goto err;
if (url->s + i + 1 == url->s + len) {
st = ST_OPTIONS;
break;
}
if (dupl_string(&id->extra_options, url->s + i + 1, url->s + len) < 0) goto err;
return 0;
}
break;

case ST_OPTIONS:
break;
}
}

if (st == ST_DB) {
if (dupl_string(&id->database, begin, url->s + len) < 0) goto err;
return 0;
}

if (st == ST_USER_HOST && begin == url->s+url->len) {
/* Not considered an error - to cope with modules that
* offer cacheDB functionality backed up by OpenSIPS mem */
Expand All @@ -288,7 +298,7 @@ static int parse_cachedb_url(struct cachedb_id* id, const str* url)
return 0;
}

if (st != ST_DB) goto err;
if (st != ST_DB && st != ST_OPTIONS) goto err;
return 0;

err:
Expand Down
1 change: 1 addition & 0 deletions cachedb/cachedb_id.h
Expand Up @@ -37,6 +37,7 @@ struct cachedb_id {
char* host; /**< Host or IP, case insensitive */
unsigned short port; /**< Port number */
char* database; /**< Database, case sensitive */
char* extra_options; /**< Extra Options */
char* initial_url; /**< Initial full URL */
int flags; /**< Flags for signaling various events */
};
Expand Down
2 changes: 1 addition & 1 deletion modules/cachedb_mongodb/cachedb_mongodb.c
Expand Up @@ -41,7 +41,7 @@ static int child_init(int);
static void destroy(void);

static str cache_mod_name = str_init("mongodb");
struct cachedb_url *mongodb_script_urls = NULL;
struct cachedb_url *mongodb_script_urls;

int mongo_exec_threshold=0;

Expand Down
36 changes: 19 additions & 17 deletions modules/cachedb_mongodb/cachedb_mongodb_dbase.c
Expand Up @@ -76,6 +76,7 @@ static char *build_mongodb_connect_string(struct cachedb_id *id)
strlen(id->host) + 1 +
5 + 1 + /* port */
strlen(id->database) + 1 +
(id->extra_options ? strlen(id->extra_options) : 0) + 1 +
1;

ret = pkg_malloc(len);
Expand All @@ -90,23 +91,20 @@ static char *build_mongodb_connect_string(struct cachedb_id *id)
else
db_len = strlen(id->database);

if (id->username && id->password) {
if (id->port == 0) {
sprintf(ret, "mongodb://%s:%s@%s/%.*s", id->username, id->password,
id->host, db_len, id->database);
} else {
sprintf(ret, "mongodb://%s:%s@%s:%d/%.*s", id->username, id->password,
id->host, id->port, db_len, id->database);
}
len = sprintf(ret, "mongodb://");

} else {
if (id->port == 0) {
sprintf(ret, "mongodb://%s/%.*s", id->host, db_len, id->database);
} else {
sprintf(ret, "mongodb://%s:%d/%.*s", id->host, id->port,
db_len, id->database);
}
}
if (id->username && id->password)
len += sprintf(ret + len, "%s:%s@", id->username, id->password);

len += sprintf(ret + len, "%s", id->host);

if (id->port != 0)
len += sprintf(ret + len, ":%d", id->port);

len += sprintf(ret + len, "/%.*s", db_len, id->database);

if (id->extra_options)
sprintf(ret + len, "?%s", id->extra_options);

return ret;
}
Expand Down Expand Up @@ -147,7 +145,8 @@ mongo_con* mongo_new_connection(struct cachedb_id* id)

p = memchr(id->database, '.', strlen(id->database));
if (!p) {
LM_ERR("malformed Mongo database part in %s\n", id->database);
LM_ERR("MongoDB URL is missing the '/DB.collection' construct, only "
"have '/DB' so far: /%s\n", id->database);
return NULL;
}

Expand All @@ -159,6 +158,9 @@ mongo_con* mongo_new_connection(struct cachedb_id* id)
return NULL;
}

LM_DBG("db: '%s', col: '%s', options: '%s'\n",
con->db, con->col, id->extra_options);

con->database = mongoc_client_get_database(con->client, id->database);
con->collection = mongoc_client_get_collection(con->client, id->database, p+1);
*p = '.';
Expand Down

0 comments on commit 9d82861

Please sign in to comment.