Skip to content
This repository has been archived by the owner on May 5, 2023. It is now read-only.

Adding connection string parser. #376

Merged
merged 27 commits into from Oct 10, 2012
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
53 changes: 27 additions & 26 deletions lib/azure.js
Expand Up @@ -26,13 +26,13 @@ exports.TableService = TableService;
* Creates a new TableService object. * Creates a new TableService object.
* If no storageaccount or storageaccesskey are provided, the AZURE_STORAGE_ACCOUNT and AZURE_STORAGE_ACCESS_KEY environment variables will be used. * If no storageaccount or storageaccesskey are provided, the AZURE_STORAGE_ACCOUNT and AZURE_STORAGE_ACCESS_KEY environment variables will be used.
* *
* @param {string} [storageAccount] The storage account. * @param {string} [storageAccountOrConnectionString] The storage account or the connection string.
* @param {string} [storageAccessKey] The storage access key. * @param {string} [storageAccessKey] The storage access key.
* @param {string} [host] The host address. * @param {string} [host] The host address.
* @param {object} [authenticationProvider] The authentication provider. * @param {object} [authenticationProvider] The authentication provider.
*/ */
exports.createTableService = function (storageAccount, storageAccessKey, host, authenticationProvider) { exports.createTableService = function (storageAccountOrConnectionString, storageAccessKey, host, authenticationProvider) {
return new TableService(storageAccount, storageAccessKey, host, authenticationProvider); return new TableService(storageAccountOrConnectionString, storageAccessKey, host, authenticationProvider);
}; };


/** /**
Expand All @@ -46,13 +46,13 @@ exports.BlobService = BlobService;
* Creates a new BlobService object. * Creates a new BlobService object.
* If no storageaccount or storageaccesskey are provided, the AZURE_STORAGE_ACCOUNT and AZURE_STORAGE_ACCESS_KEY environment variables will be used. * If no storageaccount or storageaccesskey are provided, the AZURE_STORAGE_ACCOUNT and AZURE_STORAGE_ACCESS_KEY environment variables will be used.
* *
* @param {string} [storageAccount] The storage account. * @param {string} [storageAccountOrConnectionString] The storage account or the connection string.
* @param {string} [storageAccessKey] The storage access key. * @param {string} [storageAccessKey] The storage access key.
* @param {string} [host] The host address. * @param {string} [host] The host address.
* @param {object} [authenticationProvider] The authentication provider. * @param {object} [authenticationProvider] The authentication provider.
*/ */
exports.createBlobService = function (storageAccount, storageAccessKey, host, authenticationProvider) { exports.createBlobService = function (storageAccountOrConnectionString, storageAccessKey, host, authenticationProvider) {
return new BlobService(storageAccount, storageAccessKey, host, authenticationProvider); return new BlobService(storageAccountOrConnectionString, storageAccessKey, host, authenticationProvider);
}; };


/** /**
Expand All @@ -67,13 +67,13 @@ exports.QueueService = QueueService;
* If no storageAccount or storageAccessKey are provided, the AZURE_STORAGE_ACCOUNT and AZURE_STORAGE_ACCESS_KEY * If no storageAccount or storageAccessKey are provided, the AZURE_STORAGE_ACCOUNT and AZURE_STORAGE_ACCESS_KEY
* environment variables will be used. * environment variables will be used.
* *
* @param {string} [storageAccount] The storage account. * @param {string} [storageAccountOrConnectionString] The storage account or the connection string.
* @param {string} [storageAccessKey] The storage access key. * @param {string} [storageAccessKey] The storage access key.
* @param {string} [host] The host address. * @param {string} [host] The host address.
* @param {object} [authenticationProvider] The authentication provider. * @param {object} [authenticationProvider] The authentication provider.
*/ */
exports.createQueueService = function (storageAccount, storageAccessKey, host, authenticationProvider) { exports.createQueueService = function (storageAccountOrConnectionString, storageAccessKey, host, authenticationProvider) {
return new QueueService(storageAccount, storageAccessKey, host, authenticationProvider); return new QueueService(storageAccountOrConnectionString, storageAccessKey, host, authenticationProvider);
}; };


