Merge pull request #474 from andrerod/dev

#469: Making access conditions case insensitive.
This commit is contained in:
André Rodrigues 2012-11-14 16:44:30 -08:00
Родитель 34d13cfdb8 747db082aa
Коммит 3c7440d2bd
9 изменённых файлов: 348 добавлений и 31 удалений

Просмотреть файл

@ -53,8 +53,7 @@ function createContainer() {
blobService.createContainerIfNotExists(container, function (error) {
if (error) {
console.log(error);
}
else {
} else {
console.log('Created the container ' + container);
uploadSample();
}
@ -203,8 +202,7 @@ function testAccess(containerName, blobName, etag) {
if (processArguments.length > 5 || processArguments.length < 4) {
console.log('Incorrect number of arguments');
}
else if (processArguments.length == 5) {
} else if (processArguments.length == 5) {
// Adding a third argument on the command line, whatever it is, will delete the container before running the sample.
blobService.deleteContainer(container, function (error) {
if (error) {
@ -213,8 +211,7 @@ else if (processArguments.length == 5) {
createContainer();
}
});
}
else {
} else {
createContainer();
}

Просмотреть файл

@ -287,40 +287,48 @@ WebResource.prototype.addOptionalMetadataHeaders = function (metadata) {
WebResource.prototype.addOptionalAccessConditionHeader = function (accessConditionHeaders) {
if (accessConditionHeaders) {
if (accessConditionHeaders[HeaderConstants.IF_MATCH]) {
this.addOptionalHeader(HeaderConstants.IF_MATCH, accessConditionHeaders[HeaderConstants.IF_MATCH]);
var ifMatch = azureutil.tryGetValueInsensitive(HeaderConstants.IF_MATCH, accessConditionHeaders);
if (ifMatch) {
this.addOptionalHeader(HeaderConstants.IF_MATCH, ifMatch);
}
if (accessConditionHeaders[HeaderConstants.IF_MODIFIED_SINCE]) {
this.addOptionalHeader(HeaderConstants.IF_MODIFIED_SINCE, accessConditionHeaders[HeaderConstants.IF_MODIFIED_SINCE]);
var ifModifiedSince = azureutil.tryGetValueInsensitive(HeaderConstants.IF_MODIFIED_SINCE, accessConditionHeaders);
if (ifModifiedSince) {
this.addOptionalHeader(HeaderConstants.IF_MODIFIED_SINCE, ifModifiedSince);
}
if (accessConditionHeaders[HeaderConstants.IF_NONE_MATCH]) {
this.addOptionalHeader(HeaderConstants.IF_NONE_MATCH, accessConditionHeaders[HeaderConstants.IF_NONE_MATCH]);
var ifNoneMatch = azureutil.tryGetValueInsensitive(HeaderConstants.IF_NONE_MATCH, accessConditionHeaders);
if (ifNoneMatch) {
this.addOptionalHeader(HeaderConstants.IF_NONE_MATCH, ifNoneMatch);
}
if (accessConditionHeaders[HeaderConstants.IF_UNMODIFIED_SINCE]) {
this.addOptionalHeader(HeaderConstants.IF_UNMODIFIED_SINCE, accessConditionHeaders[HeaderConstants.IF_UNMODIFIED_SINCE]);
var ifUnmodifiedSince = azureutil.tryGetValueInsensitive(HeaderConstants.IF_UNMODIFIED_SINCE, accessConditionHeaders);
if (ifUnmodifiedSince) {
this.addOptionalHeader(HeaderConstants.IF_UNMODIFIED_SINCE, ifUnmodifiedSince);
}
}
};
WebResource.prototype.addOptionalSourceAccessConditionHeader = function (accessConditionHeaders) {
if (accessConditionHeaders) {
if (accessConditionHeaders[HeaderConstants.SOURCE_IF_MATCH_HEADER]) {
this.addOptionalHeader(HeaderConstants.SOURCE_IF_MATCH_HEADER, accessConditionHeaders[HeaderConstants.SOURCE_IF_MATCH_HEADER]);
var sourceIfMatch = azureutil.tryGetValueInsensitive(HeaderConstants.SOURCE_IF_MATCH_HEADER, accessConditionHeaders);
if (sourceIfMatch) {
this.addOptionalHeader(HeaderConstants.SOURCE_IF_MATCH_HEADER, sourceIfMatch);
}
if (accessConditionHeaders[HeaderConstants.SOURCE_IF_MODIFIED_SINCE_HEADER]) {
this.addOptionalHeader(HeaderConstants.SOURCE_IF_MODIFIED_SINCE_HEADER, accessConditionHeaders[HeaderConstants.SOURCE_IF_MODIFIED_SINCE_HEADER]);
var sourceIfModifiedSince = azureutil.tryGetValueInsensitive(HeaderConstants.SOURCE_IF_MODIFIED_SINCE_HEADER, accessConditionHeaders);
if (sourceIfModifiedSince) {
this.addOptionalHeader(HeaderConstants.SOURCE_IF_MODIFIED_SINCE_HEADER, sourceIfModifiedSince);
}
if (accessConditionHeaders[HeaderConstants.SOURCE_IF_NONE_MATCH_HEADER]) {
this.addOptionalHeader(HeaderConstants.SOURCE_IF_NONE_MATCH_HEADER, accessConditionHeaders[HeaderConstants.SOURCE_IF_NONE_MATCH_HEADER]);
var sourceIfNoneMatch = azureutil.tryGetValueInsensitive(HeaderConstants.SOURCE_IF_NONE_MATCH_HEADER, accessConditionHeaders);
if (sourceIfNoneMatch) {
this.addOptionalHeader(HeaderConstants.SOURCE_IF_NONE_MATCH_HEADER, sourceIfNoneMatch);
}
if (accessConditionHeaders[HeaderConstants.SOURCE_IF_UNMODIFIED_SINCE_HEADER]) {
this.addOptionalHeader(HeaderConstants.SOURCE_IF_UNMODIFIED_SINCE_HEADER, accessConditionHeaders[HeaderConstants.SOURCE_IF_UNMODIFIED_SINCE_HEADER]);
var sourceIfUnmodifiedSince = azureutil.tryGetValueInsensitive(HeaderConstants.SOURCE_IF_UNMODIFIED_SINCE_HEADER, accessConditionHeaders);
if (sourceIfUnmodifiedSince) {
this.addOptionalHeader(HeaderConstants.SOURCE_IF_UNMODIFIED_SINCE_HEADER, sourceIfUnmodifiedSince);
}
}
};

Просмотреть файл

@ -22,6 +22,8 @@ var ISO8061Date = require('../../../util/iso8061date');
// Expose 'ContainerAclResult'.
exports = module.exports = ContainerAclResult;
var ACL_MILLISECONDS_PADING = 7;
function ContainerAclResult(signedIdentifiers) {
if (signedIdentifiers) {
this.signedIdentifiers = signedIdentifiers;
@ -51,7 +53,7 @@ ContainerAclResult.serialize = function (signedIdentifiersJs) {
var startIsoString = signedIdentifier.AccessPolicy.Start;
if (startIsoString instanceof Date) {
// Convert to expected ISO 8061 date format
startIsoString = ISO8061Date.format(startIsoString);
startIsoString = ISO8061Date.format(startIsoString, ACL_MILLISECONDS_PADING);
}
doc = doc
@ -64,7 +66,7 @@ ContainerAclResult.serialize = function (signedIdentifiersJs) {
var expiryIsoString = signedIdentifier.AccessPolicy.Expiry;
if (expiryIsoString instanceof Date) {
// Convert to expected ISO 8061 date format
expiryIsoString = ISO8061Date.format(expiryIsoString);
expiryIsoString = ISO8061Date.format(expiryIsoString, ACL_MILLISECONDS_PADING);
}
doc = doc

Просмотреть файл

@ -130,6 +130,81 @@ ServiceManagementSerialize.prototype.buildCreateStorageAccount = function(servic
}
};
/**
* Create the message body for UpdateStorageAccount
*
* @param {string} serviceName The name of the service.
* @param {object} serviceOptions The properties for the new service.
* @param {object} client The servicemanagement object.
*/
ServiceManagementSerialize.prototype.buildUpdateStorageAccount = function(serviceName, serviceOptions, client) {
var encLabel = undefined;
if (serviceOptions.Label) {
encLabel = new Buffer(serviceOptions.Label).toString('base64');
}
if (client.serializetype === 'XML') {
var doc = _createXmlRoot('UpdateStorageServiceInput');
_addDefinedValueXml(doc, 'ServiceName', serviceName);
if (encLabel) {
_addDefinedValueXml(doc, 'Label', encLabel);
}
if (serviceOptions.Description) {
_addDefinedValueXml(doc, 'Description', serviceOptions.Description);
}
if (serviceOptions.GeoReplicationEnabled) {
_addDefinedValueXml(doc, 'GeoReplicationEnabled', serviceOptions.GeoReplicationEnabled);
}
return doc.toString();
} else {
var jdoc = {
ServiceName: serviceName
};
if (encLabel) {
jdoc.Label = encLabel;
}
if (serviceOptions.Description) {
jdoc.Description = serviceOptions.Description;
}
if (serviceOptions.GeoReplicationEnabled) {
jdoc.GeoReplicationEnabled = serviceOptions.GeoReplicationEnabled;
}
return JSON.stringify(jdoc);
}
};
/**
* Create the message body for RegenerateStorageKeys
*
* @param {string} serviceName The name of the service.
* @param {string} keyType The key type.
* @param {object} client The servicemanagement object.
*/
ServiceManagementSerialize.prototype.buildRegenerateStorageKeys = function(serviceName, keyType, client) {
if (client.serializetype === 'XML') {
var doc = _createXmlRoot('RegenerateKeys');
doc.ele('KeyType').txt(keyType);
return doc.toString();
} else {
var jdoc = {
RegenerateKeys: {
KeyType: keyType
}
};
return JSON.stringify(jdoc);
}
};
/**
* Create the message body for CreateOSImage
* Use the specified serialization - for now only XML.

Просмотреть файл

@ -570,7 +570,7 @@ ServiceManagementService.prototype.deleteHostedService = function(serviceName, c
};
/**
* Returns keys of specified storage account.
* Creates a new storage account.
*
* @param {string} serviceName The name of the storage service. Required.
* @param {string} serviceOptions Object with properties for the service. Optional
@ -628,6 +628,44 @@ ServiceManagementService.prototype.createStorageAccount = function(serviceName,
});
};
/**
* Updates a storage account.
*
* @param {string} serviceName The name of the storage service. Required.
* @param {string} serviceOptions Object with properties for the service. Optional
* {
* Description: optional. Defaults to 'Service host'
* Label: optional. Defaults to serviceName
* GeoReplicationEnabled: optional. Indicates if the geo replication is enabled.
* }
* @param {function} callback The callback function called on completion. Required.
*/
ServiceManagementService.prototype.updateStorageAccount = function(serviceName, serviceOptions, callback) {
if (!callback) {
if (typeof serviceOptions === 'function') {
callback = serviceOptions;
serviceOptions = null;
}
}
validateStringArgument(serviceName, 'serviceName', 'updateStorageAccount');
validateObjectArgument(callback, 'callback', 'updateStorageAccount');
var path = '/' + this.subscriptionId + '/services/storageservices/' + serviceName;
var webResource = WebResource.put(path);
webResource.withOkCode(HttpConstants.HttpResponseCodes.OK_CODE, true);
var outbody = this.serialize.buildUpdateStorageAccount(serviceName, serviceOptions, this);
this.performRequest(webResource, outbody, null, function (responseObject, next) {
var finalCallback = function (returnObject) {
callback(returnObject.error, returnObject.response);
};
next(responseObject, finalCallback);
});
};
/**
* Returns keys of specified storage account.
*
@ -679,6 +717,62 @@ ServiceManagementService.prototype.getStorageAccountProperties = function(servic
});
};
/**
* Regenerates a storage account's keys
*
* @param {string} serviceName The name of the hosted service. Required.
* @param {string} keyType The storage key type (primary or secondary). Required.
* @param {function} callback The callback function called on completion. Required.
*/
ServiceManagementService.prototype.regenerateStorageAccountKeys = function(serviceName, keyType, callback) {
validateStringArgument(serviceName, 'serviceName', 'deleteDeployment');
validateObjectArgument(callback, 'callback', 'deleteDeployment');
if (keyType.toLowerCase() !== 'primary' && keyType.toLowerCase() !== 'secondary') {
throw new Error('Invalid storage account type');
}
var path = '/' + this.subscriptionId + '/services/storageservices/' + serviceName + '/keys?action=regenerate';
var webResource = WebResource.post(path);
webResource.withOkCode(HttpConstants.HttpResponseCodes.OK_CODE, true);
var outbody = this.serialize.buildRegenerateStorageKeys(serviceName, keyType, this);
this.performRequest(webResource, outbody, null, function (responseObject, next) {
var finalCallback = function (returnObject) {
callback(returnObject.error, returnObject.response);
};
next(responseObject, finalCallback);
});
};
/**
* Deletes a storage account
*
* @param {string} serviceName The name of the hosted service. Required.
* @param {function} callback The callback function called on completion. Required.
*/
ServiceManagementService.prototype.deleteStorageAccount = function(serviceName, callback) {
validateStringArgument(serviceName, 'serviceName', 'deleteDeployment');
validateObjectArgument(callback, 'callback', 'deleteDeployment');
var path = '/' + this.subscriptionId + '/services/storageservices/' + serviceName;
var webResource = WebResource.del(path);
webResource.withOkCode(HttpConstants.HttpResponseCodes.OK_CODE, true);
this.performRequest(webResource, null, null, function (responseObject, next) {
var finalCallback = function (returnObject) {
callback(returnObject.error, returnObject.response);
};
next(responseObject, finalCallback);
});
};
/**
* Gets deployment properties for named deployment
*

Просмотреть файл

@ -16,11 +16,12 @@
/**
* Formats a date into an iso 8061 string.
*
* @param {date} date The date to format.
* @param {bool} skipMilliseconds Boolean value indicating if the miliseconds part of the date should not be included.
* @param {date} date The date to format.
* @param {bool} skipMilliseconds Boolean value indicating if the miliseconds part of the date should not be included.
* @param {integer} millisecondsPading Number of digits to left pad the miliseconds.
* @return {string} The date formated in the ISO 8061 date format.
*/
exports.format = function (date, skipMilliseconds) {
exports.format = function (date, skipMilliseconds, millisecondsPading) {
var components = [
date.getUTCFullYear(),
'-',
@ -37,7 +38,11 @@ exports.format = function (date, skipMilliseconds) {
if (!skipMilliseconds) {
components.push('.');
components.push(leftPadThree(date.getUTCMilliseconds()));
if (!millisecondsPading) {
millisecondsPading = 3;
}
components.push(leftPad(date.getUTCMilliseconds(), millisecondsPading));
}
components.push('Z');
@ -77,9 +82,9 @@ var leftPadTwo = function (n) {
return (n < 10 ? '0' : '') + n;
};
var leftPadThree = function (n) {
var leftPad = function (n, millisecondsPading) {
var currentN = '' + n;
while (currentN.length < 3) {
while (currentN.length < millisecondsPading) {
currentN = '0' + currentN;
}

Просмотреть файл

@ -0,0 +1,67 @@
/**
* 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 testutil = require('../util/util');
var WebResource = require('../../lib/http/webresource');
var azure = testutil.libRequire('azure');
var Constants = azure.Constants;
var HeaderConstants = Constants.HeaderConstants;
suite('webresource-tests', function () {
test('addOptionalAccessConditionHeader', function () {
var ifMatch = 'ifmatch';
var ifModifiedSince = 'ifModifiedSince';
var ifNoneMatch = 'ifNoneMatch';
var ifUnmodifiedSince = 'ifUnmodifiedSince';
var accessConditions = {
'If-Match': ifMatch,
'If-Modified-Since': ifModifiedSince,
'If-None-Match': ifNoneMatch,
'If-Unmodified-Since': ifUnmodifiedSince
};
var webResource = new WebResource();
webResource.addOptionalAccessConditionHeader(accessConditions);
webResource.headers[HeaderConstants.IF_MATCH].should.equal(ifMatch);
webResource.headers[HeaderConstants.IF_MODIFIED_SINCE].should.equal(ifModifiedSince);
webResource.headers[HeaderConstants.IF_NONE_MATCH].should.equal(ifNoneMatch);
webResource.headers[HeaderConstants.IF_UNMODIFIED_SINCE].should.equal(ifUnmodifiedSince);
});
test('addOptionalSourceAccessConditionHeader', function () {
var sourceIfMatch = 'sourceIfmatch';
var sourceIfModifiedSince = 'sourceIfModifiedSince';
var sourceIfNoneMatch = 'sourceIfNoneMatch';
var sourceIfUnmodifiedSince = 'sourceIfUnmodifiedSince';
var accessConditions = {
'x-ms-source-If-Match': sourceIfMatch,
'x-ms-source-If-Modified-Since': sourceIfModifiedSince,
'x-ms-source-If-None-Match': sourceIfNoneMatch,
'x-ms-source-If-Unmodified-Since': sourceIfUnmodifiedSince
};
var webResource = new WebResource();
webResource.addOptionalSourceAccessConditionHeader(accessConditions);
webResource.headers[HeaderConstants.SOURCE_IF_MATCH_HEADER].should.equal(sourceIfMatch);
webResource.headers[HeaderConstants.SOURCE_IF_MODIFIED_SINCE_HEADER].should.equal(sourceIfModifiedSince);
webResource.headers[HeaderConstants.SOURCE_IF_NONE_MATCH_HEADER].should.equal(sourceIfNoneMatch);
webResource.headers[HeaderConstants.SOURCE_IF_UNMODIFIED_SINCE_HEADER].should.equal(sourceIfUnmodifiedSince);
});
});

Просмотреть файл

@ -420,6 +420,74 @@ suite('blobservice-tests', function () {
});
});
test('SetContainerAclWithPolicies', function (done) {
var containerName = testutil.generateId(containerNamesPrefix, containerNames, blobtestutil.isMocked);
var readWriteStartDate = new Date();
var readWriteExpiryDate = new Date(readWriteStartDate);
readWriteExpiryDate.setMinutes(readWriteStartDate.getMinutes() + 10);
var readWriteSharedAccessPolicy = {
Id: 'readwrite',
AccessPolicy: {
Start: readWriteStartDate,
Expiry: readWriteExpiryDate,
Permissions: 'rw'
}
};
var readSharedAccessPolicy = {
Id: 'read',
AccessPolicy: {
Expiry: readWriteStartDate,
Permissions: 'r'
}
};
var options = {};
options.signedIdentifiers = [readWriteSharedAccessPolicy, readSharedAccessPolicy];
blobService.createContainer(containerName, function (createError, container1, createContainerResponse) {
assert.equal(createError, null);
assert.notEqual(container1, null);
assert.ok(createContainerResponse.isSuccessful);
blobService.setContainerAcl(containerName, BlobConstants.BlobContainerPublicAccessType.BLOB, options, function (setAclError, setAclContainer1, setResponse1) {
assert.equal(setAclError, null);
assert.notEqual(setAclContainer1, null);
assert.ok(setResponse1.isSuccessful);
blobService.getContainerAcl(containerName, function (getAclError, getAclContainer1, getResponse1) {
assert.equal(getAclError, null);
assert.notEqual(getAclContainer1, null);
if (getAclContainer1) {
assert.equal(getAclContainer1.publicAccessLevel, BlobConstants.BlobContainerPublicAccessType.BLOB);
}
assert.ok(getResponse1.isSuccessful);
blobService.setContainerAcl(containerName, BlobConstants.BlobContainerPublicAccessType.CONTAINER, function (setAclError2, setAclContainer2, setResponse2) {
assert.equal(setAclError2, null);
assert.notEqual(setAclContainer2, null);
assert.ok(setResponse2.isSuccessful);
blobService.getContainerAcl(containerName, function (getAclError2, getAclContainer2, getResponse3) {
assert.equal(getAclError2, null);
assert.notEqual(getAclContainer2, null);
if (getAclContainer2) {
assert.equal(getAclContainer2.publicAccessLevel, BlobConstants.BlobContainerPublicAccessType.CONTAINER);
}
assert.ok(getResponse3.isSuccessful);
done();
});
});
});
});
});
});
test('SetContainerAclSignedIdentifiers', function (done) {
var containerName = testutil.generateId(containerNamesPrefix, containerNames, blobtestutil.isMocked);

Просмотреть файл

@ -1,6 +1,7 @@
serviceruntime/roleenvironment-tests.js
serviceruntime/runtimeversionmanager-tests.js
serviceruntime/runtimeversionprotocolclient-tests.js
http/webresource-tests.js
services/blob/blobservice-tests.js
services/blob/sharedaccesssignature-tests.js
services/blob/sharedkey-tests.js