azure-storage-legacy
Version:
Microsoft Azure Storage Client Library for node for back compat with older versions of node sdk
984 lines (850 loc) • 190 kB
JavaScript
//
// Copyright (c) Microsoft and contributors. 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.
//
// Module dependencies.
var fs = require('fs');
var qs = require('querystring');
var url = require('url');
var util = require('util');
var mime = require('mime');
var _ = require('underscore');
var crypto = require('crypto');
var FileReadStream = require('./internal/filereadstream');
var BlobBlockRangeStream = require('./internal/blobblockrangestream');
var BlobPageRangeStream = require('./internal/blobpagerangestream');
var BatchOperation = require('./internal/batchoperation');
var SpeedSummary = require('./internal/speedsummary');
var ChunkAllocator = require('./internal/chunkAllocator');
var ChunkStream = require('./internal/chunkStream');
var ChunkStreamWithStream = require('./internal/chunkStreamWithStream');
var azureCommon = require('azure-common');
var azureutil = azureCommon.util;
var validate = azureCommon.validate;
var requestPipeline = azureCommon.requestPipeline;
var ErrorHandlingFilter = azureCommon.ErrorHandlingFilter;
var UserAgentFilter = azureCommon.UserAgentFilter;
var SigningFilter = azureCommon.SigningFilter;
var StorageServiceClient = azureCommon.StorageServiceClient;
var WebResource = azureCommon.WebResource;
var Constants = azureCommon.Constants;
var HeaderConstants = Constants.HeaderConstants;
var QueryStringConstants = Constants.QueryStringConstants;
var BlobConstants = Constants.BlobConstants;
var SharedKey = require('./internal/sharedkey');
var SharedAccessSignature = require('./internal/sharedaccesssignature');
// Models requires
var servicePropertiesResult = require('./models/servicepropertiesresult');
var ContainerAclResult = require('./models/containeraclresult');
var BlockListResult = require('./models/blocklistresult');
var BlobResult = require('./models/blobresult');
var ContainerResult = require('./models/containerresult');
var LeaseResult = require('./models/leaseresult');
var ListBlobsResultContinuation = require('./models/listblobsresultcontinuation');
var ListContainersResultContinuation = require('./models/listcontainersresultcontinuation');
/**
* 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.
* @class
* The BlobService class is used to perform operations on the Microsoft Azure Blob Service.
* The Blob Service provides storage for binary large objects, and provides
* functions for working with data stored in blobs as either streams or pages of data.
*
* For more information on the Blob Service, as well as task focused information on using it in a Node.js application, see
* [How to Use the Blob Service from Node.js](https://www.windowsazure.com/en-us/develop/nodejs/how-to-guides/blob-storage/).
* @constructor
* @extends {ServiceClient}
*
* @param {string} [storageAccountOrConnectionString] The storage account or the connection string.
* @param {string} [storageAccessKey] The storage access key.
* @param {string} [host] The host address.
* @param {object} [authenticationProvider] The authentication provider.
*/
function BlobService(storageAccountOrConnectionString, storageAccessKey, host, authenticationProvider) {
var storageServiceSettings = StorageServiceClient.getStorageSettings(storageAccountOrConnectionString, storageAccessKey, host);
BlobService['super_'].call(this,
storageServiceSettings._name,
storageServiceSettings._key,
storageServiceSettings._blobEndpointUri,
storageServiceSettings._usePathStyleUri,
authenticationProvider);
this.apiVersion = '2012-02-12';
if (!this.authenticationProvider) {
this.authenticationProvider = new SharedKey(this.storageAccount, this.storageAccessKey, this.usePathStyleUri);
}
if (!this.sharedAccessSignatureCredentials) {
this.sharedAccessSignatureCredentials = new SharedAccessSignature(this.storageAccount, this.storageAccessKey);
}
this.singleBlobPutThresholdInBytes = BlobConstants.DEFAULT_SINGLE_BLOB_PUT_THRESHOLD_IN_BYTES;
this.writeBlockSizeInBytes = BlobConstants.DEFAULT_WRITE_BLOCK_SIZE_IN_BYTES;
this.pipeline = requestPipeline.create(
SigningFilter.create(this.authenticationProvider),
UserAgentFilter.create(),
ErrorHandlingFilter.create());
}
util.inherits(BlobService, StorageServiceClient);
// Non-class methods
/**
* Create resource name
* @ignore
*
* @param {string} containerName Container name
* @param {string} blobName Blob name
* @param {bool} skipEncoding Boolean value indicating if encoding should be skipped.
* @return {string} The encoded resource name.
*/
function createResourceName(containerName, blobName, skipEncoding) {
// Resource name
if (!skipEncoding) {
if (blobName) {
blobName = encodeURIComponent(blobName);
blobName = blobName.replace(/%2F/g, '/');
blobName = blobName.replace(/%5C/g, '/');
blobName = blobName.replace(/\+/g, '%20');
}
}
var resourceName = containerName + '/' + blobName;
if (!containerName || containerName === '$root') {
resourceName = blobName;
}
if (!blobName) {
resourceName = containerName;
}
return resourceName;
}
/**
* Gets the properties of a storage account’s Blob service, including Microsoft Azure Storage Analytics.
*
* @this {BlobService}
* @param {object} [options] The request options.
* @param {int} [options.timeoutIntervalInMs] The timeout interval, in milliseconds, to use for the request.
* @param {Function(error, serviceProperties, response)} callback `error` will contain information
* if an error occurs; otherwise, `serviceProperties`
* will contain the properties and `response`
* will contain information related to this operation.
*/
BlobService.prototype.getServiceProperties = function (optionsOrCallback, callback) {
var options;
azureutil.normalizeArgs(optionsOrCallback, callback, function (o, c) { options = o; callback = c; });
validate.validateArgs('getServiceProperties', function (v) {
v.callback(callback);
});
var webResource = WebResource.get()
.withQueryOption(QueryStringConstants.COMP, 'properties')
.withQueryOption(QueryStringConstants.RESTYPE, 'service');
var processResponseCallback = function (responseObject, next) {
responseObject.servicePropertiesResult = null;
if (!responseObject.error) {
responseObject.servicePropertiesResult = servicePropertiesResult.parse(responseObject.response.body.StorageServiceProperties);
}
// function to be called after all filters
var finalCallback = function (returnObject) {
callback(returnObject.error, returnObject.servicePropertiesResult, returnObject.response);
};
// call the first filter
next(responseObject, finalCallback);
};
this.performRequest(webResource, null, options, processResponseCallback);
};
/**
* Sets the properties of a storage account’s Blob service, including Microsoft Azure Storage Analytics.
* You can also use this operation to set the default request version for all incoming requests that do not have a version specified.
*
* @this {BlobService}
* @param {object} serviceProperties The service properties.
* @param {object} [options] The request options.
* @param {int} [options.timeoutIntervalInMs] The timeout interval, in milliseconds,
* to use for the request.
* @param {Function(error, response)} callback `error` will contain information
* if an error occurs; otherwise, `response`
* will contain information related to this operation.
*/
BlobService.prototype.setServiceProperties = function (serviceProperties, optionsOrCallback, callback) {
var options;
azureutil.normalizeArgs(optionsOrCallback, callback, function (o, c) { options = o; callback = c; });
validate.validateArgs('setServiceProperties', function (v) {
v.object(serviceProperties, 'serviceProperties');
v.callback(callback);
});
var servicePropertiesXml = servicePropertiesResult.serialize(serviceProperties);
var webResource = WebResource.put()
.withQueryOption(QueryStringConstants.COMP, 'properties')
.withQueryOption(QueryStringConstants.RESTYPE, 'service')
.withHeader(HeaderConstants.CONTENT_TYPE, 'application/xml;charset="utf-8"')
.withHeader(HeaderConstants.CONTENT_LENGTH, Buffer.byteLength(servicePropertiesXml))
.withBody(servicePropertiesXml);
var processResponseCallback = function (responseObject, next) {
var finalCallback = function (returnObject) {
callback(returnObject.error, returnObject.response);
};
next(responseObject, finalCallback);
};
this.performRequest(webResource, webResource.body, options, processResponseCallback);
};
/**
* Returns a list of the containers under the specified account.
*
* @this {BlobService}
* @param {object} [options] The list container options.
* @param {string} [options.prefix] Filters the results to return only containers whose name begins with the specified prefix.
* @param {int} [options.maxresults] Specifies the maximum number of containers to return per call to Azure storage.
* @param {string} [options.marker] String value that identifies the portion of the list to be returned with the next list operation.
* @param {string} [options.include] Include this parameter to specify that the container's metadata be returned as part of the response body. (allowed values: '', 'metadata')
* @param {int} [options.timeoutIntervalInMs] The timeout interval, in milliseconds, to use for the request.
* @param {Function(error, containers, nextMarker, response)} callback `error` will contain information
* if an error occurs; otherwise `containers` will contain a list of
* {@link BlobService~containerResult} objects,
* and `response` will contain information related to this operation.
* If not all container information could be retrieved,
* `nextMarker` will contain a value that can be used
* to retrieve the next section of the containers list.
*/
BlobService.prototype.listContainers = function (optionsOrCallback, callback) {
var options;
azureutil.normalizeArgs(optionsOrCallback, callback, function (o, c) { options = o; callback = c; });
validate.validateArgs('listContainers', function (v) {
v.callback(callback);
});
var webResource = WebResource.get()
.withProperty(BlobConstants.ResourceTypeProperty, BlobConstants.ResourceTypes.CONTAINER)
.withProperty(BlobConstants.SharedAccessPermissionProperty, BlobConstants.SharedAccessPermissions.LIST)
.withQueryOption(QueryStringConstants.COMP, 'list')
.withQueryOptions(options,
QueryStringConstants.PREFIX,
QueryStringConstants.MARKER,
QueryStringConstants.MAX_RESULTS,
QueryStringConstants.INCLUDE);
var self = this;
var processResponseCallback = function (responseObject, next) {
responseObject.listContainersResult = null;
responseObject.listContainersResultContinuation = null;
if (!responseObject.error) {
responseObject.listContainersResult = [];
if (responseObject.response.body.EnumerationResults.Containers && responseObject.response.body.EnumerationResults.Containers.Container) {
var containers = responseObject.response.body.EnumerationResults.Containers.Container;
if (!_.isArray(containers)) {
containers = [ containers ];
}
containers.forEach(function (currentContainer) {
var containerResult = ContainerResult.parse(currentContainer);
responseObject.listContainersResult.push(containerResult);
});
responseObject.listContainersResultContinuation = new ListContainersResultContinuation(self, options, responseObject.response.body.EnumerationResults.NextMarker);
}
}
var finalCallback = function (returnObject) {
callback(returnObject.error, returnObject.listContainersResult, returnObject.listContainersResultContinuation, returnObject.response);
};
next(responseObject, finalCallback);
};
this.performRequest(webResource, null, options, processResponseCallback);
};
/**
* Creates a new container under the specified account.
* If a container with the same name already exists, the operation fails.
*
* @this {BlobService}
* @param {string} container The container name.
* @param {object} [options] The optional container and request options.
* @param {object} [options.metadata] The metadata key/value pairs.
* @param {string} [options.publicAccessLevel] Specifies whether data in the container may be accessed publicly and the level of access.
* @param {int} [options.timeoutIntervalInMs] The timeout interval, in milliseconds, to use for the request.
* @param {function(error, container, response)} callback `error` will contain information
* if an error occurs; otherwise `container` will contain
* the {@link BlobService~containerResult} for the container.
* `response` will contain information related to this operation.
*/
BlobService.prototype.createContainer = function (container, optionsOrCallback, callback) {
var options;
azureutil.normalizeArgs(optionsOrCallback, callback, function (o, c) { options = o; callback = c; });
validate.validateArgs('createContainer', function (v) {
v.string(container, 'container');
v.test(function () { return container !== '$logs'; },
'Container name format is incorrect');
v.containerNameIsValid(container);
v.callback(callback);
});
var webResource = WebResource.put(container)
.withProperty(BlobConstants.ResourceTypeProperty, BlobConstants.ResourceTypes.CONTAINER)
.withProperty(BlobConstants.SharedAccessPermissionProperty, BlobConstants.SharedAccessPermissions.WRITE)
.withQueryOption(QueryStringConstants.RESTYPE, 'container');
if (options) {
webResource.addOptionalMetadataHeaders(options.metadata);
webResource.withHeader(HeaderConstants.BLOB_PUBLIC_ACCESS_HEADER, options.publicAccessLevel);
}
var processResponseCallback = function (responseObject, next) {
responseObject.containerResult = null;
if (!responseObject.error) {
responseObject.containerResult = new ContainerResult(container);
responseObject.containerResult.getPropertiesFromHeaders(responseObject.response.headers);
if (options && options.metadata) {
responseObject.containerResult.metadata = options.metadata;
}
}
var finalCallback = function (returnObject) {
callback(returnObject.error, returnObject.containerResult, returnObject.response);
};
next(responseObject, finalCallback);
};
this.performRequest(webResource, null, options, processResponseCallback);
};
/**
* Creates a new container under the specified account if the container does not exists.
*
* @this {BlobService}
* @param {string} container The container name.
* @param {object} [options] The optional container and request options.
* @param {object} [options.metadata] The metadata key/value pairs.
* @param {string} [options.publicAccessLevel] Specifies whether data in the container may be accessed publicly and the level of access.
* @param {int} [options.timeoutIntervalInMs] The timeout interval, in milliseconds, to use for the request.
* @param {Function(error, containerCreated, response)} callback `error` will contain information
* if an error occurs; otherwise `containerCreated` will contain
* be true if the container was created, or false if the container
* already exists.
* `response` will contain information related to this operation.
*
* @example
* var azure = require('azure');
* var blobService = azure.createBlobService();
* blobService.createContainerIfNotExists('taskcontainer', {publicAccessLevel : 'blob'}, function(error) {
* if(!error) {
* // Container created or exists, and is public
* }
* });
*/
BlobService.prototype.createContainerIfNotExists = function (container, optionsOrCallback, callback) {
var options;
azureutil.normalizeArgs(optionsOrCallback, callback, function (o, c) { options = o; callback = c; });
validate.validateArgs('createContainerIfNotExists', function (v) {
v.callback(callback);
});
this.createContainer(container, options, function (error, responseContainer, response) {
if (error && error.code === Constants.BlobErrorCodeStrings.CONTAINER_ALREADY_EXISTS) {
// If it was created before, there was no actual error.
error = null;
}
callback(error, !azureutil.objectIsNull(responseContainer), response);
});
};
/**
* Retrieves a container and its properties from a specified account.
*
* @this {BlobService}
* @param {string} container The container name.
* @param {object} [options] The request options.
* @param {string} [options.leaseId] The target blob lease identifier.
* @param {int} [options.timeoutIntervalInMs] The timeout interval, in milliseconds, to use for the request.
* @param {Function(error, container, response)} callback `error` will contain information
* if an error occurs; otherwise `container` will contain
* the {@link BlobService~containerResult} information for the container.
* `response` will contain information related to this operation.
*/
BlobService.prototype.getContainerProperties = function (container, optionsOrCallback, callback) {
var options;
azureutil.normalizeArgs(optionsOrCallback, callback, function (o, c) { options = o; callback = c; });
validate.validateArgs('getContainerProperties', function (v) {
v.string(container, 'container');
v.containerNameIsValid(container);
v.callback(callback);
});
var webResource = WebResource.head(container)
.withProperty(BlobConstants.ResourceTypeProperty, BlobConstants.ResourceTypes.CONTAINER)
.withProperty(BlobConstants.SharedAccessPermissionProperty, BlobConstants.SharedAccessPermissions.READ)
.withQueryOption(QueryStringConstants.RESTYPE, 'container');
if (options) {
if (options.leaseId) {
webResource.withHeader(HeaderConstants.LEASE_ID_HEADER, options.leaseId);
}
}
var self = this;
var processResponseCallback = function (responseObject, next) {
responseObject.containerResult = null;
if (!responseObject.error) {
responseObject.containerResult = new ContainerResult(container);
responseObject.containerResult.metadata = self.parseMetadataHeaders(responseObject.response.headers);
responseObject.containerResult.getPropertiesFromHeaders(responseObject.response.headers);
}
var finalCallback = function (returnObject) {
callback(returnObject.error, returnObject.containerResult, returnObject.response);
};
next(responseObject, finalCallback);
};
this.performRequest(webResource, null, options, processResponseCallback);
};
/**
* Returns all user-defined metadata for the container.
*
* @this {BlobService}
* @param {string} container The container name.
* @param {object} [options] The request options.
* @param {string} [options.leaseId] The target blob lease identifier.
* @param {int} [options.timeoutIntervalInMs] The timeout interval, in milliseconds, to use for the request.
* @param {Function(error, container, response)} callback `error` will contain information
* if an error occurs; otherwise `container` will contain
* the {@link BlobService~containerResult} information for the container.
* `response` will contain information related to this operation.
*/
BlobService.prototype.getContainerMetadata = function (container, optionsOrCallback, callback) {
var options;
azureutil.normalizeArgs(optionsOrCallback, callback, function (o, c) { options = o; callback = c; });
validate.validateArgs('getContainerMetadata', function (v) {
v.string(container, 'container');
v.containerNameIsValid(container);
v.callback(callback);
});
var webResource = WebResource.head(container)
.withProperty(BlobConstants.ResourceTypeProperty, BlobConstants.ResourceTypes.CONTAINER)
.withProperty(BlobConstants.SharedAccessPermissionProperty, BlobConstants.SharedAccessPermissions.READ)
.withQueryOption(QueryStringConstants.RESTYPE, 'container')
.withQueryOption(QueryStringConstants.COMP, 'metadata');
if (options) {
if (options.leaseId) {
webResource.withHeader(HeaderConstants.LEASE_ID_HEADER, options.leaseId);
}
}
var self = this;
var processResponseCallback = function (responseObject, next) {
responseObject.containerResult = null;
if (!responseObject.error) {
responseObject.containerResult = new ContainerResult(container);
responseObject.containerResult.metadata = self.parseMetadataHeaders(responseObject.response.headers);
responseObject.containerResult.getPropertiesFromHeaders(responseObject.response.headers);
}
var finalCallback = function (returnObject) {
callback(returnObject.error, returnObject.containerResult, returnObject.response);
};
next(responseObject, finalCallback);
};
this.performRequest(webResource, null, options, processResponseCallback);
};
/**
* Sets the container's metadata.
*
* Calling the Set Container Metadata operation overwrites all existing metadata that is associated with the container.
* It's not possible to modify an individual name/value pair.
*
* @this {BlobService}
* @param {string} container The container name.
* @param {object} metadata The metadata key/value pairs.
* @param {object} [options] The container and request options.
* @param {string} [options.leaseId] The target blob lease identifier.
* @param {object} [options.accessConditions] See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
* @param {int} [options.timeoutIntervalInMs] The timeout interval, in milliseconds, to use for the request.
* @param {Function(error, response)} callback `error` will contain information
* if an error occurs; otherwise
* `response` will contain information related to this operation.
*/
BlobService.prototype.setContainerMetadata = function (container, metadata, optionsOrCallback, callback) {
var options;
azureutil.normalizeArgs(optionsOrCallback, callback, function (o, c) { options = o; callback = c; });
validate.validateArgs('setContainerMetadata', function (v) {
v.string(container, 'container');
v.object(metadata, 'metadata');
v.containerNameIsValid(container);
v.callback(callback);
});
var webResource = WebResource.put(container)
.withProperty(BlobConstants.ResourceTypeProperty, BlobConstants.ResourceTypes.CONTAINER)
.withProperty(BlobConstants.SharedAccessPermissionProperty, BlobConstants.SharedAccessPermissions.WRITE)
.withQueryOption(QueryStringConstants.RESTYPE, 'container')
.withQueryOption(QueryStringConstants.COMP, 'metadata');
webResource.addOptionalMetadataHeaders(metadata);
if (options) {
if (options.leaseId) {
webResource.withHeader(HeaderConstants.LEASE_ID_HEADER, options.leaseId);
}
}
var processResponseCallback = function (responseObject, next) {
var finalCallback = function (returnObject) {
callback(returnObject.error, returnObject.response);
};
next(responseObject, finalCallback);
};
this.performRequest(webResource, null, options, processResponseCallback);
};
/**
* Gets the container's ACL.
*
* @this {BlobService}
* @param {string} container The container name.
* @param {object} [options] The container and request options.
* @param {string} [options.leaseId] The target blob lease identifier.
* @param {int} [options.timeoutIntervalInMs] The timeout interval, in milliseconds, to use for the request.
* @param {Function(error, container, response)} callback `error` will contain information
* if an error occurs; otherwise `container` will contain
* the {@link BlobService~containerResult} information for the container.
* `response` will contain information related to this operation.
*/
BlobService.prototype.getContainerAcl = function (container, optionsOrCallback, callback) {
var options;
azureutil.normalizeArgs(optionsOrCallback, callback, function (o, c) { options = o; callback = c; });
validate.validateArgs('getContainerAcl', function (v) {
v.string(container, 'container');
v.containerNameIsValid(container);
v.callback(callback);
});
var webResource = WebResource.get(container)
.withProperty(BlobConstants.ResourceTypeProperty, BlobConstants.ResourceTypes.CONTAINER)
.withProperty(BlobConstants.SharedAccessPermissionProperty, BlobConstants.SharedAccessPermissions.READ)
.withQueryOption(QueryStringConstants.RESTYPE, 'container')
.withQueryOption(QueryStringConstants.COMP, 'acl');
if (options) {
if (options.leaseId) {
webResource.withHeader(HeaderConstants.LEASE_ID_HEADER, options.leaseId);
}
}
var processResponseCallback = function (responseObject, next) {
responseObject.containerResult = null;
if (!responseObject.error) {
responseObject.containerResult = new ContainerResult(container);
responseObject.containerResult.getPropertiesFromHeaders(responseObject.response.headers);
responseObject.containerResult.signedIdentifiers = ContainerAclResult.parse(responseObject.response.body);
}
var finalCallback = function (returnObject) {
callback(returnObject.error, returnObject.containerResult, returnObject.response);
};
next(responseObject, finalCallback);
};
this.performRequest(webResource, null, options, processResponseCallback);
};
/**
* Updates the container's ACL.
*
* @this {BlobService}
* @param {string} container The container name.
* @param {string} publicAccessLevel Specifies whether data in the container may be accessed publicly and the level of access.
* @param {object} [options] The container and request options.
* @param {string} [options.leaseId] The target blob lease identifier.
* @param {object} [options.signedIdentifiers] The signed identifiers.
* @param {int} [options.timeoutIntervalInMs] The timeout interval, in milliseconds, to use for the request.
* @param {Function(error, container, response)} callback `error` will contain information
* if an error occurs; otherwise `container` will contain
* the {@link BlobService~containerResult} information for the container.
* `response` will contain information related to this operation.
*/
BlobService.prototype.setContainerAcl = function (container, publicAccessLevel, optionsOrCallback, callback) {
var options;
azureutil.normalizeArgs(optionsOrCallback, callback, function (o, c) { options = o; callback = c; });
validate.validateArgs('setContainerAcl', function (v) {
v.string(container, 'container');
v.containerNameIsValid(container);
v.callback(callback);
});
var policies = null;
if (options && options.signedIdentifiers) {
if (!_.isArray(options.signedIdentifiers)) {
throw new Error('Signed identifiers need to be an array');
}
policies = ContainerAclResult.serialize(options.signedIdentifiers);
}
var webResource = WebResource.put(container)
.withProperty(BlobConstants.ResourceTypeProperty, BlobConstants.ResourceTypes.CONTAINER)
.withProperty(BlobConstants.SharedAccessPermissionProperty, BlobConstants.SharedAccessPermissions.WRITE)
.withQueryOption(QueryStringConstants.RESTYPE, 'container')
.withQueryOption(QueryStringConstants.COMP, 'acl')
.withHeader(HeaderConstants.CONTENT_LENGTH, !azureutil.objectIsNull(policies) ? Buffer.byteLength(policies) : 0)
.withBody(policies);
if (publicAccessLevel) {
webResource.withHeader(HeaderConstants.BLOB_PUBLIC_ACCESS_HEADER, publicAccessLevel);
}
if (options) {
if (options.leaseId) {
webResource.withHeader(HeaderConstants.LEASE_ID_HEADER, options.leaseId);
}
}
var processResponseCallback = function (responseObject, next) {
responseObject.containerResult = null;
if (!responseObject.error) {
responseObject.containerResult = new ContainerResult(container, publicAccessLevel);
responseObject.containerResult.getPropertiesFromHeaders(responseObject.response.headers);
if (options && options.signedIdentifiers) {
responseObject.containerResult.signedIdentifiers = options.signedIdentifiers;
}
}
var finalCallback = function (returnObject) {
callback(returnObject.error, returnObject.containerResult, returnObject.response);
};
next(responseObject, finalCallback);
};
this.performRequest(webResource, webResource.body, options, processResponseCallback);
};
/**
* Marks the specified container for deletion.
* The container and any blobs contained within it are later deleted during garbage collection.
*
* @this {BlobService}
* @param {string} container The container name.
* @param {object} [options] The container and request options.
* @param {string} [options.leaseId] The target blob lease identifier.
* @param {int} [options.timeoutIntervalInMs] The timeout interval, in milliseconds, to use for the request.
* @param {Function(error, response)} callback `error` will contain information
* if an error occurs; otherwise
* `response` will contain information related to this operation.
*/
BlobService.prototype.deleteContainer = function (container, optionsOrCallback, callback) {
var options;
azureutil.normalizeArgs(optionsOrCallback, callback, function (o, c) { options = o; callback = c; });
validate.validateArgs('deleteContainer', function (v) {
v.string(container, 'container');
v.containerNameIsValid(container);
v.callback(callback);
});
var webResource = WebResource.del(container)
.withProperty(BlobConstants.ResourceTypeProperty, BlobConstants.ResourceTypes.CONTAINER)
.withProperty(BlobConstants.SharedAccessPermissionProperty, BlobConstants.SharedAccessPermissions.WRITE)
.withQueryOption(QueryStringConstants.RESTYPE, 'container');
if (options) {
if (options.leaseId) {
webResource.withHeader(HeaderConstants.LEASE_ID_HEADER, options.leaseId);
}
}
var processResponseCallback = function (responseObject, next) {
var finalCallback = function (returnObject) {
callback(returnObject.error, returnObject.response);
};
next(responseObject, finalCallback);
};
this.performRequest(webResource, null, options, processResponseCallback);
};
/**
* Lists all of the blobs in the given container.
*
* @this {BlobService}
* @param {string} container The container name.
* @param {object} [options] The listing and request options.
* @param {string} [options.prefix] The blob name prefix.
* @param {string} [options.delimiter] Delimiter, i.e. '/', for specifying folder hierarchy.
* @param {int} [options.maxresults] Specifies the maximum number of blobs to return per call to Azure ServiceClient. This does NOT affect list size returned by this function. (maximum: 5000)
* @param {string} [options.marker] String value that identifies the portion of the list to be returned with the next list operation.
* @param {string} [options.include] Specifies that the response should include one or more of the following subsets: '', 'metadata', 'snapshots', 'uncommittedblobs'). Multiple values can be added separated with a comma (,)
* @param {int} [options.timeoutIntervalInMs] The timeout interval, in milliseconds, to use for the request.
* @param {Function(error, blobs, response)} callback `error` will contain information
* if an error occurs; otherwise `blobs` will contain
* the blobs within the container.
* `response` will contain information related to this operation.
*/
BlobService.prototype.listBlobs = function (container, optionsOrCallback, callback) {
var options;
azureutil.normalizeArgs(optionsOrCallback, callback, function (o, c) { options = o; callback = c; });
validate.validateArgs('listBlobs', function (v) {
v.string(container, 'container');
v.containerNameIsValid(container);
v.callback(callback);
});
var webResource = WebResource.get(container)
.withProperty(BlobConstants.ResourceTypeProperty, BlobConstants.ResourceTypes.BLOB)
.withProperty(BlobConstants.SharedAccessPermissionProperty, BlobConstants.SharedAccessPermissions.LIST)
.withQueryOption(QueryStringConstants.RESTYPE, 'container')
.withQueryOption(QueryStringConstants.COMP, 'list')
.withQueryOptions(options,
QueryStringConstants.PREFIX,
QueryStringConstants.MARKER,
QueryStringConstants.MAX_RESULTS,
QueryStringConstants.DELIMITER,
QueryStringConstants.INCLUDE);
var self = this;
var processResponseCallback = function (responseObject, next) {
responseObject.listBlobsResult = null;
responseObject.listBlobsResultContinuation = null;
if (!responseObject.error) {
responseObject.listBlobsResult = [];
var blobs = [];
if (responseObject.response.body.EnumerationResults.Blobs.Blob) {
blobs = responseObject.response.body.EnumerationResults.Blobs.Blob;
if (!_.isArray(blobs)) {
blobs = [ blobs ];
}
}
blobs.forEach(function (currentBlob) {
var blobResult = BlobResult.parse(currentBlob);
responseObject.listBlobsResult.push(blobResult);
});
responseObject.listBlobsResultContinuation = new ListBlobsResultContinuation(self, container, options, responseObject.response.body.EnumerationResults.NextMarker);
}
var finalCallback = function (returnObject) {
callback(returnObject.error, returnObject.listBlobsResult, returnObject.listBlobsResultContinuation, returnObject.response);
};
next(responseObject, finalCallback);
};
this.performRequest(webResource, null, options, processResponseCallback);
};
/**
* Writes a range of pages to a page blob.
*
* @this {BlobService}
* @param {string} container The container name.
* @param {string} blob The blob name.
* @param {int} length The length of the page blob in bytes.
* @param {object} [options] The page blob and request options.
* @param {object} [options.metadata] The metadata key/value pairs.
* @param {string} [options.leaseId] The target blob lease identifier.
* @param {object} [options.accessConditions] The access conditions. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
* @param {int} [options.timeoutIntervalInMs] The timeout interval, in milliseconds, to use for the request.
* @param {Function(error, response)} callback `error` will contain information
* if an error occurs; otherwise
* `response` will contain information related to this operation.
*/
BlobService.prototype.createPageBlob = function (container, blob, length, optionsOrCallback, callback) {
var options;
azureutil.normalizeArgs(optionsOrCallback, callback, function (o, c) { options = o; callback = c; });
validate.validateArgs('createPageBlob', function (v) {
v.string(container, 'container');
v.string(blob, 'blob');
v.containerNameIsValid(container);
v.blobNameIsValid(container, blob);
v.callback(callback);
});
var resourceName = createResourceName(container, blob);
var webResource = WebResource.put(resourceName)
.withProperty(BlobConstants.ResourceTypeProperty, BlobConstants.ResourceTypes.BLOB)
.withProperty(BlobConstants.SharedAccessPermissionProperty, BlobConstants.SharedAccessPermissions.WRITE)
.withHeader(HeaderConstants.BLOB_TYPE_HEADER, BlobConstants.BlobTypes.PAGE)
.withHeader(HeaderConstants.CONTENT_LENGTH_HEADER, length)
.withHeader(HeaderConstants.CONTENT_LENGTH, 0);
if (options) {
webResource.withHeader(HeaderConstants.LEASE_ID_HEADER, options.leaseId);
webResource.addOptionalMetadataHeaders(options.metadata);
}
var processResponseCallback = function (responseObject, next) {
var finalCallback = function (returnObject) {
callback(returnObject.error, returnObject.response);
};
next(responseObject, finalCallback);
};
this.performRequest(webResource, null, options, processResponseCallback);
};
/**
* Creates a new block blob or page blob, or updates the content of an existing block blob.
* Updating an existing block blob overwrites any existing metadata on the blob. Partial updates are not supported with Put Blob; the content of the existing blob is overwritten with the content of the new blob. To perform a partial update of the content of a block blob, use the Put Block List operation.
* Calling Put Blob to create a page blob only initializes the blob. To add content to a page blob, call the Put Page operation.
*
* @this {BlobService}
* @param {string} container The container name.
* @param {string} blob The blob name.
* @param {string} localFilename The local path to the file to be uploaded.
* @param {object} [options] The creating and request options.
* @param {string} [options.leaseId] The lease identifier.
* @param {object} [options.metadata] The metadata key/value pairs.
* @param {bool} [options.setBlobContentMD5] Specifies whether the blob's ContentMD5 header should be set on uploads. This field is not supported for page blobs. The default value is false.
* @param {string} [options.contentType] The MIME content type of the blob. The default type is application/octet-stream.
* @param {string} [options.contentEncoding] The content encodings that have been applied to the blob.
* @param {string} [options.contentLanguage] The natural languages used by this resource.
* @param {string} [options.contentMD5] The MD5 hash of the blob content.
* @param {string} [options.cacheControl] The Blob service stores this value but does not use or modify it.
* @param {string} [options.contentTypeHeader] The blob’s content type. (x-ms-blob-content-type)
* @param {string} [options.contentEncodingHeader] The blob’s content encoding. (x-ms-blob-content-encoding)
* @param {string} [options.contentLanguageHeader] The blob's content language. (x-ms-blob-content-language)
* @param {string} [options.contentMD5Header] The blob’s MD5 hash. (x-ms-blob-content-md5)
* @param {string} [options.cacheControlHeader] The blob's cache control. (x-ms-blob-cache-control)
* @param {object} [options.accessConditions] The access conditions. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
* @param {int} [options.timeoutIntervalInMs] The timeout interval, in milliseconds, to use for the request.
* @param {Function(error, blockBlob, response)} callback `error` will contain information
* if an error occurs; otherwise `blockBlob` will contain
* information about the blob.
* `response` will contain information related to this operation.
* @return {undefined}
*/
BlobService.prototype.putBlockBlobFromFile = function (container, blob, localFilename, optionsOrCallback, callback) {
var options;
azureutil.normalizeArgs(optionsOrCallback, callback, function (o, c) { options = o; callback = c; });
validate.validateArgs('putBlockBlobFromFile', function (v) {
v.string(container, 'container');
v.string(blob, 'blob');
v.containerNameIsValid(container);
v.blobNameIsValid(container, blob);
v.callback(callback);
});
var self = this;
if (!options.speedSummary) {
options.speedSummary = new SpeedSummary(blob);
}
var operation = function (length, md5) {
if (md5 && !blob.contentMD5) {
blob.contentMD5 = md5;
}
if (!options) {
options = {};
}
if (options.contentType === undefined) {
options.contentType = mime.getType(localFilename);
}
if (options.contentTypeHeader === undefined) {
options.contentTypeHeader = mime.getType(localFilename);
}
if (length >= BlobConstants.MAX_SINGLE_UPLOAD_BLOB_SIZE_IN_BYTES) {
throw new Error('Invalid file size for a single block. Please use the createBlockBlobFromFile to upload large file.');
} else {
var readStream = fs.createReadStream(localFilename);
self.putBlockBlobFromStream(container, blob, readStream, length, options, callback);
}
};
var calculateMD5 = (options && options.setBlobContentMD5 && !options[HeaderConstants.CONTENT_MD5]);
if (calculateMD5) {
var stream = fs.createReadStream(localFilename);
azureutil.analyzeStream(stream, calculateMD5, operation);
} else {
fs.stat(localFilename, function (statErr, stat) {
if (statErr) {
callback(statErr);
} else {
operation(stat.size);
}
});
}
return options.speedSummary;
};
/**
* Uploads a block blob from a stream.
*
* @this {BlobService}
* @param {string} container The container name.
* @param {string} blob The blob name.
* @param (Stream) stream Stream to the data to store.
* @param {int} streamLength The length of the stream to upload.
* @param {object} [options] The creating and request options.
* @param {string} [options.leaseId] The lease identifier.
* @param {object} [options.metadata] The metadata key/value pairs.
* @param {bool} [options.setBlobContentMD5] Specifies whether the blob's ContentMD5 header should be set on uploads. This field is not supported for page blobs. The default value is false.
* @param {string} [options.contentType] The MIME content type of the blob. The default type is application/octet-stream.
* @param {string} [options.contentEncoding] The content encodings that have been applied to the blob.
* @param {string} [options.contentLanguage] The natural languages used by this resource.
* @param {string} [options.contentMD5] The MD5 hash of the blob content.
* @param {string} [options.cacheControl] The Blob service stores this value but does not use or modify it.
* @param {string} [options.contentTypeHeader] The blob’s content type. (x-ms-blob-content-type)
* @param {string} [options.contentEncodingHeader] The blob’s content encoding. (x-ms-blob-content-encoding)
* @param {string} [options.contentLanguageHeader] The blob's content language. (x-ms-blob-content-language)
* @param {string} [options.contentMD5Header] The blob’s MD5 hash. (x-ms-blob-content-md5)
* @param {string} [options.cacheControlHeader] The blob's cache control. (x-ms-blob-cache-control)
* @param {object} [options.accessConditions] The access conditions. See http://msdn.microsoft.com/en-us/library/dd179371.aspx for more information.
* @param {int} [options.timeoutIntervalInMs] The timeout interval, in milliseconds, to use for the request.
* @param {Function(error, blockBlob, response)} callback `error` will contain information
* if an error occurs; otherwise `blockBlob` will contain
* information about the blob.
* `response` will contain information related to this operation.
* @return {undefined}
*
* @example
* var azure = require('azure');
* var blobService = azure.createBlobService();
* blobService.putBlockBlobFromStream('taskcontainer', 'task1', fs.createReadStream('task1-upload.txt'), 11, function(error) {
* if(!error) {
* // Blob uploaded
* }
* });
*/
BlobService.prototype.putBlockBlobFromStream = function (container, blob, readStream, streamLength, optionsOrCallback, callback) {
var options;
azureutil.normalizeArgs(optionsOrCallback, callback, function (o, c) { options = o; callback = c; });
validate.validateArgs('putBlockBlobFromStream', fu