/** /**
Expand All @@ -86,15 +86,15 @@ exports.ServiceBusService = ServiceBusService;
/** /**
* Creates a new ServiceBusService object. * Creates a new ServiceBusService object.
* *
* @param {string} [namespace] The service bus namespace. * @param {string} [namespaceOrConnectionString] The service bus namespace.
* @param {string} [accessKey] The password. * @param {string} [accessKey] The password.
* @param {string} [issuer] The issuer. * @param {string} [issuer] The issuer.
* @param {string} [acsNamespace] The acs namespace. Usually the same as the sb namespace with "-sb" suffix. * @param {string} [acsNamespace] The acs namespace. Usually the same as the sb namespace with "-sb" suffix.
* @param {string} [host] The host address. * @param {string} [host] The host address.
* @param {object} [authenticationProvider] The authentication provider. * @param {object} [authenticationProvider] The authentication provider.
*/ */
exports.createServiceBusService = function (namespace, accessKey, issuer, acsNamespace, host, authenticationProvider) { exports.createServiceBusService = function (namespaceOrConnectionString, accessKey, issuer, acsNamespace, host, authenticationProvider) {
return new ServiceBusService(namespace, accessKey, issuer, acsNamespace, host, authenticationProvider); return new ServiceBusService(namespaceOrConnectionString, accessKey, issuer, acsNamespace, host, authenticationProvider);
}; };


