fast-azure-storage
Advanced tools
Comparing version 0.3.7 to 1.0.0
@@ -26,3 +26,4 @@ 'use strict'; | ||
lazyExportModule('Queue', './queue'); | ||
lazyExportModule('Blob', './blob'); | ||
lazyExportModule('Table', './table'); | ||
lazyExportModule('Agent', './agent'); |
202
lib/queue.js
@@ -13,2 +13,3 @@ 'use strict'; | ||
var xml = require('./xml-parser'); | ||
var auth = require('./authorization'); | ||
@@ -34,12 +35,2 @@ /* | ||
/* | ||
* List of x-ms-* headers supported in lexicographical order, used for | ||
* construction of the canonicalized headers. | ||
*/ | ||
var X_MS_HEADERS_SUPPORTED = [ | ||
'x-ms-client-request-id', | ||
'x-ms-date', | ||
'x-ms-version' | ||
].sort(); | ||
/* | ||
* List of query-string parameter supported in lexicographical order, used for | ||
@@ -62,170 +53,2 @@ * construction of the canonicalized resource. | ||
/* | ||
* Authorize the request with shared key | ||
* Intended to define `Queue.prototype.authorize`. | ||
*/ | ||
var authorizeWithSharedKey = function (method, path, query, headers) { | ||
// Find account id | ||
var accountId = this.options.accountId; | ||
// Build string to sign | ||
var stringToSign = ( | ||
method + '\n' + | ||
(headers['content-encoding'] || '') + '\n' + | ||
(headers['content-language'] || '') + '\n' + | ||
(headers['content-length'] || '') + '\n' + | ||
(headers['content-md5'] || '') + '\n' + | ||
(headers['content-type'] || '') + '\n' + | ||
'\n' + // we always include x-ms-date, so we never specify date header | ||
(headers['if-modified-since'] || '') + '\n' + | ||
(headers['if-match'] || '') + '\n' + | ||
(headers['if-none-match'] || '') + '\n' + | ||
(headers['if-unmodified-since'] || '') + '\n' + | ||
(headers['range'] || '') | ||
); | ||
// Check if we have meta-data header fields, if we don't we can use a | ||
// presorted list of headers which doesn't involve any allocations. | ||
// Otherwise, we callback to building a list of 'x-ms-' prefixed headers and | ||
// sorting it. | ||
var hasMetadata = false; | ||
for (var field in headers) { | ||
hasMetadata = hasMetadata || /^x-ms-meta/.test(field); | ||
} | ||
var fields; | ||
if (hasMetadata) { | ||
// Construct fields as a sorted list of 'x-ms-' prefixed headers | ||
fields = []; | ||
for (var field in headers) { | ||
if (/^x-ms-/.test(field)) { | ||
fields.push(field); | ||
} | ||
} | ||
fields.sort(); | ||
} else { | ||
// Fields used in most API methods presorted in lexicographical order. | ||
fields = X_MS_HEADERS_SUPPORTED; | ||
} | ||
// Add lines for canonicalized headers using presorted list of fields | ||
var N = fields.length; | ||
for(var i = 0; i < N; i++) { | ||
var field = fields[i]; | ||
var value = headers[field]; | ||
if (value) { | ||
stringToSign += '\n' + field + ':' + value; | ||
} | ||
} | ||
// Added lines from canonicalized resource and query-string parameters | ||
// supported by this library in lexicographical order as presorted in | ||
// QUERY_PARAMS_SUPPORTED | ||
stringToSign += '\n/' + accountId + path; | ||
var M = QUERY_PARAMS_SUPPORTED.length; | ||
for(var j = 0; j < M; j++) { | ||
var param = QUERY_PARAMS_SUPPORTED[j]; | ||
var value = query[param]; | ||
if (value) { | ||
stringToSign += '\n' + param + ':' + value; | ||
} | ||
} | ||
// Compute signature | ||
var signature = crypto | ||
.createHmac('sha256', this._accessKey) | ||
.update(stringToSign) | ||
.digest('base64'); | ||
// Set authorization header | ||
headers.authorization = 'SharedKey ' + accountId + ':' + signature; | ||
// Encode query string | ||
var qs = querystring.stringify(query); | ||
// Construct request options | ||
return Promise.resolve({ | ||
host: this.hostname, | ||
method: method, | ||
path: (qs.length > 0 ? path + '?' + qs : path), | ||
headers: headers, | ||
agent: this.options.agent, | ||
}); | ||
} | ||
/* | ||
* Authorize the request with a shared-access-signature that is refreshed with | ||
* the a function given as `options.sas`. | ||
* Intended to define `Queue.prototype.authorize`. | ||
*/ | ||
function authorizeWithRefreshSAS(method, path, query, headers) { | ||
var self = this; | ||
// Check if we should refresh SAS | ||
if (Date.now() > this._nextSASRefresh && this._nextSASRefresh !== 0) { | ||
debug("Refreshing shared-access-signature"); | ||
// Avoid refreshing more than once | ||
this._nextSASRefresh = 0; | ||
// Refresh SAS | ||
this._sas = Promise.resolve(this.options.sas()); | ||
// Update _nextSASRefresh when the SAS has been refreshed | ||
this._sas.then(function(sas) { | ||
sas = querystring.parse(sas); | ||
// Find next sas refresh time | ||
self._nextSASRefresh = ( | ||
new Date(sas.se).getTime() - self.options.minSASAuthExpiry | ||
); | ||
debug("Refreshed shared-access-signature, will refresh in %s ms", | ||
self._nextSASRefresh); | ||
// Throw an error if the signature expiration comes too soon | ||
if (Date.now() > self._nextSASRefresh) { | ||
throw new Error("Refreshed SAS, but got a Shared-Access-Signature " + | ||
"that expires less than options.minSASAuthExpiry " + | ||
"from now, signature expiry: " + sas.se); | ||
} | ||
}).catch(function(err) { | ||
// If we have an error freshing SAS that's bad and we'll emit it; for most | ||
// apps it's probably best to ignore this error and just crash. | ||
self.emit('error', err); | ||
}); | ||
} | ||
// Construct request options, whenever the `_sas` promise is resolved. | ||
return this._sas.then(function(sas) { | ||
// Serialize query-string | ||
var qs = querystring.stringify(query); | ||
if (qs.length > 0) { | ||
qs += '&'; | ||
} | ||
qs += sas | ||
return { | ||
host: self.hostname, | ||
method: method, | ||
path: path + '?' + qs, | ||
headers: headers, | ||
agent: self.options.agent, | ||
}; | ||
}); | ||
} | ||
/* | ||
* Authorize the request with a shared-access-signature that is given with | ||
* `options.sas` as string. | ||
* Intended to define `Queue.prototype.authorize`. | ||
*/ | ||
function authorizeWithSAS(method, path, query, headers) { | ||
// Serialize query-string | ||
var qs = querystring.stringify(query); | ||
if (qs.length > 0) { | ||
qs += '&'; | ||
} | ||
qs += this.options.sas; | ||
// Construct request options | ||
return Promise.resolve({ | ||
host: this.hostname, | ||
method: method, | ||
path: path + '?' + qs, | ||
headers: headers, | ||
agent: this.options.agent, | ||
}); | ||
} | ||
/** | ||
@@ -330,3 +153,3 @@ * Queue client class for interacting with Azure Queue Storage. | ||
// If set authorize to use shared key signatures | ||
this.authorize = authorizeWithSharedKey; | ||
this.authorize = auth.authorizeWithSharedKey.call(this, 'queue', QUERY_PARAMS_SUPPORTED); | ||
// Decode accessKey | ||
@@ -336,3 +159,3 @@ this._accessKey = new Buffer(this.options.accessKey, 'base64'); | ||
// Set authorize to use shared-access-signatures with refresh function | ||
this.authorize = authorizeWithRefreshSAS; | ||
this.authorize = auth.authorizeWithRefreshSAS; | ||
// Set state with _nextSASRefresh = -1, we'll refresh on the first request | ||
@@ -343,3 +166,3 @@ this._nextSASRefresh = -1; | ||
// Set authorize to use shared-access-signature as hardcoded | ||
this.authorize = authorizeWithSAS; | ||
this.authorize = auth.authorizeWithSAS; | ||
} else { | ||
@@ -429,6 +252,3 @@ throw new Error("Either options.accessKey, options.sas as function or " + | ||
// Compute signature | ||
query.sig = crypto | ||
.createHmac('sha256', this._accessKey) | ||
.update(stringToSign) | ||
.digest('base64'); | ||
query.sig = utils.hmacSha256(this._accessKey, stringToSign);; | ||
@@ -505,3 +325,3 @@ // Return Shared-Access-Signature as query-string | ||
// Parse error message | ||
var data = xml.queueParseError(res); | ||
var data = xml.parseError(res); | ||
@@ -663,12 +483,6 @@ // Construct error object | ||
} | ||
// Extract meta-data | ||
var metadata = {}; | ||
for(var field in res.headers) { | ||
if (/x-ms-meta-/.test(field)) { | ||
metadata[field.substr(10)] = res.headers[field]; | ||
} | ||
} | ||
return { | ||
messageCount: parseInt(res.headers['x-ms-approximate-messages-count']), | ||
metadata: metadata | ||
metadata: utils.extractMetadataFromHeaders(res) | ||
}; | ||
@@ -675,0 +489,0 @@ }); |
@@ -12,2 +12,3 @@ 'use strict'; | ||
var utils = require('./utils'); | ||
var auth = require('./authorization'); | ||
@@ -52,6 +53,3 @@ /* Transient error codes (we'll retry request when encountering these codes */ | ||
// Compute signature | ||
var signature = crypto | ||
.createHmac('sha256', this._accessKey) | ||
.update(stringToSign) | ||
.digest('base64'); | ||
var signature = utils.hmacSha256(this._accessKey, stringToSign); | ||
@@ -74,82 +72,2 @@ // Set authorization header | ||
/* | ||
* Authorize the request with a shared-access-signature that is refreshed with | ||
* the a function given as `options.sas`. | ||
* Intended to define `Table.prototype.authorize`. | ||
*/ | ||
function authorizeWithRefreshSAS(method, path, query, headers) { | ||
var self = this; | ||
// Check if we should refresh SAS | ||
if (Date.now() > this._nextSASRefresh && this._nextSASRefresh !== 0) { | ||
debug("Refreshing shared-access-signature"); | ||
// Avoid refreshing more than once | ||
this._nextSASRefresh = 0; | ||
// Refresh SAS | ||
this._sas = Promise.resolve(this.options.sas()); | ||
// Update _nextSASRefresh when the SAS has been refreshed | ||
this._sas.then(function(sas) { | ||
sas = querystring.parse(sas); | ||
// Find next sas refresh time | ||
self._nextSASRefresh = ( | ||
new Date(sas.se).getTime() - self.options.minSASAuthExpiry | ||
); | ||
debug("Refreshed shared-access-signature, will refresh in %s ms", | ||
self._nextSASRefresh); | ||
// Throw an error if the signature expiration comes too soon | ||
if (Date.now() > self._nextSASRefresh) { | ||
throw new Error("Refreshed SAS, but got a Shared-Access-Signature " + | ||
"that expires less than options.minSASAuthExpiry " + | ||
"from now, signature expiry: " + sas.se); | ||
} | ||
}).catch(function(err) { | ||
// If we have an error freshing SAS that's bad and we'll emit it; for most | ||
// apps it's probably best to ignore this error and just crash. | ||
self.emit('error', err); | ||
}); | ||
} | ||
// Construct request options, whenever the `_sas` promise is resolved. | ||
return this._sas.then(function(sas) { | ||
// Serialize query-string | ||
var qs = querystring.stringify(query); | ||
if (qs.length > 0) { | ||
qs += '&'; | ||
} | ||
qs += sas | ||
return { | ||
host: self.hostname, | ||
method: method, | ||
path: path + '?' + qs, | ||
headers: headers, | ||
agent: self.options.agent, | ||
}; | ||
}); | ||
} | ||
/* | ||
* Authorize the request with a shared-access-signature that is given with | ||
* `options.sas` as string. | ||
* Intended to define `Table.prototype.authorize`. | ||
*/ | ||
function authorizeWithSAS(method, path, query, headers) { | ||
// Serialize query-string | ||
var qs = querystring.stringify(query); | ||
if (qs.length > 0) { | ||
qs += '&'; | ||
} | ||
qs += this.options.sas; | ||
// Construct request options | ||
return Promise.resolve({ | ||
host: this.hostname, | ||
method: method, | ||
path: path + '?' + qs, | ||
headers: headers, | ||
agent: this.options.agent, | ||
}); | ||
} | ||
/** | ||
@@ -272,3 +190,3 @@ * Table client class for interacting with Azure Table Storage. | ||
// If set authorize to use shared key signatures | ||
this.authorize = authorizeWithSharedKey; | ||
this.authorize = auth.authorizeWithSharedKey.call(this, 'table'); | ||
// Decode accessKey | ||
@@ -278,3 +196,3 @@ this._accessKey = new Buffer(this.options.accessKey, 'base64'); | ||
// Set authorize to use shared-access-signatures with refresh function | ||
this.authorize = authorizeWithRefreshSAS; | ||
this.authorize = auth.authorizeWithRefreshSAS; | ||
// Set state with _nextSASRefresh = -1, we'll refresh on the first request | ||
@@ -285,3 +203,3 @@ this._nextSASRefresh = -1; | ||
// Set authorize to use shared-access-signature as hardcoded | ||
this.authorize = authorizeWithSAS; | ||
this.authorize = auth.authorizeWithSAS; | ||
} else { | ||
@@ -394,6 +312,3 @@ throw new Error("Either options.accessKey, options.sas as function or " + | ||
// Compute signature | ||
query.sig = crypto | ||
.createHmac('sha256', this._accessKey) | ||
.update(stringToSign) | ||
.digest('base64'); | ||
query.sig = utils.hmacSha256(this._accessKey, stringToSign); | ||
@@ -400,0 +315,0 @@ // Return Shared-Access-Signature as query-string |
141
lib/utils.js
@@ -5,2 +5,6 @@ 'use strict'; | ||
var https = require('https'); | ||
var crypto = require('crypto'); | ||
var querystring = require('querystring'); | ||
var debug = require('debug')('azure:utils'); | ||
var assert = require('assert'); | ||
@@ -11,3 +15,3 @@ /* | ||
* @param {Number} delay - Number of ms to sleep. | ||
* @returns {Promise} A romise that will be resolved after `delay` ms | ||
* @returns {Promise} A promise that will be resolved after `delay` ms | ||
*/ | ||
@@ -178,3 +182,3 @@ var sleep = function sleep(delay) { | ||
var contentLength = res.headers['content-length']; | ||
if (contentLength) { | ||
if (contentLength && options.method !== 'HEAD') { | ||
var length = Buffer.byteLength(res.payload, 'utf8'); | ||
@@ -232,1 +236,134 @@ if (length !== parseInt(contentLength)) { | ||
exports.parseJSON = parseJSON; | ||
/* | ||
* Extracts the metadata from HTTP response header | ||
* | ||
* @param {object} response - HTTP response | ||
* @returns {object} Mapping from meta-data keys to values | ||
*/ | ||
var extractMetadataFromHeaders = function extractMetadataFromHeaders(response) { | ||
var metadata = {}; | ||
/* | ||
* Metadata names must be valid C# identifiers and are case-insensitive, but case preserving, | ||
* meaning that you can set,for example, a metadata with the following form: | ||
* { | ||
* applicationName: 'fast-azure-blob-storage' | ||
* } | ||
* In order to return the original metadata name, the header names should be read from response.rawHeaders. | ||
* That is because 'https' library returns the response headers with lowercase. | ||
* The response.rawHeaders is a list that contains the raw header names and values. It is NOT a list of tuples. | ||
* So, the even-numbered offsets are key values, and the odd-numbered offsets are the associated values. | ||
*/ | ||
for(var i = 0; i < response.rawHeaders.length; i += 2) { | ||
var key = response.rawHeaders[i]; | ||
if (/x-ms-meta-/.test(key)) { | ||
metadata[key.substr(10)] = response.headers[key.toLowerCase()]; | ||
} | ||
} | ||
return metadata; | ||
} | ||
exports.extractMetadataFromHeaders = extractMetadataFromHeaders; | ||
/* | ||
* Checks if the given value is a valid GUID | ||
* | ||
* A string that contains a GUID in one of the following formats (`d` represents a hexadecimal digit whose case is ignored): | ||
* | ||
* - 32 contiguous digits: dddddddddddddddddddddddddddddddd | ||
* - Groups of 8, 4, 4, 4, and 12 digits with hyphens between the groups | ||
* dddddddd-dddd-dddd-dddd-dddddddddddd | ||
* -or- | ||
* {dddddddd-dddd-dddd-dddd-dddddddddddd} | ||
* -or- | ||
* (dddddddd-dddd-dddd-dddd-dddddddddddd) | ||
* -Groups of 8, 4, and 4 digits, and a subset of eight groups of 2 digits, with each group prefixed by "0x" or "0X", and separated by commas. | ||
* {0xdddddddd, 0xdddd, 0xdddd,{0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd,0xdd}} | ||
* | ||
* @param {string} value - String value to be verified | ||
* @returns {boolean} True if the value is a valid GUID | ||
*/ | ||
var isValidGUID = function isValidGUID(value) { | ||
// remove all embedded whitespaces | ||
value = value.replace(/\s/g, ''); | ||
var patterns = [ | ||
/^[0-9a-fA-F]{1,32}$/i, | ||
/^[0-9a-fA-F]{1,8}(-[0-9a-fA-F]{1,4}){3}-[0-9a-fA-F]{1,12}$/i, | ||
/^\{[0-9a-fA-F]{1,8}(-[0-9a-fA-F]{1,4}){3}-[0-9a-fA-F]{1,12}\}$/i, | ||
/^\([0-9a-fA-F]{1,8}(-[0-9a-fA-F]{1,4}){3}-[0-9a-fA-F]{1,12}\)$/i, | ||
/^\{0x[0-9a-fA-F]{1,8}(,0x[0-9a-fA-F]{1,4}){2},\{0x[0-9a-fA-F]{1,2}(,0x[0-9a-fA-F]{1,2}){7}\}\}$/i | ||
]; | ||
for (var x = 0 ; x < patterns.length ; x++) { | ||
if (patterns[x].test(value)) { | ||
return true; | ||
} | ||
} | ||
return false; | ||
} | ||
exports.isValidGUID = isValidGUID; | ||
/* | ||
* @param {object} headers - request headers | ||
* @param {object} conditionalHeaders - Conditional headers on the following form | ||
* ```js | ||
* { | ||
* ifModifiedSince: new Date(), // Specify this to perform the operation only if the resource has been modified since the specified time. (optional) | ||
* ifUnmodifiedSince: new Date(), // Specify this to perform the operation only if the resource has not been modified since the specified date/time. (optional) | ||
* ifMatch: '...', // ETag value. Specify this to perform the operation only if the resource's ETag matches the value specified. (optional) | ||
* ifNoneMatch: '...' // ETag value. Specify this to perform the operation only if the resource's ETag does not match the value specified. (optional) | ||
* } | ||
*``` | ||
* @param {boolean} onlyDateSupport - true if the request supports only the if-modified-since and if-unmodified-since conditional headers | ||
*/ | ||
var setConditionalHeaders = function setConditionalHeaders(headers, conditionalHeaders, onlyDateSupport) { | ||
if (conditionalHeaders) { | ||
if (conditionalHeaders.ifModifiedSince){ | ||
assert(conditionalHeaders.ifModifiedSince instanceof Date, | ||
'If specified, the `options.ifModifiedSince` must be a Date'); | ||
headers['if-modified-since'] = conditionalHeaders.ifModifiedSince.toUTCString(); | ||
} | ||
if (conditionalHeaders.ifUnmodifiedSince) { | ||
assert(conditionalHeaders.ifUnmodifiedSince instanceof Date, | ||
'If specified, the `options.ifUnmodifiedSince` must be a Date'); | ||
headers['if-unmodified-since'] = conditionalHeaders.ifUnmodifiedSince.toUTCString(); | ||
} | ||
if (!onlyDateSupport) { | ||
if (conditionalHeaders.ifMatch) headers['if-match'] = conditionalHeaders.ifMatch; | ||
if (conditionalHeaders.ifNoneMatch) headers['if-none-match'] = conditionalHeaders.ifNoneMatch; | ||
} | ||
} | ||
} | ||
exports.setConditionalHeaders = setConditionalHeaders; | ||
/* | ||
* Computes a signature for the specified string using the HMAC-SHA256 algorithm. | ||
* | ||
* @param {string} accessKey - The access key | ||
* @param {string} stringToSign - The UTF-8-encoded string to sign. | ||
* @return A String that contains the HMAC-SHA256-encoded signature. | ||
*/ | ||
var hmacSha256 = function hmacSha256(accessKey, stringToSign) { | ||
return crypto | ||
.createHmac('sha256', accessKey) | ||
.update(stringToSign) | ||
.digest('base64'); | ||
} | ||
exports.hmacSha256 = hmacSha256; | ||
/* | ||
* Calculate MD5sum for the content | ||
*/ | ||
var md5 = function md5(content) { | ||
return crypto | ||
.createHash('md5') | ||
.update(content, 'utf8') | ||
.digest('base64'); | ||
} | ||
exports.md5 = md5; |
var libxml = require('libxmljs'); | ||
/* Parse queue error, return: {message, code, detail} */ | ||
exports.queueParseError = function queueParseError(res) { | ||
exports.parseError = function parseError(res) { | ||
// Parse payload for error message and code | ||
@@ -28,3 +28,4 @@ var result = { | ||
if (detail) { | ||
result.detail = detail.text(); | ||
// pixl-xml parser strips whitespaces from beginning and end of a node value | ||
result.detail = detail.text().trim(); | ||
} | ||
@@ -128,2 +129,334 @@ } catch (e) { | ||
}); | ||
}; | ||
}; | ||
/* Parse list of containers and return object for listContainers */ | ||
exports.blobParseListContainers = function blobParseListContainers(res) { | ||
// Get results | ||
var xml = libxml.parseXml(res.payload); | ||
var containers = xml.get('/EnumerationResults/Containers').childNodes(); | ||
// Construct results | ||
var result = { | ||
containers: containers.map(function(container) { | ||
var metadata = undefined; | ||
var metaNode = container.get('Metadata'); | ||
if (metaNode) { | ||
metadata = {}; | ||
metaNode.childNodes().forEach(function(node) { | ||
metadata[node.name()] = node.text(); | ||
}); | ||
} | ||
var properties = undefined; | ||
var propsNode = container.get('Properties'); | ||
if (propsNode) { | ||
properties = {}; | ||
properties.eTag = propsNode.get('Etag').text(); | ||
properties.lastModified = propsNode.get('Last-Modified').text(); | ||
properties.leaseStatus = propsNode.get('LeaseStatus').text(); | ||
properties.leaseState = propsNode.get('LeaseState').text(); | ||
if (propsNode.get('LeaseDuration')) { | ||
properties.leaseDuration = propsNode.get('LeaseDuration').text(); | ||
} | ||
if (propsNode.get('PublicAccess')) { | ||
properties.publicAccessLevel = propsNode.get('PublicAccess').text(); | ||
} | ||
} | ||
return { | ||
name: container.get('Name').text(), | ||
properties: properties, | ||
metadata: metadata | ||
}; | ||
}) | ||
}; | ||
// Get Marker, Prefix, MaxResults and NextMarker, if present | ||
var marker = xml.get('/EnumerationResults/Marker'); | ||
if (marker) { | ||
result.marker = marker.text(); | ||
} | ||
var prefix = xml.get('/EnumerationResults/Prefix'); | ||
if (prefix) { | ||
result.prefix = prefix.text(); | ||
} | ||
var maxResults = xml.get('/EnumerationResults/MaxResults'); | ||
if (maxResults) { | ||
result.maxResults = parseInt(maxResults.text()); | ||
} | ||
var nextMarker = xml.get('/EnumerationResults/NextMarker'); | ||
if (nextMarker ) { | ||
result.nextMarker = nextMarker.text(); | ||
} | ||
// Return result | ||
return result; | ||
}; | ||
/* Parse container ACL and return object to getContainerACL */ | ||
exports.blobParseContainerACL = function blobParseContainerACL(response) { | ||
var xml = libxml.parseXml(response.payload); | ||
var signedIdentifiers = xml.get('/SignedIdentifiers').childNodes(); | ||
// Construct results | ||
var result = []; | ||
result = signedIdentifiers.map(function(signedIdentifier) { | ||
var policy = {}; | ||
var id = signedIdentifier.get('Id'); | ||
if (id) { | ||
policy.id = id.text(); | ||
} | ||
var accessPolicy = signedIdentifier.get('AccessPolicy'); | ||
if (accessPolicy) { | ||
var start = accessPolicy.get('Start'); | ||
if (start) { | ||
policy.start = start.text(); | ||
} | ||
var expiry = accessPolicy.get('Expiry'); | ||
if (expiry) { | ||
policy.expiry = expiry.text(); | ||
} | ||
// Default values for permission | ||
policy.permission = { | ||
read: false, | ||
add: false, | ||
create: false, | ||
write: false, | ||
delete: false, | ||
list: false | ||
} | ||
var permission = accessPolicy.get('Permission'); | ||
if (permission) { | ||
permission = permission.text(); | ||
policy.permission.read = permission.indexOf('r') !== -1; | ||
policy.permission.add = permission.indexOf('a') !== -1; | ||
policy.permission.create = permission.indexOf('c') !== -1; | ||
policy.permission.write = permission.indexOf('w') !== -1; | ||
policy.permission.delete = permission.indexOf('d') !== -1; | ||
policy.permission.list = permission.indexOf('l') !== -1; | ||
} | ||
} | ||
return policy; | ||
}); | ||
// return the result | ||
return result; | ||
}; | ||
/* Parse list of blobs and return object for listBlobs */ | ||
exports.blobParseListBlobs = function blobParseListBlobs(response) { | ||
var xml = libxml.parseXml(response.payload); | ||
var result = { | ||
blobs: [] | ||
}; | ||
if (xml.get('Blobs')){ | ||
var blobs = xml.get('Blobs').childNodes(); | ||
result.blobs = blobs.map(function(blob){ | ||
var theBlob = {}; | ||
theBlob.name = blob.get('Name').text(); | ||
var snapshot = blob.get('Snapshot'); | ||
if (snapshot){ | ||
theBlob.snapshot = snapshot.text(); | ||
} | ||
var properties = blob.get('Properties'); | ||
var lastModified = properties.get('Last-Modified'); | ||
if (lastModified){ | ||
theBlob.lastModified = lastModified.text(); | ||
} | ||
var eTag = properties.get('Etag'); | ||
if (eTag){ | ||
theBlob.eTag = eTag.text(); | ||
} | ||
var contentLength = properties.get('Content-Length'); | ||
if (contentLength) { | ||
theBlob.contentLength = contentLength.text(); | ||
} | ||
var contentType = properties.get('Content-Type'); | ||
if (contentType) { | ||
theBlob.contentType = contentType.text(); | ||
} | ||
var contentEncoding = properties.get('Content-Encoding'); | ||
if (contentEncoding) { | ||
theBlob.contentEncoding = contentEncoding.text(); | ||
} | ||
var contentLanguage = properties.get('Content-Language'); | ||
if (contentLanguage) { | ||
theBlob.contentLanguage = contentLanguage.text(); | ||
} | ||
var contentMD5 = properties.get('Content-MD5'); | ||
if (contentMD5) { | ||
theBlob.contentMD5 = contentMD5.text(); | ||
} | ||
var cacheControl = properties.get('Cache-Control'); | ||
if (cacheControl) { | ||
theBlob.cacheControl = cacheControl.text(); | ||
} | ||
var xmsBlobSequenceNumber = properties.get('x-ms-blob-sequence-number'); | ||
if (xmsBlobSequenceNumber) { | ||
theBlob.xmsBlobSequenceNumber = xmsBlobSequenceNumber.text(); | ||
} | ||
theBlob.type = properties.get('BlobType').text(); | ||
var leaseStatus = properties.get('LeaseStatus'); | ||
if (leaseStatus) { | ||
theBlob.leaseStatus = leaseStatus.text(); | ||
} | ||
var leaseState = properties.get('LeaseState'); | ||
if (leaseState) { | ||
theBlob.leaseState = leaseState.text(); | ||
} | ||
var leaseDuration = properties.get('LeaseDuration'); | ||
if (leaseDuration) { | ||
theBlob.leaseDuration = leaseDuration.text(); | ||
} | ||
var copyId = properties.get('CopyId'); | ||
if(copyId) { | ||
theBlob.copyId = copyId.text(); | ||
} | ||
var copyStatus = properties.get('CopyStatus'); | ||
if(copyStatus) { | ||
theBlob.copyStatus = copyStatus.text(); | ||
} | ||
var copySource = properties.get('CopySource'); | ||
if(copySource) { | ||
theBlob.copySource = copySource.text(); | ||
} | ||
var copyProgress = properties.get('CopyProgress'); | ||
if(copyProgress) { | ||
theBlob.copyProgress = copyProgress.text(); | ||
} | ||
var copyCompletionTime = properties.get('CopyCompletionTime'); | ||
if(copyCompletionTime) { | ||
theBlob.copyCompletionTime = copyCompletionTime.text(); | ||
} | ||
var copyStatusDescription = properties.get('CopyStatusDescription'); | ||
if(copyStatusDescription) { | ||
theBlob.copyStatusDescription = copyStatusDescription.text(); | ||
} | ||
theBlob.serverEncrypted = properties.get('ServerEncrypted').text(); | ||
var metadata = undefined; | ||
var metaNode = blob.get('Metadata'); | ||
if (metaNode) { | ||
metadata = {}; | ||
metaNode.childNodes().forEach(function(node) { | ||
metadata[node.name()] = node.text(); | ||
}); | ||
} | ||
if (metadata) { | ||
theBlob.metadata = metadata; | ||
} | ||
return theBlob; | ||
}); | ||
} | ||
// Get Marker, Prefix, MaxResults and NextMarker, if present | ||
var marker = xml.get('/EnumerationResults/Marker'); | ||
if (marker) { | ||
result.marker = marker.text(); | ||
} | ||
var prefix = xml.get('/EnumerationResults/Prefix'); | ||
if (prefix) { | ||
result.prefix = prefix.text(); | ||
} | ||
var maxResults = xml.get('/EnumerationResults/MaxResults'); | ||
if (maxResults) { | ||
result.maxResults = parseInt(maxResults.text()); | ||
} | ||
var nextMarker = xml.get('/EnumerationResults/NextMarker'); | ||
if (nextMarker) { | ||
result.nextMarker = nextMarker.text(); | ||
} | ||
var delimiter = xml.get('/EnumerationResults/Delimiter'); | ||
if (delimiter) { | ||
result.nextMarker = delimiter.text(); | ||
} | ||
return result; | ||
} | ||
/* Parse list of blocks and return object for getBlockList */ | ||
exports.blobParseListBlock = function blobParseListBlock(response) { | ||
var xml = libxml.parseXml(response.payload); | ||
var result = {}; | ||
var blockList = xml.get('/BlockList'); | ||
var getBlockInfo = function(block) { | ||
return { | ||
blockId: block.get('Name').text(), | ||
size: block.get('Size').text() | ||
} | ||
}; | ||
if (blockList.get('CommittedBlocks')) { | ||
var committedBlocksNodes = blockList.get('CommittedBlocks').childNodes(); | ||
result.committedBlocks = committedBlocksNodes.map(getBlockInfo); | ||
} | ||
if (blockList.get('UncommittedBlocks')) { | ||
var uncommittedBlocks = blockList.get('UncommittedBlocks').childNodes(); | ||
result.uncommittedBlocks = uncommittedBlocks.map(getBlockInfo); | ||
} | ||
return result; | ||
} | ||
exports.blobParseServiceProperties = function blobParseServiceProperties(response) { | ||
var xml = libxml.parseXml(response.payload); | ||
var result = {}; | ||
var properties = xml.get('/StorageServiceProperties'); | ||
if (properties.get('Logging')){ | ||
var logging = properties.get('Logging'); | ||
result.logging = {}; | ||
result.logging.version = logging.get('Version').text(); | ||
result.logging.delete = logging.get('Delete').text(); | ||
result.logging.read = logging.get('Read').text(); | ||
result.logging.write = logging.get('Write').text(); | ||
result.logging.retentionPolicy = {}; | ||
result.logging.retentionPolicy.enabled = logging.get('RetentionPolicy/Enabled').text(); | ||
if(logging.get('RetentionPolicy/Days')) result.logging.retentionPolicy.days = logging.get('RetentionPolicy/Days').text(); | ||
} | ||
if (properties.get('HourMetrics')){ | ||
var hourMetrics = properties.get('HourMetrics'); | ||
result.hourMetrics = {}; | ||
result.hourMetrics.version = hourMetrics.get('Version').text(); | ||
result.hourMetrics.enabled = hourMetrics.get('Enabled').text(); | ||
if (hourMetrics.get('IncludeAPIs')) result.hourMetrics.includeAPIs = hourMetrics.get('IncludeAPIs').text(); | ||
result.hourMetrics.retentionPolicy = {}; | ||
result.hourMetrics.retentionPolicy.enabled = hourMetrics.get('RetentionPolicy/Enabled').text(); | ||
if(hourMetrics.get('RetentionPolicy/Days')) result.hourMetrics.retentionPolicy.days = hourMetrics.get('RetentionPolicy/Days').text(); | ||
} | ||
if (properties.get('MinuteMetrics')){ | ||
var minuteMetrics = properties.get('MinuteMetrics'); | ||
result.minuteMetrics = {}; | ||
result.minuteMetrics.version = minuteMetrics.get('Version').text(); | ||
result.minuteMetrics.enabled = minuteMetrics.get('Enabled').text(); | ||
if (minuteMetrics.get('IncludeAPIs')) result.minuteMetrics.includeAPIs = minuteMetrics.get('IncludeAPIs').text(); | ||
result.minuteMetrics.retentionPolicy = {}; | ||
result.minuteMetrics.retentionPolicy.enabled = minuteMetrics.get('RetentionPolicy/Enabled').text(); | ||
if(minuteMetrics.get('RetentionPolicy/Days')) result.minuteMetrics.retentionPolicy.days = minuteMetrics.get('RetentionPolicy/Days').text(); | ||
} | ||
if (properties.get('Cors')){ | ||
result.corsRules = []; | ||
var rules = properties.get('Cors').childNodes(); | ||
result.corsRules = rules.map(function(rule) { | ||
return { | ||
allowedOrigins: rule.get('AllowedOrigins').text(), | ||
allowedMethods: rule.get('AllowedMethods').text(), | ||
maxAgeInSeconds: rule.get('MaxAgeInSeconds').text(), | ||
exposedHeaders: rule.get('ExposedHeaders').text(), | ||
allowedHeaders: rule.get('AllowedHeaders').text() | ||
}; | ||
}); | ||
} | ||
return result; | ||
} |
var XML = require('pixl-xml'); | ||
/* Parse queue error, return: {message, code, detail} */ | ||
exports.queueParseError = function queueParseError(res) { | ||
exports.parseError = function parseError(res) { | ||
// Parse payload for error message and code | ||
@@ -13,2 +13,3 @@ var result = { | ||
var xml = XML.parse(res.payload); | ||
result.message = xml.Message; | ||
@@ -116,1 +117,326 @@ result.code = xml.Code; | ||
}; | ||
/* Parse list of containers and return object for listContainers */ | ||
exports.blobParseListContainers = function blobParseListContainers(res) { | ||
// Get results | ||
var xml = XML.parse(res.payload); | ||
var containers = (xml.Containers || {}).Container || []; | ||
if(!(containers instanceof Array)) { | ||
containers = [containers]; | ||
} | ||
// Construct results | ||
var result = { | ||
containers: containers.map(function(container) { | ||
var metadata = undefined; | ||
if (container.hasOwnProperty('Metadata')) { | ||
metadata = container.Metadata || {}; | ||
} | ||
var properties = undefined; | ||
if (container.hasOwnProperty('Properties')) { | ||
properties = {}; | ||
properties.eTag = container.Properties.Etag; | ||
properties.lastModified = container.Properties['Last-Modified']; | ||
properties.leaseStatus = container.Properties.LeaseStatus; | ||
properties.leaseState = container.Properties.LeaseState; | ||
if (container.Properties.hasOwnProperty('LeaseDuration')) { | ||
properties.leaseDuration = container.Properties.LeaseDuration; | ||
} | ||
if (container.Properties.hasOwnProperty('PublicAccess')) { | ||
properties.publicAccessLevel = container.Properties.PublicAccess; | ||
} | ||
} | ||
return { | ||
name: container.Name, | ||
properties: properties, | ||
metadata: metadata | ||
}; | ||
}) | ||
}; | ||
// Get Marker, Prefix, MaxResults and NextMarker, if present | ||
if (xml.hasOwnProperty('Marker')) { | ||
result.marker = xml.Marker; | ||
} | ||
if (xml.hasOwnProperty('Prefix')) { | ||
result.prefix = xml.Prefix; | ||
} | ||
if (xml.hasOwnProperty('MaxResults')) { | ||
result.maxResults = parseInt(xml.MaxResults); | ||
} | ||
if (xml.hasOwnProperty('NextMarker')) { | ||
result.nextMarker = xml.NextMarker; | ||
} | ||
// Return result | ||
return result; | ||
}; | ||
/* Parse container ACL and return object to getContainerACL */ | ||
exports.blobParseContainerACL = function blobParseContainerACL(response) { | ||
var xml = XML.parse(response.payload); | ||
var signedIdentifiers = xml.SignedIdentifier || []; | ||
if(!(signedIdentifiers instanceof Array)) { | ||
signedIdentifiers = [signedIdentifiers]; | ||
} | ||
var result = []; | ||
// Construct results | ||
result = signedIdentifiers.map(function(signedIdentifier) { | ||
var policy = {}; | ||
policy.id = signedIdentifier.Id; | ||
if (signedIdentifier.hasOwnProperty('AccessPolicy')){ | ||
var accessPolicy = signedIdentifier.AccessPolicy; | ||
if (accessPolicy.hasOwnProperty('Start')) { | ||
policy.start = accessPolicy.Start; | ||
} | ||
if (accessPolicy.hasOwnProperty('Expiry')) { | ||
policy.expiry = accessPolicy.Expiry; | ||
} | ||
// Default values for permission | ||
policy.permission = { | ||
read: false, | ||
add: false, | ||
create: false, | ||
write: false, | ||
delete: false, | ||
list: false | ||
} | ||
if (accessPolicy.hasOwnProperty('Permission')) { | ||
var permission = accessPolicy.Permission; | ||
policy.permission.read = permission.indexOf('r') !== -1; | ||
policy.permission.add = permission.indexOf('a') !== -1; | ||
policy.permission.create = permission.indexOf('c') !== -1; | ||
policy.permission.write = permission.indexOf('w') !== -1; | ||
policy.permission.delete = permission.indexOf('d') !== -1; | ||
policy.permission.list = permission.indexOf('l') !== -1; | ||
} | ||
} | ||
return policy; | ||
}); | ||
return result; | ||
}; | ||
/* Parse list of blobs and return object for listBlobs */ | ||
exports.blobParseListBlobs = function blobParseListBlobs(response) { | ||
var xml = XML.parse(response.payload); | ||
var blobs = (xml.Blobs || {}).Blob || []; | ||
if(!(blobs instanceof Array)) { | ||
blobs = [blobs]; | ||
} | ||
var result = {}; | ||
result.blobs = blobs.map(function(blob) { | ||
var theBlob = {}; | ||
theBlob.name = blob.Name; | ||
if (blob.hasOwnProperty('Snapshot')) { | ||
theBlob.snapshot = blob.Snapshot; | ||
} | ||
var properties = blob.Properties; | ||
if (properties.hasOwnProperty('Last-Modified')){ | ||
theBlob.lastModified = properties['Last-Modified']; | ||
} | ||
if (properties.hasOwnProperty('Etag')){ | ||
theBlob.eTag = properties.Etag; | ||
} | ||
if (properties.hasOwnProperty('Content-Length')){ | ||
theBlob.contentLength = properties['Content-Length']; | ||
} | ||
if (properties.hasOwnProperty('Content-Type')){ | ||
theBlob.contentType = properties['Content-Type']; | ||
} | ||
if (properties.hasOwnProperty('Content-Encoding')){ | ||
theBlob.contentEncoding = properties['Content-Encoding']; | ||
} | ||
if (properties.hasOwnProperty('Content-Language')){ | ||
theBlob.contentLanguage = properties['Content-Language']; | ||
} | ||
if (properties.hasOwnProperty('Content-MD5')){ | ||
theBlob.contentMD5 = properties['Content-MD5']; | ||
} | ||
if (properties.hasOwnProperty('Cache-Control')){ | ||
theBlob.cacheControl = properties['Cache-Control']; | ||
} | ||
if (properties.hasOwnProperty('x-ms-blob-sequence-number')){ | ||
theBlob.xmsBlobSequenceNumber = properties['x-ms-blob-sequence-number']; | ||
} | ||
theBlob.type = properties.BlobType; | ||
if (properties.hasOwnProperty('LeaseStatus')){ | ||
theBlob.leaseStatus = properties.LeaseStatus; | ||
} | ||
if (properties.hasOwnProperty('LeaseState')){ | ||
theBlob.leaseState = properties.LeaseState; | ||
} | ||
if (properties.hasOwnProperty('LeaseDuration')){ | ||
theBlob.leaseDuration = properties.LeaseDuration; | ||
} | ||
if (properties.hasOwnProperty('CopyId')){ | ||
theBlob.copyId = properties.CopyId; | ||
} | ||
if (properties.hasOwnProperty('CopyStatus')){ | ||
theBlob.copyStatus = properties.CopyStatus; | ||
} | ||
if (properties.hasOwnProperty('CopySource')){ | ||
theBlob.copySource = properties.CopySource; | ||
} | ||
if (properties.hasOwnProperty('CopyProgress')){ | ||
theBlob.copyProgress = properties.CopyProgress; | ||
} | ||
if (properties.hasOwnProperty('CopyCompletionTime')){ | ||
theBlob.copyCompletionTime = properties.CopyCompletionTime; | ||
} | ||
if (properties.hasOwnProperty('CopyStatusDescription')){ | ||
theBlob.copyStatusDescription = properties.CopyStatusDescription; | ||
} | ||
theBlob.serverEncrypted = properties.ServerEncrypted; | ||
var metadata = undefined; | ||
if (blob.hasOwnProperty('Metadata')) { | ||
metadata = blob.Metadata || {}; | ||
} | ||
if (metadata) { | ||
theBlob.metadata = metadata; | ||
} | ||
return theBlob; | ||
}); | ||
// Get Marker, Prefix, MaxResults and NextMarker, if present | ||
if (xml.hasOwnProperty('Marker')) { | ||
result.marker = xml.Marker; | ||
} | ||
if (xml.hasOwnProperty('Prefix')) { | ||
result.prefix = xml.Prefix; | ||
} | ||
if (xml.hasOwnProperty('MaxResults')) { | ||
result.maxResults = parseInt(xml.MaxResults); | ||
} | ||
if (xml.hasOwnProperty('NextMarker')) { | ||
result.nextMarker = xml.NextMarker; | ||
} | ||
if (xml.hasOwnProperty('Delimiter')) { | ||
result.delimiter = xml.Delimiter; | ||
} | ||
// Return result | ||
return result; | ||
}; | ||
/* Parse list of blocks and return object for getBlockList */ | ||
exports.blobParseListBlock = function blobParseListBlock(response) { | ||
var xml = XML.parse(response.payload); | ||
var result = {}; | ||
var getBlockInfo = function(block){ | ||
return { | ||
blockId: block.Name, | ||
size: block.Size | ||
} | ||
}; | ||
if (xml.hasOwnProperty('CommittedBlocks')) { | ||
var blocks = (xml.CommittedBlocks || {}).Block || []; | ||
if(!(blocks instanceof Array)) { | ||
blocks = [blocks]; | ||
} | ||
result.committedBlocks = blocks.map(getBlockInfo); | ||
} | ||
if (xml.hasOwnProperty('UncommittedBlocks')) { | ||
var blocks = (xml.UncommittedBlocks || {}).Block || []; | ||
if(!(blocks instanceof Array)) { | ||
blocks = [blocks]; | ||
} | ||
result.uncommittedBlocks = blocks.map(getBlockInfo); | ||
} | ||
return result; | ||
}; | ||
/* Parse the blob service properties and return object for getServiceProperties */ | ||
exports.blobParseServiceProperties = function blobParseServiceProperties(response) { | ||
var xml = XML.parse(response.payload); | ||
var result = {}; | ||
if (xml.hasOwnProperty('Logging')) { | ||
result.logging = { | ||
version: xml.Logging.Version, | ||
delete: xml.Logging.Delete, | ||
read: xml.Logging.Read, | ||
write: xml.Logging.Write, | ||
retentionPolicy: { | ||
enabled: xml.Logging.RetentionPolicy.Enabled | ||
} | ||
}; | ||
if (xml.Logging.RetentionPolicy.hasOwnProperty('Days')){ | ||
result.logging.retentionPolicy.days = xml.Logging.RetentionPolicy.Days; | ||
} | ||
} | ||
if (xml.hasOwnProperty('HourMetrics')) { | ||
result.hourMetrics = { | ||
version: xml.HourMetrics.Version, | ||
enabled: xml.HourMetrics.Enabled | ||
}; | ||
if (xml.HourMetrics.hasOwnProperty('IncludeAPIs')) { | ||
result.hourMetrics.includeAPIs = xml.HourMetrics.IncludeAPIs; | ||
} | ||
result.hourMetrics.retentionPolicy = { | ||
enabled: xml.HourMetrics.RetentionPolicy.Enabled | ||
}; | ||
if (xml.HourMetrics.RetentionPolicy.hasOwnProperty('Days')){ | ||
result.hourMetrics.retentionPolicy.days = xml.HourMetrics.RetentionPolicy.Days; | ||
} | ||
} | ||
if (xml.hasOwnProperty('MinuteMetrics')) { | ||
result.minuteMetrics = { | ||
version: xml.MinuteMetrics.Version, | ||
enabled: xml.MinuteMetrics.Enabled | ||
}; | ||
if (xml.MinuteMetrics.hasOwnProperty('IncludeAPIs')) { | ||
result.minuteMetrics.includeAPIs = xml.MinuteMetrics.IncludeAPIs; | ||
} | ||
result.minuteMetrics.retentionPolicy = { | ||
enabled: xml.MinuteMetrics.RetentionPolicy.Enabled | ||
}; | ||
if (xml.MinuteMetrics.RetentionPolicy.hasOwnProperty('Days')){ | ||
result.minuteMetrics.retentionPolicy.days = xml.MinuteMetrics.RetentionPolicy.Days; | ||
} | ||
} | ||
if (xml.hasOwnProperty('Cors')) { | ||
var rules = (xml.Cors || {}).CorsRule || []; | ||
if(!(rules instanceof Array)) { | ||
rules = [rules]; | ||
} | ||
result.corsRules = rules.map(function(rule) { | ||
return { | ||
allowedOrigins: rule.AllowedOrigins, | ||
allowedMethods: rule.AllowedMethods, | ||
maxAgeInSeconds: rule.MaxAgeInSeconds, | ||
exposedHeaders: rule.ExposedHeaders, | ||
allowedHeaders: rule.AllowedHeaders | ||
}; | ||
}); | ||
} | ||
return result; | ||
}; |
{ | ||
"name": "fast-azure-storage", | ||
"version": "0.3.7", | ||
"author": "Jonas Finnemann Jensen <jopsen@gmail.com>", | ||
"version": "1.0.0", | ||
"author": "Jonas Finnemann Jensen <jopsen@gmail.com>, Elena Solomon <elenasolomon28@gmail.com>", | ||
"description": "Fast client library for azure storage services", | ||
@@ -17,2 +17,5 @@ "license": "MPL-2.0", | ||
}, | ||
"engines": { | ||
"node": ">=4" | ||
}, | ||
"dependencies": { | ||
@@ -19,0 +22,0 @@ "debug": "^2.2.0", |
@@ -10,3 +10,3 @@ Fast Azure Storage Client for Node.js | ||
At this point this library implement most of the APIs for queue and table | ||
At this point this library implement most of the APIs for queue, table and blob | ||
storage. Pull request with additional feature additions will generally be | ||
@@ -22,3 +22,3 @@ accepted, as long as patches don't compromise efficiency. | ||
--------------------- | ||
Both `Queue` and `Table` takes a range of common configuration options. | ||
All three clients, `Queue`, `Table` and `Blob`, take a range of common configuration options. | ||
@@ -38,5 +38,6 @@ ### Authentication Options | ||
// Create queue and table clients | ||
// Create queue, table and blob clients | ||
var queue = new azure.Queue(options); | ||
var table = new azure.Table(options); | ||
var blob = new azure.Blob(options); | ||
``` | ||
@@ -71,3 +72,3 @@ | ||
optimized for Azure Storage service to reduce latency and avoid errors. | ||
By default both `Table` and `Queue` clients will use a global instance of this | ||
By default,`Blob`,`Table` and `Queue` clients will use a global instance of this | ||
custom agent configured to allow 100 connections per host. | ||
@@ -182,1 +183,59 @@ | ||
Azure Blob Storage Client | ||
-------------------------- | ||
The Azure Blob Storage client aims at interfacing Azure Blob Storage. | ||
Using this client, text and binary data can be stored in one of the following types | ||
of blob: | ||
* Block blobs, which are optimized for upload large blobs | ||
* Append blobs, which are optimized for append operations, making it ideal for | ||
eg. logging, auditing | ||
Simple example of a container and blob creation. | ||
```js | ||
// Load fast-azure-storage client | ||
var azure = require('fast-azure-storage'); | ||
var blob = new azure.Blob({ | ||
accountId: '...', | ||
accessKey: '...' | ||
}); | ||
var blobContent = 'Sample content'; // The content can be a string or a Buffer | ||
// Create container and upload a blob | ||
blob.createContainer('mycontainer').then(function() { | ||
return blob.putBlob('mycontainer', 'myblob', { | ||
type: 'BlockBlob', // Type of the blob | ||
}, blobContent); | ||
}); | ||
``` | ||
### Blob API Reference | ||
See also [reference documentation](https://taskcluster.github.io/fast-azure-storage/). | ||
* `Blob(options)` | ||
* `Blob#setServiceProperties(options)` | ||
* `Blob#getServiceProperties()` | ||
* `Blob#createContainer(name, options)` | ||
* `Blob#setContainerMetadata(name, metadata, options)` | ||
* `Blob#getContainerMetadata(name, options)` | ||
* `Blob#deleteContainer(name, options)` | ||
* `Blob#listContainers(options)` | ||
* `Blob#getContainerProperties(name, options)` | ||
* `Blob#getContainerACL(name, options)` | ||
* `Blob#setContainerACL(name, options)` | ||
* `Blob#listBlobs(container, options)` | ||
* `Blob#leaseContainer(name, options)` | ||
* `Blob#putBlob(container, blob, options, content)` | ||
* `Blob#getBlob(container, blob, options)` | ||
* `Blob#getBlobProperties(container, blob, options)` | ||
* `Blob#setBlobProperties(container, blob, options)` | ||
* `Blob#getBlobMetadata(container, blob, options)` | ||
* `Blob#setBlobMetadata(container, blob, metadata, options)` | ||
* `Blob#deleteBlob(container, blob, options)` | ||
* `Blob#putBlock(container, blob, options, content)` | ||
* `Blob#putBlockList(container, blob, options)` | ||
* `Blob#getBlockList(container, blob, options)` | ||
* `Blob#getBlockId(prefix, blockNumber, length)` | ||
* `Blob#appendBlock(container, blob, options, content)` | ||
* `Blob#sas(container, blob, options)` |
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
New author
Supply chain riskA new npm collaborator published a version of the package for the first time. New collaborators are usually benign additions to a project, but do indicate a change to the security surface area of a package.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
246228
16
5217
1
236
3