// // 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 _ = require('underscore'); var azureCommon = require('./../../../common/common.core'); var azureutil = azureCommon.util; var Constants = azureCommon.Constants; var HeaderConstants = Constants.HeaderConstants; /** * Creates a new BlobResult object. * @class * The BlobResult class is used to store the blob information. * * @property {string} container The container name. * @property {string} name The blob name. * @property {object} metadata The metadata key/value pair. * @property {string} etag The etag. * @property {string} lastModified The date/time that the blob was last modified. * @property {string} contentLength The size of the blob in bytes. * @property {string} blobType The blob type. * @property {boolean} isIncrementalCopy If the blob is incremental copy blob. * @property {string} requestId The request id. * @property {string} sequenceNumber The current sequence number for a page blob. * @property {string} contentRange The content range. * @property {string} committedBlockCount The committed block count. * @property {string} serverEncrypted If the blob data and application metadata are completely encrypted using the specified algorithm. true/false. * @property {object} contentSettings The content settings. * @property {string} contentSettings.contentType The content type. * @property {string} contentSettings.contentEncoding The content encoding. * @property {string} contentSettings.contentLanguage The content language. * @property {string} contentSettings.cacheControl The cache control. * @property {string} contentSettings.contentDisposition The content disposition. * @property {string} contentSettings.contentMD5 The content MD5 hash. * @property {object} lease The lease information. * @property {string} lease.id The lease id. * @property {string} lease.status The lease status. * @property {string} lease.state The lease state. * @property {string} lease.duration The lease duration. * @property {object} copy The copy information. * @property {string} copy.id The copy id. * @property {string} copy.status The copy status. * @property {string} copy.completionTime The copy completion time. * @property {string} copy.statusDescription The copy status description. * @property {string} copy.destinationSnapshot The snapshot time of the last successful incremental copy snapshot for this blob. * @property {string} copy.progress The copy progress. * @property {string} copy.source The copy source. * * @constructor * @param {string} [container] The container name. * @param {string} [name] The blob name. */ function BlobResult(container, name) { if (container) { this.container = container; } if (name) { this.name = name; } } BlobResult.parse = function (blobXml) { var blobResult = new BlobResult(); for (var propertyName in blobXml) { if (blobXml.hasOwnProperty(propertyName)) { if (propertyName === 'Properties') { // Lift out the properties onto the main object to keep consistent across all APIs like: getBlobProperties azureutil.setPropertyValueFromXML(blobResult, blobXml[propertyName], true); } else if (propertyName === 'Metadata') { var resultPropertyName = azureutil.normalizePropertyNameFromXML(propertyName); blobResult[resultPropertyName] = {}; azureutil.setPropertyValueFromXML(blobResult[resultPropertyName], blobXml[propertyName], false); } else { blobResult[propertyName.toLowerCase()] = blobXml[propertyName]; } } } if (blobResult.isIncrementalCopy !== undefined) { blobResult.isIncrementalCopy = (blobResult.isIncrementalCopy === 'true'); } // convert accessTierInferred to boolean type if (blobResult.accessTierInferred !== undefined) { blobResult.accessTierInferred = (blobResult.accessTierInferred === 'true'); } if (blobResult.deleted !== undefined) { blobResult.deleted = (blobResult.deleted == 'true'); } if (blobResult.remainingRetentionDays !== undefined) { blobResult.remainingRetentionDays = parseInt(blobResult.remainingRetentionDays); } return blobResult; }; var headersForProperties = { 'lastModified': 'LAST_MODIFIED', 'creationTime': 'CREATION_TIME', 'etag': 'ETAG', 'sequenceNumber': 'SEQUENCE_NUMBER', 'blobType': 'BLOB_TYPE', 'contentLength': 'CONTENT_LENGTH', 'blobContentLength': 'BLOB_CONTENT_LENGTH', 'contentRange': 'CONTENT_RANGE', 'committedBlockCount': 'BLOB_COMMITTED_BLOCK_COUNT', 'serverEncrypted': 'SERVER_ENCRYPTED', 'requestId': 'REQUEST_ID', 'range': 'RANGE', 'blobRange': 'STORAGE_RANGE', 'getContentMd5': 'RANGE_GET_CONTENT_MD5', 'acceptRanges': 'ACCEPT_RANGES', 'appendOffset': 'BLOB_APPEND_OFFSET', 'accessTier': 'ACCESS_TIER', 'accessTierChangeTime': 'ACCESS_TIER_CHANGE_TIME', 'accessTierInferred': 'ACCESS_TIER_INFERRED', 'archiveStatus': 'ARCHIVE_STATUS', 'isIncrementalCopy': 'INCREMENTAL_COPY', // ContentSettings 'contentSettings.contentType': 'CONTENT_TYPE', 'contentSettings.contentEncoding': 'CONTENT_ENCODING', 'contentSettings.contentLanguage': 'CONTENT_LANGUAGE', 'contentSettings.cacheControl': 'CACHE_CONTROL', 'contentSettings.contentDisposition': 'CONTENT_DISPOSITION', 'contentSettings.contentMD5': 'CONTENT_MD5', // Lease 'lease.id': 'LEASE_ID', 'lease.status': 'LEASE_STATUS', 'lease.duration': 'LEASE_DURATION', 'lease.state': 'LEASE_STATE', // Copy 'copy.id': 'COPY_ID', 'copy.status': 'COPY_STATUS', 'copy.source': 'COPY_SOURCE', 'copy.progress': 'COPY_PROGRESS', 'copy.completionTime': 'COPY_COMPLETION_TIME', 'copy.statusDescription': 'COPY_STATUS_DESCRIPTION', 'copy.destinationSnapshot': 'COPY_DESTINATION_SNAPSHOT' }; BlobResult.prototype.getPropertiesFromHeaders = function (headers) { var self = this; var setBlobPropertyFromHeaders = function (blobProperty, headerProperty) { if (!azureutil.tryGetValueChain(self, blobProperty.split('.'), null) && headers[headerProperty.toLowerCase()]) { azureutil.setObjectInnerPropertyValue(self, blobProperty.split('.'), headers[headerProperty.toLowerCase()]); if (blobProperty === 'copy.progress') { var info = azureutil.parseCopyProgress(self.copy.progress); self.copy.bytesCopied = parseInt(info.bytesCopied); self.copy.totalBytes = parseInt(info.totalBytes); } } }; // For range get, 'x-ms-blob-content-md5' indicate the overall MD5 of the blob. Try to set the contentMD5 using this header if it presents setBlobPropertyFromHeaders('contentSettings.contentMD5', HeaderConstants.BLOB_CONTENT_MD5); _.chain(headersForProperties).pairs().each(function (pair) { var property = pair[0]; var header = HeaderConstants[pair[1]]; setBlobPropertyFromHeaders(property, header); }); // convert isIncrementalCopy to boolean type if (self.isIncrementalCopy !== undefined) { self.isIncrementalCopy = (self.isIncrementalCopy === 'true'); } // convert accessTierInferred to boolean type if (self.accessTierInferred !== undefined) { self.accessTierInferred = (self.accessTierInferred == 'true'); } }; /** * This method sets the HTTP headers and is used by all methods except setBlobProperties and commitBlocks. Those 2 methods will set the x-ms-* headers using setPropertiesFromBlob. * @ignore */ BlobResult.setHeadersFromBlob = function (webResource, blob) { var setHeaderPropertyFromBlob = function (headerProperty, blobProperty) { var blobPropertyValue = azureutil.tryGetValueChain(blob, blobProperty.split('.'), null); if (blobPropertyValue) { webResource.withHeader(headerProperty, blobPropertyValue); } }; if (blob) { // Content-Type setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_TYPE, 'contentSettings.contentType'); // Content-Encoding setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_ENCODING, 'contentSettings.contentEncoding'); // Content-Language setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_LANGUAGE, 'contentSettings.contentLanguage'); // Content-Disposition setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_DISPOSITION, 'contentSettings.contentDisposition'); // Cache-Control setHeaderPropertyFromBlob(HeaderConstants.BLOB_CACHE_CONTROL, 'contentSettings.cacheControl'); // Blob's Content-MD5 setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_MD5, 'contentSettings.contentMD5'); // Content-Length setHeaderPropertyFromBlob(HeaderConstants.CONTENT_LENGTH, 'contentLength'); // transactional Content-MD5 setHeaderPropertyFromBlob(HeaderConstants.CONTENT_MD5, 'transactionalContentMD5'); // Range if (!azureutil.objectIsNull(blob.rangeStart)) { var range = 'bytes=' + blob.rangeStart + '-'; if (!azureutil.objectIsNull(blob.rangeEnd)) { range += blob.rangeEnd; } webResource.withHeader(HeaderConstants.RANGE, range); } // Source Range if (!azureutil.objectIsNull(blob.sourceRangeStart)) { var sourceRange = 'bytes=' + blob.sourceRangeStart + '-'; if (!azureutil.objectIsNull(blob.sourceRangeEnd)) { sourceRange += blob.sourceRangeEnd; } webResource.withHeader(HeaderConstants.SOURCE_RANGE, sourceRange); } // Blob Type setHeaderPropertyFromBlob(HeaderConstants.BLOB_TYPE, 'blobType'); // Lease id setHeaderPropertyFromBlob(HeaderConstants.LEASE_ID, 'leaseId'); // Sequence number setHeaderPropertyFromBlob(HeaderConstants.SEQUENCE_NUMBER, 'sequenceNumber'); setHeaderPropertyFromBlob(HeaderConstants.SEQUENCE_NUMBER_ACTION, 'sequenceNumberAction'); if (blob.metadata) { webResource.addOptionalMetadataHeaders(blob.metadata); } } }; /** * This method sets the x-ms-* headers and is used by setBlobProperties and commitBlocks. All other methods will set the regular HTTP headers using setHeadersFromBlob. * @ignore */ BlobResult.setPropertiesFromBlob = function (webResource, blob) { var setHeaderPropertyFromBlob = function (headerProperty, blobProperty) { var propertyValue = azureutil.tryGetValueChain(blob, blobProperty.split('.'), null); if (propertyValue) { webResource.withHeader(headerProperty, propertyValue); } }; if (blob) { // Content-Type setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_TYPE, 'contentSettings.contentType'); // Content-Encoding setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_ENCODING, 'contentSettings.contentEncoding'); // Content-Language setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_LANGUAGE, 'contentSettings.contentLanguage'); // Content-Disposition setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_DISPOSITION, 'contentSettings.contentDisposition'); // Cache-Control setHeaderPropertyFromBlob(HeaderConstants.BLOB_CACHE_CONTROL, 'contentSettings.cacheControl'); // Content-MD5 setHeaderPropertyFromBlob(HeaderConstants.BLOB_CONTENT_MD5, 'contentSettings.contentMD5'); // Lease id setHeaderPropertyFromBlob(HeaderConstants.LEASE_ID, 'leaseId'); if (blob.metadata) { webResource.addOptionalMetadataHeaders(blob.metadata); } } }; module.exports = BlobResult;