Permalink
Browse files

Merge pull request #564 from andrerod/dev

#499: Make generating blob URL with SAS easier
  • Loading branch information...
2 parents db8ff69 + 596e056 commit 2712ccb9b28126513faec5c0a8b4f36cab228ac2 André Rodrigues committed Jan 30, 2013
@@ -82,7 +82,7 @@ PushpinService.prototype.createPushpin = function (pushpinData, pushpinImage, ca
entity.PartitionKey = DEFAULT_PARTITION;
if (blob) {
- entity.imageUrl = self.blobClient.getBlobUrl(blob.container, blob.blob).url();
+ entity.imageUrl = self.blobClient.getBlobUrl(blob.container, blob.blob);
}
self.tableClient.insertEntity(TABLE_NAME, entity, callback);
@@ -31,7 +31,7 @@ EventService.prototype = {
res.render('detail', {
title: eventItem.name,
eventItem: eventItem,
- imageUrl: self.blobClient.getBlobUrl('photos', eventItem.RowKey).url(),
+ imageUrl: self.blobClient.getBlobUrl('photos', eventItem.RowKey),
});
}
});
@@ -146,7 +146,7 @@ exports.createOrEditRole = function (roleData, roleImage, callback) {
function insertOrUpdateEntity(error, role) {
if (role) {
- roleData.imageUrl = blobClient.getBlobUrl(role.container, role.blob).url();
+ roleData.imageUrl = blobClient.getBlobUrl(role.container, role.blob);
}
if (!_.isUndefined(roleData.RowKey) && !_.isUndefined(roleData.PartitionKey)) {
View
@@ -208,6 +208,8 @@ exports.ServiceBusSettings = require('./services/core/servicebussettings');
exports.ServiceManagementSettings = require('./services/core/servicemanagementsettings');
exports.Validate = require('./util/validate');
+exports.date = require('./util/date');
+
/*
* Convenience functions.
*/
@@ -2142,7 +2142,7 @@ BlobService.prototype.listBlobBlocks = function (container, blob, blocklisttype,
* @param {string} [blob] The blob name.
* @param {object} sharedAccessPolicy The shared access policy.
* @param {string} [sharedAccessPolicy.Id] The signed identifier.
-* @param {SharedAccessPermissions} sharedAccessPolicy.AccessPolicy.Permissions The permission type.
+* @param {object} [sharedAccessPolicy.AccessPolicy.Permissions] The permission type.
* @param {date|string} [sharedAccessPolicy.AccessPolicy.Start] The time at which the Shared Access Signature becomes valid (The UTC value will be used).
* @param {date|string} sharedAccessPolicy.AccessPolicy.Expiry The time at which the Shared Access Signature becomes expired (The UTC value will be used).
* @return {object} An object with the shared access signature.
@@ -2156,6 +2156,10 @@ BlobService.prototype.generateSharedAccessSignature = function (container, blob,
resourceType = BlobConstants.ResourceTypes.BLOB;
}
+ if (azureutil.objectIsNull(sharedAccessPolicy.AccessPolicy.Permissions)) {
+ sharedAccessPolicy.AccessPolicy.Permissions = BlobConstants.SharedAccessPermissions.READ;
+ }
+
if (!azureutil.objectIsNull(sharedAccessPolicy.AccessPolicy.Start)) {
sharedAccessPolicy.AccessPolicy.Start = ISO8061Date.format(sharedAccessPolicy.AccessPolicy.Start, true);
}
@@ -2186,24 +2190,29 @@ BlobService.prototype.generateSharedAccessSignature = function (container, blob,
* @this {BlobService}
* @param {string} container The container name.
* @param {string} [blob] The blob name.
+* @param {object} [sharedAccessPolicy] The shared access policy.
+* @param {string} [sharedAccessPolicy.Id] The signed identifier.
+* @param {object} [sharedAccessPolicy.AccessPolicy.Permissions] The permission type.
+* @param {date|string} [sharedAccessPolicy.AccessPolicy.Start] The time at which the Shared Access Signature becomes valid (The UTC value will be used).
+* @param {date|string} sharedAccessPolicy.AccessPolicy.Expiry The time at which the Shared Access Signature becomes expired (The UTC value will be used).
* @return {object} An object with the blob URL.
*/
-BlobService.prototype.getBlobUrl = function (container, blob) {
+BlobService.prototype.getBlobUrl = function (container, blob, sharedAccessPolicy) {
// Validate container name. Blob name is optional.
validateContainerName(container);
- var resourceName = createResourceName(container, blob);
-
- var baseUrl = this.protocol + this.host + ':' + this.port;
- var path = this._getPath('/' + resourceName);
+ var signedQueryString = {};
+ if (sharedAccessPolicy) {
+ signedQueryString = this.generateSharedAccessSignature(container, blob, sharedAccessPolicy).queryString;
+ }
- return {
- baseUrl: baseUrl,
- path: path,
- url: function () {
- return baseUrl + path;
- }
- };
+ return url.format({
+ protocol: this._isHttps() ? 'https:' : 'http:',
+ hostname: this.host,
+ port: this.port,
+ pathname: this._getPath('/' + createResourceName(container, blob)),
+ query: signedQueryString
+ });
};
// Private methods
@@ -29,6 +29,9 @@ var HeaderConstants = Constants.HeaderConstants;
var HttpConstants = Constants.HttpConstants;
var Logger = require('../../diagnostics/logger');
+var moduleVersion = require('../../../package.json').version;
+var operatingSystem = process.platform;
+
// Expose 'ServiceClient'.
exports = module.exports = ServiceClient;
@@ -206,6 +209,8 @@ ServiceClient.prototype._performRequest = function (webResource, body, options,
finalCallback(requestOptions);
});
} else {
+ self._tagRequest(requestOptions);
+
self.logger.log(Logger.LogLevels.DEBUG, "REQUEST OPTIONS:\n" + util.inspect(requestOptions));
var operation = function (finalRequestOptions, operationCallback, next) {
@@ -284,6 +289,14 @@ ServiceClient.prototype._performRequest = function (webResource, body, options,
});
};
+ServiceClient.prototype._tagRequest = function (requestOptions) {
+ if (!this.userAgent) {
+ this.userAgent = util.format('Windows Azure SDK/%s (Node.js; %s)', moduleVersion, operatingSystem);
+ }
+
+ requestOptions.headers[HeaderConstants.USER_AGENT] = this.userAgent;
+};
+
/**
* Process the response.
*
View
@@ -2112,14 +2112,6 @@ var Constants = {
USER_AGENT: 'user-agent',
/**
- * Specifies the value to use for UserAgent header.
- *
- * @const
- * @type {string}
- */
- USER_AGENT_PREFIX: 'WA-Storage',
-
- /**
* The pop receipt header.
*
* @const
View
@@ -0,0 +1,62 @@
+/**
+* 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.
+*/
+
+/**
+* Generates a Date object which is in the given days from now.
+*
+* @param {int} days The days timespan.
+* @return {Date}
+*/
+exports.daysFromNow = function (days) {
+ var date = new Date()
+ date.setDate(date.getDate() + days);
+ return date;
+};
+
+/**
+* Generates a Date object which is in the given hours from now.
+*
+* @param {int} hours The hours timespan.
+* @return {Date}
+*/
+exports.hoursFromNow = function (hours) {
+ var date = new Date()
+ date.setHours(date.getHours() + hours);
+ return date;
+};
+
+/**
+* Generates a Date object which is in the given minutes from now.
+*
+* @param {int} minutes The minutes timespan.
+* @return {Date}
+*/
+exports.minutesFromNow = function (minutes) {
+ var date = new Date()
+ date.setMinutes(date.getMinutes() + minutes);
+ return date;
+};
+
+/**
+* Generates a Date object which is in the given seconds from now.
+*
+* @param {int} seconds The seconds timespan.
+* @return {Date}
+*/
+exports.secondsFromNow = function (seconds) {
+ var date = new Date()
+ date.setSeconds(date.getSeconds() + seconds);
+ return date;
+};
@@ -18,6 +18,7 @@ var assert = require('assert');
var fs = require('fs');
var path = require("path");
var util = require('util');
+var sinon = require('sinon');
// Test includes
var testutil = require('../../util/util');
@@ -1250,11 +1251,52 @@ suite('blobservice-tests', function () {
var blobServiceassert = azure.createBlobService('storageAccount', 'storageAccessKey', 'host.com:80');
- var urlParts = blobServiceassert.getBlobUrl(containerName);
- assert.equal(urlParts.url(), 'http://host.com:80/' + containerName);
+ var blobUrl = blobServiceassert.getBlobUrl(containerName);
+ assert.equal(blobUrl, 'http://host.com:80/' + containerName);
- urlParts = blobServiceassert.getBlobUrl(containerName, blobName);
- assert.equal(urlParts.url(), 'http://host.com:80/' + containerName + '/' + blobName);
+ blobUrl = blobServiceassert.getBlobUrl(containerName, blobName);
+ assert.equal(blobUrl, 'http://host.com:80/' + containerName + '/' + blobName);
+
+ done();
+ });
+
+ test('GetBlobSharedUrl', function (done) {
+ var containerName = 'container';
+ var blobName = 'blob';
+
+ var blobServiceassert = azure.createBlobService('storageAccount', 'storageAccessKey', 'host.com:80');
+
+ var sharedAccessPolicy = {
+ AccessPolicy: {
+ Expiry: new Date('October 12, 2011 11:53:40 am GMT')
+ }
+ };
+
+ var blobUrl = blobServiceassert.getBlobUrl(containerName, blobName, sharedAccessPolicy);
+ assert.equal(blobUrl, 'http://host.com:80/' + containerName + '/' + blobName + '?se=2011-10-12T11%3A53%3A40Z&sr=b&sp=r&sig=eVkH%2BFxxShel2hcN50ZUmgPAHk%2FmqRVeaBfyry%2BVacw%3D');
+
+ done();
+ });
+
+ test('GetBlobSharedUrlWithDuration', function (done) {
+ var containerName = 'container';
+ var blobName = 'blob';
+
+ var blobServiceassert = azure.createBlobService('storageAccount', 'storageAccessKey', 'host.com:80');
+
+ // Mock Date just to ensure a fixed signature
+ this.clock = sinon.useFakeTimers(0, "Date");
+
+ var sharedAccessPolicy = {
+ AccessPolicy: {
+ Expiry: azure.date.minutesFromNow(10)
+ }
+ };
+
+ this.clock.restore();
+
+ var blobUrl = blobServiceassert.getBlobUrl(containerName, blobName, sharedAccessPolicy);
+ assert.equal(blobUrl, 'http://host.com:80/' + containerName + '/' + blobName + '?se=1970-01-01T00%3A10%3A00Z&sr=b&sp=r&sig=LofuDUzdHPpiteauMetANWzDpzd0Vw%2BVMOHyXYCipAM%3D');
done();
});
View
@@ -30,6 +30,7 @@ services/table/tableservice-tablequery-tests.js
services/table/tableservice-tests.js
services/sqlAzure/sqlservice-tests.js
util/atomhandler-tests.js
+util/date-tests.js
util/iso8061date-tests.js
util/util-tests.js
util/validate-tests.js
View
@@ -0,0 +1,58 @@
+/**
+* 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 should = require('should');
+var sinon = require('sinon');
+
+var testutil = require('./util');
+var azure = testutil.libRequire('azure');
+
+suite('date-tests', function () {
+ setup(function () {
+ this.clock = sinon.useFakeTimers(0, "Date");
+ });
+
+ teardown(function () {
+ this.clock.restore();
+ });
+
+ test('daysFromNow', function () {
+ var daysInterval = 1;
+ var expectedDate = new Date('Jan 2, 1970 00:00:00 am GMT');
+
+ azure.date.daysFromNow(daysInterval).should.equal(expectedDate);
+ });
+
+ test('hoursFromNow', function () {
+ var hoursInterval = 3;
+ var expectedDate = new Date('Jan 1, 1970 03:00:00 am GMT');
+
+ azure.date.hoursFromNow(hoursInterval).should.equal(expectedDate);
+ });
+
+ test('minutesFromNow', function () {
+ var minutesInterval = 10;
+ var expectedDate = new Date('Jan 1, 1970 00:10:00 am GMT');
+
+ azure.date.minutesFromNow(minutesInterval).should.equal(expectedDate);
+ });
+
+ test('secondsFromNow', function () {
+ var secondsInterval = 20;
+ var expectedDate = new Date('Jan 1, 1970 00:00:20 am GMT');
+
+ azure.date.secondsFromNow(secondsInterval).should.equal(expectedDate);
+ });
+});

0 comments on commit 2712ccb

Please sign in to comment.