/** /**
Expand Down Expand Up @@ -149,6 +149,7 @@ exports.SharedKeyTable = require('./services/table/sharedkeytable');
exports.SharedKeyLiteTable = require('./services/table/sharedkeylitetable'); exports.SharedKeyLiteTable = require('./services/table/sharedkeylitetable');
exports.ISO8061Date = require('./util/iso8061date'); exports.ISO8061Date = require('./util/iso8061date');
exports.Logger = require('./diagnostics/logger'); exports.Logger = require('./diagnostics/logger');
exports.ConnectionStringParser = require('./services/core/connectionstringparser');


/* /*
* Convenience functions. * Convenience functions.
Expand Down
12 changes: 6 additions & 6 deletions lib/services/blob/blobservice.js
Expand Up @@ -70,12 +70,12 @@ BlobService.incorrectEndByteOffsetErr = 'End byte offset must be a modulus of 51
* @constructor * @constructor
* @extends {ServiceClient} * @extends {ServiceClient}
* *
* @param {string} [storageAccount] The storage account. * @param {string} [storageAccountOrConnectionString] The storage account or the connection string.
* @param {string} [storageAccessKey] The storage access key. * @param {string} [storageAccessKey] The storage access key.
* @param {string} [host] The host address. * @param {string} [host] The host address.
* @param {object} [authenticationProvider] The authentication provider. * @param {object} [authenticationProvider] The authentication provider.
*/ */
function BlobService(storageAccount, storageAccessKey, host, authenticationProvider) { function BlobService(storageAccountOrConnectionString, storageAccessKey, host, authenticationProvider) {
if (!host) { if (!host) {
if (ServiceClient.isEmulated()) { if (ServiceClient.isEmulated()) {
host = ServiceClient.DEVSTORE_BLOB_HOST; host = ServiceClient.DEVSTORE_BLOB_HOST;
Expand All @@ -84,7 +84,7 @@ function BlobService(storageAccount, storageAccessKey, host, authenticationProvi
} }
} }


BlobService.super_.call(this, host, storageAccount, storageAccessKey, authenticationProvider); BlobService.super_.call(this, storageAccountOrConnectionString, storageAccessKey, host, authenticationProvider);


if (!this.authenticationProvider) { if (!this.authenticationProvider) {
this.authenticationProvider = new SharedKey(this.storageAccount, this.storageAccessKey, this.usePathStyleUri); this.authenticationProvider = new SharedKey(this.storageAccount, this.storageAccessKey, this.usePathStyleUri);
Expand Down
217 changes: 217 additions & 0 deletions lib/services/core/connectionstringparser.js
@@ -0,0 +1,217 @@
/**
* Copyright (c) Microsoft. All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

var util = require('../../util/util');

// Expose 'ConnectionStringParser'.
exports = module.exports;

/**
* Creates a new 'ConnectionString' instance.
*
* @constructor
* @param {string} connectionString The connection string to be parsed.
*/
function ConnectionStringParser(connectionString) {
this._value = connectionString;
this._pos = 0;
this._state = 'ExpectKey';
}

/**
* Parses a connection string into an object.
*
* @return {object} The query string object.
*/
ConnectionStringParser.prototype._parse = function () {
var key = null;
var value = null;
var parsedConnectionString = { };

for (; ;) {
this._skipWhitespaces();

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 string until the given quotation mark.
*
* @param {string} quote Quotation mark terminating the string.
* @return {string} string.
*/
ConnectionStringParser.prototype._extractString = function (quote) {
var firstPos = this._pos;
while (this._pos < this._value.length && this._value[this._pos] !== quote)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a way to escape quotes within a quoted string? If so then this needs to be a little more complex to handle that case. If not, you're good.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nop.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

{
this._pos++;
}

if (this._pos === this._value.length) {
// Runaway string.
throw new Error('Unterminated string starting at position ' + firstPos);
}

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('expecting ' + operatorChar + ' but instead got ' + currentChar + ' at position ' + this._pos);

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's no currentChar variable - you should probably define one, or replace with the full expression.

}

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 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();
};
3 changes: 1 addition & 2 deletions lib/services/core/servicebusserviceclient.js
Expand Up @@ -33,12 +33,11 @@ exports = module.exports = ServiceBusServiceClient;
* Creates a new ServiceBusServiceClient object. * Creates a new ServiceBusServiceClient object.
* *
* @constructor * @constructor
* @param {string} host The host for the service. * @param {string} host The host for the service.
* @param {string} [namespace] The service bus namespace. * @param {string} [namespace] The service bus namespace.
* @param {string} [accessKey] The password. * @param {string} [accessKey] The password.
* @param {string} [issuer] The issuer. * @param {string} [issuer] The issuer.
* @param {string} [acsNamespace] The acs namespace. Usually the same as the sb namespace with "-sb" suffix. * @param {string} [acsNamespace] The acs namespace. Usually the same as the sb namespace with "-sb" suffix.
* @param {string} [host] The host address.
* @param {object} [authenticationProvider] The authentication provider. * @param {object} [authenticationProvider] The authentication provider.
*/ */
function ServiceBusServiceClient(host, namespace, accessKey, issuer, acsNamespace, authenticationProvider) { function ServiceBusServiceClient(host, namespace, accessKey, issuer, acsNamespace, authenticationProvider) {
Expand Down
6 changes: 4 additions & 2 deletions lib/services/core/serviceclient.js
Expand Up @@ -109,9 +109,11 @@ function ServiceClient(host, authenticationProvider) {
var parsedHost = this._parseHost(host); var parsedHost = this._parseHost(host);
this.host = parsedHost.hostname; this.host = parsedHost.hostname;
this.port = parsedHost.port; this.port = parsedHost.port;
this.protocol = parsedHost.protocol + '//'; if (!this.protocol) {
this.protocol = parsedHost.protocol + '//';
}
} }
else { else if (!this.protocol) {
this.protocol = ServiceClient.DEFAULT_PROTOCOL; this.protocol = ServiceClient.DEFAULT_PROTOCOL;
} }


Expand Down