summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTad Marshall <tad@10gen.com>2013-03-10 13:34:11 -0400
committerTad Marshall <tad@10gen.com>2013-07-29 13:48:33 -0400
commit031daa05328127af84a0625ab9165a531678fe5d (patch)
tree9dfdc68d3e0851c2fc8d7a1325ad4edb0ef55118
parentad46ea3318bd584ac27cca7b90fe6f68948c2530 (diff)
downloadmongo-031daa05328127af84a0625ab9165a531678fe5d.tar.gz
SERVER-8030 Validate connection string in JavaScript connect() function
Validate that the "URL" passed to the connect() function matches one of the accepted formats (host:port/database, host/database or database) before trying to use it to connect to a server. Change a uassert in HostAndPort::init() to an massert to match the massert four lines above it. Add jstest for connect() validation.
-rw-r--r--jstests/connection_string_validation.js99
-rw-r--r--src/mongo/shell/mongo.js64
-rw-r--r--src/mongo/util/net/hostandport.h2
3 files changed, 148 insertions, 17 deletions
diff --git a/jstests/connection_string_validation.js b/jstests/connection_string_validation.js
new file mode 100644
index 00000000000..fe15ea6808c
--- /dev/null
+++ b/jstests/connection_string_validation.js
@@ -0,0 +1,99 @@
+// Test validation of connection strings passed to the JavaScript "connect()" function.
+// Related to SERVER-8030.
+
+var goodStrings = [
+ "localhost:27999/test",
+ "127.0.0.1:27999/test"
+ ];
+
+var badStrings = [
+ { s: undefined, r: /^Missing connection string$/ },
+ { s: 7, r: /^Incorrect type/ },
+ { s: null, r: /^Incorrect type/ },
+ { s: "", r: /^Empty connection string$/ },
+ { s: " ", r: /^Empty connection string$/ },
+ { s: ":", r: /^Missing host name/ },
+ { s: "/", r: /^Missing host name/ },
+ { s: ":/", r: /^Missing host name/ },
+ { s: ":/test", r: /^Missing host name/ },
+ { s: ":27999/", r: /^Missing host name/ },
+ { s: ":27999/test", r: /^Missing host name/ },
+ { s: "/test", r: /^Missing host name/ },
+ { s: "localhost:/test", r: /^Missing port number/ },
+ { s: "127.0.0.1:/test", r: /^Missing port number/ },
+ { s: "127.0.0.1:cat/test", r: /^Invalid port number/ },
+ { s: "127.0.0.1:1cat/test", r: /^Invalid port number/ },
+ { s: "127.0.0.1:123456/test", r: /^Invalid port number/ },
+ { s: "127.0.0.1:65536/test", r: /^Invalid port number/ },
+ { s: "::1:65536/test", r: /^Invalid port number/ },
+ { s: "127.0.0.1:27999/", r: /^Missing database name/ },
+ { s: "::1:27999/", r: /^Missing database name/ }
+ ];
+
+function testGood(i, connectionString) {
+ print("\nTesting good connection string " + i + " (\"" + connectionString + "\") ...");
+ var gotException = false;
+ var exception;
+ try {
+ var connectDB = connect(connectionString);
+ connectDB = null;
+ }
+ catch (e) {
+ gotException = true;
+ exception = e;
+ }
+ if (!gotException) {
+ print("Good connection string " + i +
+ " (\"" + connectionString + "\") correctly validated");
+ return;
+ }
+ var message = "FAILED to correctly validate goodString " + i +
+ " (\"" + connectionString + "\"): exception was \"" + tojson(exception) + "\"";
+ doassert(message);
+}
+
+function testBad(i, connectionString, errorRegex) {
+ print("\nTesting bad connection string " + i + " (\"" + connectionString + "\") ...");
+ var gotException = false;
+ var gotCorrectErrorText = false;
+ var exception;
+ try {
+ var connectDB = connect(connectionString);
+ connectDB = null;
+ }
+ catch (e) {
+ gotException = true;
+ exception = e;
+ if (errorRegex.test(e.message)) {
+ gotCorrectErrorText = true;
+ }
+ }
+ if (gotCorrectErrorText) {
+ print("Bad connection string " + i + " (\"" + connectionString +
+ "\") correctly rejected:\n" + tojson(exception));
+ return;
+ }
+ var message = "FAILED to generate correct exception for badString " + i +
+ " (\"" + connectionString + "\"): ";
+ if (gotException) {
+ message += "exception was \"" + tojson(exception) +
+ "\", it should have matched \"" + errorRegex.toString() + "\"";
+ }
+ else {
+ message += "no exception was thrown";
+ }
+ doassert(message);
+}
+
+var i;
+jsTest.log("TESTING " + goodStrings.length + " good connection strings");
+for (i = 0; i < goodStrings.length; ++i) {
+ testGood(i, goodStrings[i]);
+}
+
+jsTest.log("TESTING " + badStrings.length + " bad connection strings");
+for (i = 0; i < badStrings.length; ++i) {
+ testBad(i, badStrings[i].s, badStrings[i].r);
+}
+
+jsTest.log("SUCCESSFUL test completion");
diff --git a/src/mongo/shell/mongo.js b/src/mongo/shell/mongo.js
index e4786a7cc17..2f3667f53f3 100644
--- a/src/mongo/shell/mongo.js
+++ b/src/mongo/shell/mongo.js
@@ -98,26 +98,58 @@ Mongo.prototype.getReadPrefTagSet = function () {
return this._readPrefTagSet;
};
-connect = function( url , user , pass ){
- chatty( "connecting to: " + url )
-
- if ( user && ! pass )
- throw "you specified a user and not a password. either you need a password, or you're using the old connect api";
+connect = function(url, user, pass) {
+ if (user && !pass)
+ throw Error("you specified a user and not a password. " +
+ "either you need a password, or you're using the old connect api");
+
+ // Validate connection string "url" as "hostName:portNumber/databaseName"
+ // or "hostName/databaseName"
+ // or "databaseName"
+ // hostName may be an IPv6 address (with colons), in which case ":portNumber" is required
+ //
+ var urlType = typeof url;
+ if (urlType == "undefined") {
+ throw Error("Missing connection string");
+ }
+ if (urlType != "string") {
+ throw Error("Incorrect type \"" + urlType +
+ "\" for connection string \"" + tojson(url) + "\"");
+ }
+ url = url.trim();
+ if (0 == url.length) {
+ throw Error("Empty connection string");
+ }
+ var colon = url.lastIndexOf(":");
+ var slash = url.lastIndexOf("/");
+ if (0 == colon || 0 == slash) {
+ throw Error("Missing host name in connection string \"" + url + "\"");
+ }
+ if (colon == slash - 1 || colon == url.length - 1) {
+ throw Error("Missing port number in connection string \"" + url + "\"");
+ }
+ if (colon != -1 && colon < slash) {
+ var portNumber = url.substring(colon + 1, slash);
+ if (portNumber.length > 5 || !/^\d*$/.test(portNumber) || parseInt(portNumber) > 65535) {
+ throw Error("Invalid port number \"" + portNumber +
+ "\" in connection string \"" + url + "\"");
+ }
+ }
+ if (slash == url.length - 1) {
+ throw Error("Missing database name in connection string \"" + url + "\"");
+ }
- var idx = url.lastIndexOf( "/" );
-
+ chatty("connecting to: " + url)
var db;
-
- if ( idx < 0 )
- db = new Mongo().getDB( url );
+ if (slash == -1)
+ db = new Mongo().getDB(url);
else
- db = new Mongo( url.substring( 0 , idx ) ).getDB( url.substring( idx + 1 ) );
-
- if ( user && pass ){
- if ( ! db.auth( user , pass ) ){
- throw "couldn't login";
+ db = new Mongo(url.substring(0, slash)).getDB(url.substring(slash + 1));
+
+ if (user && pass) {
+ if (!db.auth(user, pass)) {
+ throw Error("couldn't login");
}
}
-
return db;
}
diff --git a/src/mongo/util/net/hostandport.h b/src/mongo/util/net/hostandport.h
index 2d8e435293c..ff47d7f9ef4 100644
--- a/src/mongo/util/net/hostandport.h
+++ b/src/mongo/util/net/hostandport.h
@@ -170,7 +170,7 @@ namespace mongo {
const char *colon = strrchr(p, ':');
if( colon ) {
int port = atoi(colon+1);
- uassert(13095, "HostAndPort: bad port #", port > 0);
+ massert(13095, "HostAndPort: bad port #", port > 0);
_host = string(p,colon-p);
_port = port;
}