Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Merge branch 'connectionStrings' into storageconnect

  • Loading branch information...
commit fa460df4872b5bce88d854a7ccdabbb052d08014 2 parents f4a5d70 + cc96782
@andrerod andrerod authored
View
208 lib/services/core/connectionstringparser.js
@@ -16,27 +16,18 @@
var util = require('../../util/util');
// Expose 'ConnectionStringParser'.
-exports = module.exports = ConnectionStringParser;
-
-/**
-* Parses a connection string.
-*
-* @param {number} connectionString The connection string to be parsed.
-* @return {object} The query string object.
-*/
-ConnectionStringParser.parse = function (connectionString) {
- var connectionStringParser = new ConnectionStringParser(connectionString);
- return connectionStringParser._parse();
-};
+exports = module.exports;
/**
* Creates a new 'ConnectionString' instance.
*
* @constructor
-* @param {number} connectionString The connection string to be parsed.
+* @param {string} connectionString The connection string to be parsed.
*/
function ConnectionStringParser(connectionString) {
- this._connectionString = connectionString;
+ this._value = connectionString;
+ this._pos = 0;
+ this._state = 'ExpectKey';
}
/**
@@ -45,41 +36,182 @@ function ConnectionStringParser(connectionString) {
* @return {object} The query string object.
*/
ConnectionStringParser.prototype._parse = function () {
- var self = this;
- var parts = this._connectionString.split(';');
+ var key = null;
+ var value = null;
var parsedConnectionString = { };
- parts.forEach(function (part) {
- part = part.trim();
+ for (; ;) {
+ this._skipWhitespaces();
- if (part) {
- var currentKVP = part.split('=');
- if (currentKVP.length === 2) {
- if (currentKVP[0].length > 0) {
- parsedConnectionString[self._getValue(currentKVP[0].toLowerCase())] = self._getValue(currentKVP[1]);
- } else {
- throw new Error('Invalid key');
- }
- } else {
- throw new Error('Invalid connection string');
- }
+ if (this._pos === this._value.length && this._state !== 'ExpectValue')
+ {
+ // Not stopping after the end has been reached and a value is expected
+ // results in creating an empty value, which we expect.
+ break;
}
- });
+
+ switch (this._state) {
+ case 'ExpectKey':
+ key = this._extractKey();
+ this._state = 'ExpectAssignment';
+ break;
+
+ case 'ExpectAssignment':
+ this._skipOperator('=');
+ this._state = 'ExpectValue';
+ break;
+
+ case 'ExpectValue':
+ value = this._extractValue();
+ this._state = 'ExpectSeparator';
+ parsedConnectionString[key.toLowerCase()] = value;
+ key = null;
+ value = null;
+ break;
+
+ default:
+ this._skipOperator(';');
+ this._state = 'ExpectKey';
+ break;
+ }
+ }
+
+ if (this._state === 'ExpectAssignment') {
+ // Must end parsing in the valid state (expected key or separator)
+ throw new Error('Missing character "="');
+ }
return parsedConnectionString;
};
+
+/**
+* Skips whitespaces at the current position.
+*/
+ConnectionStringParser.prototype._skipWhitespaces = function () {
+ while (this._pos < this._value.length && this._value[this._pos] === ' ')
+ {
+ this._pos++;
+ }
+};
+
+/**
+* Extracts key at the current position.
+*
+* @return {string} Key.
+*/
+ConnectionStringParser.prototype._extractKey = function () {
+ var key = null;
+ var firstPos = this._pos;
+ var ch = this._value[this._pos++];
+
+ if (ch === '"' || ch === '\'') {
+ key = this._extractString(ch);
+ } else if (ch === ';' || ch === '=') {
+ // Key name was expected.
+ throw new Error('Missing key');
+ } else {
+ while (this._pos < this._value.length) {
+ ch = this._value[this._pos];
+ if (ch === '=') {
+ break;
+ }
+ this._pos++;
+ }
+
+ key = this._value.substring(firstPos, this._pos);
+ }
+
+ if (key.length === 0) {
+ // Empty key name.
+ throw new Error('Empty key name');
+ }
+
+ return key;
+};
+
/**
-* Extracts the actual value from a possibly quotes value.
+* Extracts the string until the given quotation mark.
*
-* @param {string} str The quoted or unquoted value.
-* @return {string} The value.
+* @param {string} quote Quotation mark terminating the string.
+* @return {string} string.
*/
-ConnectionStringParser.prototype._getValue = function (str) {
- if ((util.stringStartsWith(str, '"') && util.stringEndsWith(str, '"')) ||
- (util.stringStartsWith(str, '\'') && util.stringEndsWith(str, '\''))) {
- return str.substring(1, str.length - 1);
+ConnectionStringParser.prototype._extractString = function (quote) {
+ var firstPos = this._pos;
+ while (this._pos < this._value.length && this._value[this._pos] !== quote)
+ {
+ this._pos++;
+ }
+
+ if (this._pos === this._value.length) {
+ // Runaway string.
+ throw new Error('Invalid string');
+ }
+
+ return this._value.substring(firstPos, this._pos++);
+};
+
+/**
+* Skips specified operator.
+*
+* @param {string} operatorChar The oeprator to skip.
+*/
+ConnectionStringParser.prototype._skipOperator = function (operatorChar) {
+ if (this._value[this._pos] != operatorChar) {
+ // Character was expected.
+ throw new Error('Character not expected ' + operatorChar);
+ }
+
+ this._pos++;
+};
+
+/**
+* Extracts key's value.
+*
+* @return {string} The key value.
+*/
+ConnectionStringParser.prototype._extractValue = function () {
+ var value = '';
+
+ if (this._pos < this._value.length) {
+ var ch = this._value[this._pos];
+
+ if (ch === '\'' || ch === '"') {
+ this._pos++;
+ value = this._extractString(ch);
+ } else {
+ var firstPos = this._pos;
+ var isFound = false;
+
+ while (this._pos < this._value.length && !isFound) {
+ ch = this._value[this._pos];
+
+ switch (ch) {
+ case ';':
+ isFound = true;
+ break;
+
+
+ default:
+ this._pos++;
+ break;
+ }
+ }
+
+ value = this._value.substring(firstPos, this._pos);
+ }
}
- return str;
+ return value;
+};
+
+/**
+* Parses a connection string.
+*
+* @param {number} connectionString The connection string to be parsed.
+* @return {object} The query string object.
+*/
+exports.parse = function (connectionString) {
+ var connectionStringParser = new ConnectionStringParser(connectionString);
+ return connectionStringParser._parse();
};
View
37 test/services/core/connectionstringparser-tests.js
@@ -49,7 +49,12 @@ suite('connectionstringparser-tests', function () {
function() {
var parsedConnectionString = ConnectionStringParser.parse('Endpoint');
},
- Error
+ function(err) {
+ if ((err instanceof Error) && err.message === 'Missing character "="') {
+ return true;
+ }
+ },
+ "unexpected error"
);
done();
@@ -60,26 +65,48 @@ suite('connectionstringparser-tests', function () {
function() {
var parsedConnectionString = ConnectionStringParser.parse('=value');
},
- Error
+ function(err) {
+ if ((err instanceof Error) && err.message === 'Missing key') {
+ return true;
+ }
+ },
+ "unexpected error"
);
assert.throws(
function() {
var parsedConnectionString = ConnectionStringParser.parse(' =value');
},
- Error
+ function(err) {
+ if ((err instanceof Error) && err.message === 'Missing key') {
+ return true;
+ }
+ },
+ "unexpected error"
);
done();
});
test('parseQuotedValues', function (done) {
- var parsedConnectionString = ConnectionStringParser.parse('"test"=\'value\'');
- assert.equal(parsedConnectionString['test'], 'value');
+ var parsedConnectionString = ConnectionStringParser.parse('"test key"=\'value of test\'');
+ assert.equal(parsedConnectionString['test key'], 'value of test');
var parsedConnectionString = ConnectionStringParser.parse('\'test\'="value"');
assert.equal(parsedConnectionString['test'], 'value');
done();
});
+
+ test('connectionStringWithSpecialCharacters', function (done) {
+ var parsedConnectionString = ConnectionStringParser.parse('key1=qwdwdqdw=@#!@;key2=value2');
+ assert.equal(parsedConnectionString['key1'], 'qwdwdqdw=@#!@');
+ assert.equal(parsedConnectionString['key2'], 'value2');
+
+ var parsedConnectionString = ConnectionStringParser.parse('key1="qwd;wdqdw=@#!@";key2=value2');
+ assert.equal(parsedConnectionString['key1'], 'qwd;wdqdw=@#!@');
+ assert.equal(parsedConnectionString['key2'], 'value2');
+
+ done();
+ });
});
View
1  test/testlist.txt
@@ -9,6 +9,7 @@ services/blob/sharedaccesssignature-tests.js
services/blob/sharedkey-tests.js
services/blob/sharedkeylite-tests.js
services/blob/filters-tests.js
+services/core/connectionstringparser-tests.js
services/core/serviceclient-tests.js
services/core/exponentialretrypolicyfilter-tests.js
services/core/linearretrypolicyfilter-tests.js
Please sign in to comment.
Something went wrong with that request. Please try again.