Skip to content

Commit 037a7d6

Browse files
committed
feat: Fix for issue#663
Signed-off-by: jaishirole <[email protected]>
1 parent 5936ba0 commit 037a7d6

File tree

3 files changed

+329
-74
lines changed

3 files changed

+329
-74
lines changed

lib/mongodb.js

Lines changed: 98 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -332,13 +332,11 @@ MongoDB.prototype.connect = function(callback) {
332332
if (callback) callback(err);
333333
}
334334

335-
const urlObj = new URL(self.settings.url);
336-
337-
if ((urlObj.pathname === '' ||
338-
urlObj.pathname.split('/')[1] === '') &&
339-
typeof self.settings.database === 'string') {
340-
urlObj.pathname = self.settings.database;
341-
self.settings.url = urlObj.toString();
335+
// This is special processing if database is not part of url, but is in settings
336+
if (self.settings.database && self.settings.url) {
337+
if ((self.settings.url.indexOf('/' + self.settings.database) === -1) && (self.settings.url.indexOf('authSource=' + self.settings.database) === -1)) {
338+
self.settings.url = processMongoDBURL(self.settings.database, self.settings.url);
339+
}
342340
}
343341

344342
new mongodb.MongoClient(self.settings.url, validOptions).connect(function(
@@ -2118,6 +2116,99 @@ MongoDB.prototype.rollback = function(tx, cb) {
21182116
});
21192117
};
21202118

2119+
exports.processMongoDBURL = processMongoDBURL;
2120+
/**
2121+
* This method parses a Mongo connection url string and refers the formats
2122+
* specified at: https://www.mongodb.com/docs/manual/reference/connection-string/.
2123+
* Since there are cases where database is not specified in the url, but as a settings property,
2124+
* the code has to reflect that in the url otherwise the MongoDB driver defaults to 'admin' db.
2125+
* @param {string} settingsDatabase - the database that will be added if url doesn't have a db specified
2126+
* @param {string} mongoUrl - the url to be processed for database manipulation
2127+
*/
2128+
function processMongoDBURL(settingsDatabase, mongoUrl) {
2129+
// Reference: https://www.mongodb.com/docs/manual/reference/connection-string/
2130+
// Standard format::: mongodb://[username:password@]host1[:port1][,...hostN[:portN]][/[defaultauthdb][?options]]
2131+
// DNS SeedList format::: mongodb+srv://server.example.com/?connectTimeoutMS=300000&authSource=aDifferentAuthDB
2132+
// Actual replicaset example::: mongodb://mongodb1.example.com:27317,mongodb2.example.com:27017/?connectTimeoutMS=300000&replicaSet=mySet&authSource=aDifferentAuthDB
2133+
2134+
if (mongoUrl) {
2135+
// 1. Know the protocol
2136+
let baseUrl = '';
2137+
if (mongoUrl.startsWith('mongodb:'))
2138+
baseUrl = 'mongodb://';
2139+
else if (mongoUrl.startsWith('mongodb+srv:'))
2140+
baseUrl = 'mongodb+srv://';
2141+
2142+
let remainderUrl = mongoUrl.substring(baseUrl.length);
2143+
// 2. Check if userId/password is present
2144+
let uidPassword = '';
2145+
if (remainderUrl.indexOf('@') !== -1) {
2146+
const parts = remainderUrl.split('@');
2147+
uidPassword = parts[0];
2148+
if (parts.length === 2)
2149+
remainderUrl = parts[1];
2150+
else
2151+
remainderUrl = '';
2152+
}
2153+
let hosts = '';
2154+
let dbName = '';
2155+
let options = '';
2156+
let hostsArray = [];
2157+
// 3. Check if comma separated replicas are specified
2158+
if (remainderUrl.indexOf(',') !== -1) {
2159+
hostsArray = remainderUrl.split(',');
2160+
remainderUrl = hostsArray[hostsArray.length - 1];
2161+
}
2162+
2163+
// 4. Check if authDB is specified in the URL
2164+
const slashIndex = remainderUrl.indexOf('/');
2165+
if ((slashIndex !== -1)) {
2166+
if (slashIndex !== (remainderUrl.length - 1)) {
2167+
const optionsIndex = remainderUrl.indexOf('?');
2168+
if (optionsIndex !== -1) {
2169+
options = remainderUrl.substring(optionsIndex + 1);
2170+
dbName = remainderUrl.substring(slashIndex + 1, optionsIndex);
2171+
} else {
2172+
// No DB options specified
2173+
dbName = remainderUrl.substring(slashIndex + 1);
2174+
}
2175+
}
2176+
2177+
if (hostsArray.length > 1) {
2178+
const newHosts = hostsArray;
2179+
newHosts.pop();
2180+
newHosts.push(remainderUrl.substring(0, slashIndex));
2181+
hosts = newHosts.join(',');
2182+
} else {
2183+
hosts = remainderUrl.substring(0, slashIndex);
2184+
}
2185+
} else {
2186+
// No database specified
2187+
if (hostsArray.length > 1)
2188+
hosts = hostsArray.join(',');
2189+
else
2190+
hosts = remainderUrl;
2191+
}
2192+
2193+
// 5. Reconstruct url, but this time add database from settings if URL didn't have it
2194+
// The below code has an overlap with generateMongoDBURL()
2195+
let modifiedUrl = baseUrl;
2196+
2197+
if (uidPassword)
2198+
modifiedUrl += uidPassword + '@';
2199+
if (hosts)
2200+
modifiedUrl += hosts;
2201+
2202+
modifiedUrl += '/' + (dbName ? dbName : settingsDatabase);
2203+
2204+
if (options)
2205+
modifiedUrl += '?' + options;
2206+
2207+
return modifiedUrl;
2208+
}
2209+
return mongoUrl;
2210+
}
2211+
21212212
function isInTransation(options) {
21222213
const ops = {};
21232214
if (options && options.transaction && options.transaction.isInTransation)

0 commit comments

Comments
 (0)