diff --git a/CHANGELOG.md b/CHANGELOG.md index 0a03b6c..14d2c11 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -7,6 +7,53 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 Generated by [`auto-changelog`](https://github.com/CookPete/auto-changelog). +## [v1.0.9](https://github.com/tencentyun/cos-wx-sdk-v5/compare/v1.0.8...v1.0.9) - 2021-06-11 + +- 新增高级上传接口 + +### Merged + +- feat:新增高级上传uploadFile接口 [`#48`](https://github.com/tencentyun/cos-wx-sdk-v5/pull/48) + +### Commits + +- Updated CHANGELOG.md [`9263e5f`](https://github.com/tencentyun/cos-wx-sdk-v5/commit/9263e5f29e6ad4e493c32cdfe011f8a55126818b) +- update uploadFile [`f7f8949`](https://github.com/tencentyun/cos-wx-sdk-v5/commit/f7f89495694eb07f4d19f0759320ac2962e58abe) + +## [v1.0.8](https://github.com/tencentyun/cos-wx-sdk-v5/compare/1.0.7...v1.0.8) - 2021-06-04 + +-sliceUploadFile方法新增返回值UploadId + +### Commits + +- update version 1.0.8 [`c89ac9e`](https://github.com/tencentyun/cos-wx-sdk-v5/commit/c89ac9ef3af9c52a87f3bca6ef15081a43c0d741) +- Updated CHANGELOG.md [`c359130`](https://github.com/tencentyun/cos-wx-sdk-v5/commit/c359130a54555bb8cffaf1e837bfb29e72798509) +- update version 1.0.8 [`3a3af79`](https://github.com/tencentyun/cos-wx-sdk-v5/commit/3a3af79437434eee549a8f2f745a53cff4e696d7) +- feat/uploadId [`023261a`](https://github.com/tencentyun/cos-wx-sdk-v5/commit/023261aedaa00c10b682c032d6b7bad830cf6641) + +## [1.0.7](https://github.com/tencentyun/cos-wx-sdk-v5/compare/v1.0.6...1.0.7) - 2021-05-08 + +支持全球加速及图片处理 + +### Merged + +- Feat/accelerate and ci [`#44`](https://github.com/tencentyun/cos-wx-sdk-v5/pull/44) + +### Commits + +- support UseAccelerate [`a32b890`](https://github.com/tencentyun/cos-wx-sdk-v5/commit/a32b890007fbcec767e48c50b440e89a1827ed9e) +- feat: 支持全球加速及图片处理 [`81e70a0`](https://github.com/tencentyun/cos-wx-sdk-v5/commit/81e70a098f62818de9ac4bae1a1da2680c3b8f78) +- fix: sts 服务取环境内的配置 [`e586635`](https://github.com/tencentyun/cos-wx-sdk-v5/commit/e586635fdf2857136d41988137faa8e7ae3592d1) +- fix: 优化 sts 服务 [`1cf2582`](https://github.com/tencentyun/cos-wx-sdk-v5/commit/1cf2582834fc3f2495bcf1341fb38c5902b681a9) + +## [v1.0.6](https://github.com/tencentyun/cos-wx-sdk-v5/compare/v1.0.5...v1.0.6) - 2021-01-13 + +### Commits + +- postObject Location support key=${filename} [`b1cb886`](https://github.com/tencentyun/cos-wx-sdk-v5/commit/b1cb88694e885950ab3ea1bb97d3d64c54a2abb9) +- Updated CHANGELOG.md [`6673a43`](https://github.com/tencentyun/cos-wx-sdk-v5/commit/6673a4316b9f7ba86524c986021f497430ef65fe) +- postObject Location support key=${filename} [`e3681df`](https://github.com/tencentyun/cos-wx-sdk-v5/commit/e3681df6ff552e033ede7026eb4608a8a5d69412) + ## [v1.0.5](https://github.com/tencentyun/cos-wx-sdk-v5/compare/v1.0.4...v1.0.5) - 2020-12-18 const 改为 var diff --git a/demo-album/lib/cos-wx-sdk-v5.js b/demo-album/lib/cos-wx-sdk-v5.js index 0de1a00..c7ba392 100644 --- a/demo-album/lib/cos-wx-sdk-v5.js +++ b/demo-album/lib/cos-wx-sdk-v5.js @@ -67,7 +67,7 @@ return /******/ (function(modules) { // webpackBootstrap /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ -/******/ __webpack_require__.p = "D:\\code\\cos-wx-sdk-v5\\demo\\lib"; +/******/ __webpack_require__.p = "/Users/tianfeng/Documents/项目/sdk/cos-wx-sdk-v5/demo/lib"; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 6); @@ -78,590 +78,590 @@ return /******/ (function(modules) { // webpackBootstrap /***/ (function(module, exports, __webpack_require__) { "use strict"; -/* WEBPACK VAR INJECTION */(function(global) { - -var md5 = __webpack_require__(8); -var CryptoJS = __webpack_require__(11); -var xml2json = __webpack_require__(12); -var json2xml = __webpack_require__(15); -var base64 = __webpack_require__(3); -var btoa = base64.btoa; -var wxfs = wx.getFileSystemManager(); - -function camSafeUrlEncode(str) { - return encodeURIComponent(str) - .replace(/!/g, '%21') - .replace(/'/g, '%27') - .replace(/\(/g, '%28') - .replace(/\)/g, '%29') - .replace(/\*/g, '%2A'); -} - -//测试用的key后面可以去掉 -var getAuth = function (opt) { - opt = opt || {}; - - var SecretId = opt.SecretId; - var SecretKey = opt.SecretKey; - var KeyTime = opt.KeyTime; - var method = (opt.method || opt.Method || 'get').toLowerCase(); - var queryParams = clone(opt.Query || opt.params || {}); - var headers = clone(opt.Headers || opt.headers || {}); - - var Key = opt.Key || ''; - var pathname; - if (opt.UseRawKey) { - pathname = opt.Pathname || opt.pathname || '/' + Key; - } else { - pathname = opt.Pathname || opt.pathname || Key; - pathname.indexOf('/') !== 0 && (pathname = '/' + pathname); - } - - if (!SecretId) return console.error('missing param SecretId'); - if (!SecretKey) return console.error('missing param SecretKey'); - - var getObjectKeys = function (obj, forKey) { - var list = []; - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - list.push(forKey ? camSafeUrlEncode(key).toLowerCase() : key); - } - } - return list.sort(function (a, b) { - a = a.toLowerCase(); - b = b.toLowerCase(); - return a === b ? 0 : (a > b ? 1 : -1); - }); - }; - - var obj2str = function (obj) { - var i, key, val; - var list = []; - var keyList = getObjectKeys(obj); - for (i = 0; i < keyList.length; i++) { - key = keyList[i]; - val = (obj[key] === undefined || obj[key] === null) ? '' : ('' + obj[key]); - key = camSafeUrlEncode(key).toLowerCase(); - val = camSafeUrlEncode(val) || ''; - list.push(key + '=' + val) - } - return list.join('&'); - }; - - // 签名有效起止时间 - var now = Math.round(getSkewTime(opt.SystemClockOffset) / 1000) - 1; - var exp = now; - - var Expires = opt.Expires || opt.expires; - if (Expires === undefined) { - exp += 900; // 签名过期时间为当前 + 900s - } else { - exp += (Expires * 1) || 0; - } - - // 要用到的 Authorization 参数列表 - var qSignAlgorithm = 'sha1'; - var qAk = SecretId; - var qSignTime = KeyTime || now + ';' + exp; - var qKeyTime = KeyTime || now + ';' + exp; - var qHeaderList = getObjectKeys(headers, true).join(';').toLowerCase(); - var qUrlParamList = getObjectKeys(queryParams, true).join(';').toLowerCase(); - - // 签名算法说明文档:https://www.qcloud.com/document/product/436/7778 - // 步骤一:计算 SignKey - var signKey = CryptoJS.HmacSHA1(qKeyTime, SecretKey).toString(); - - // 步骤二:构成 FormatString - var formatString = [method, pathname, obj2str(queryParams), obj2str(headers), ''].join('\n'); - - // 步骤三:计算 StringToSign - var stringToSign = ['sha1', qSignTime, CryptoJS.SHA1(formatString).toString(), ''].join('\n'); - - // 步骤四:计算 Signature - var qSignature = CryptoJS.HmacSHA1(stringToSign, signKey).toString(); - - // 步骤五:构造 Authorization - var authorization = [ - 'q-sign-algorithm=' + qSignAlgorithm, - 'q-ak=' + qAk, - 'q-sign-time=' + qSignTime, - 'q-key-time=' + qKeyTime, - 'q-header-list=' + qHeaderList, - 'q-url-param-list=' + qUrlParamList, - 'q-signature=' + qSignature - ].join('&'); - - return authorization; - -}; - -var noop = function () { - -}; - -// 清除对象里值为的 undefined 或 null 的属性 -var clearKey = function (obj) { - var retObj = {}; - for (var key in obj) { - if (obj.hasOwnProperty(key) && obj[key] !== undefined && obj[key] !== null) { - retObj[key] = obj[key]; - } - } - return retObj; -}; - -// 获取文件分片 -var fileSlice = function (FilePath, start, end, callback) { - if (FilePath) { - wxfs.readFile({ - filePath: FilePath, - position: start, - length: end - start, - success: function (res) { - callback(res.data); - }, - fail: function () { - callback(null); - }, - }); - } else { - callback(null); - } -}; - -// 获取文件内容的 MD5 -var getBodyMd5 = function (UploadCheckContentMd5, Body, callback) { - callback = callback || noop; - if (UploadCheckContentMd5) { - if (Body && Body instanceof ArrayBuffer) { - util.getFileMd5(Body, function (err, md5) { - callback(md5); - }); - } else { - callback(); - } - } else { - callback(); - } -}; - -// 获取文件 md5 值 -var getFileMd5 = function (body, callback) { - var hash = md5(body); - callback && callback(hash); - return hash; -}; - -function clone(obj) { - return map(obj, function (v) { - return typeof v === 'object' ? clone(v) : v; - }); -} - -function attr(obj, name, defaultValue) { - return obj && name in obj ? obj[name] : defaultValue; -} - -function extend(target, source) { - each(source, function (val, key) { - target[key] = source[key]; - }); - return target; -} - -function isArray(arr) { - return arr instanceof Array; -} - -function isInArray(arr, item) { - var flag = false; - for (var i = 0; i < arr.length; i++) { - if (item === arr[i]) { - flag = true; - break; - } - } - return flag; -} - -function makeArray(arr) { - return isArray(arr) ? arr : [arr]; -} - -function each(obj, fn) { - for (var i in obj) { - if (obj.hasOwnProperty(i)) { - fn(obj[i], i); - } - } -} - -function map(obj, fn) { - var o = isArray(obj) ? [] : {}; - for (var i in obj) { - if (obj.hasOwnProperty(i)) { - o[i] = fn(obj[i], i); - } - } - return o; -} - -function filter(obj, fn) { - var iaArr = isArray(obj); - var o = iaArr ? [] : {}; - for (var i in obj) { - if (obj.hasOwnProperty(i)) { - if (fn(obj[i], i)) { - if (iaArr) { - o.push(obj[i]); - } else { - o[i] = obj[i]; - } - } - } - } - return o; -} - -var binaryBase64 = function (str) { - var i, len, char, res = ''; - for (i = 0, len = str.length / 2; i < len; i++) { - char = parseInt(str[i * 2] + str[i * 2 + 1], 16); - res += String.fromCharCode(char); - } - return btoa(res); -}; -var uuid = function () { - var S4 = function () { - return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); - }; - return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4()); -}; - -var hasMissingParams = function (apiName, params) { - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - if (apiName.indexOf('Bucket') > -1 || apiName === 'deleteMultipleObject' || apiName === 'multipartList' || apiName === 'listObjectVersions') { - if (!Bucket) return 'Bucket'; - if (!Region) return 'Region'; - } else if (apiName.indexOf('Object') > -1 || apiName.indexOf('multipart') > -1 || apiName === 'sliceUploadFile' || apiName === 'abortUploadTask') { - if (!Bucket) return 'Bucket'; - if (!Region) return 'Region'; - if (!Key) return 'Key'; - } - return false; -}; - -var formatParams = function (apiName, params) { - - // 复制参数对象 - params = extend({}, params); - - // 统一处理 Headers - if (apiName !== 'getAuth' && apiName !== 'getV4Auth' && apiName !== 'getObjectUrl') { - var Headers = params.Headers || {}; - if (params && typeof params === 'object') { - (function () { - for (var key in params) { - if (params.hasOwnProperty(key) && key.indexOf('x-cos-') > -1) { - Headers[key] = params[key]; - } - } - })(); - - var headerMap = { - // params headers - 'x-cos-mfa': 'MFA', - 'Content-MD5': 'ContentMD5', - 'Content-Length': 'ContentLength', - 'Content-Type': 'ContentType', - 'Expect': 'Expect', - 'Expires': 'Expires', - 'Cache-Control': 'CacheControl', - 'Content-Disposition': 'ContentDisposition', - 'Content-Encoding': 'ContentEncoding', - 'Range': 'Range', - 'If-Modified-Since': 'IfModifiedSince', - 'If-Unmodified-Since': 'IfUnmodifiedSince', - 'If-Match': 'IfMatch', - 'If-None-Match': 'IfNoneMatch', - 'x-cos-copy-source': 'CopySource', - 'x-cos-copy-source-Range': 'CopySourceRange', - 'x-cos-metadata-directive': 'MetadataDirective', - 'x-cos-copy-source-If-Modified-Since': 'CopySourceIfModifiedSince', - 'x-cos-copy-source-If-Unmodified-Since': 'CopySourceIfUnmodifiedSince', - 'x-cos-copy-source-If-Match': 'CopySourceIfMatch', - 'x-cos-copy-source-If-None-Match': 'CopySourceIfNoneMatch', - 'x-cos-acl': 'ACL', - 'x-cos-grant-read': 'GrantRead', - 'x-cos-grant-write': 'GrantWrite', - 'x-cos-grant-full-control': 'GrantFullControl', - 'x-cos-grant-read-acp': 'GrantReadAcp', - 'x-cos-grant-write-acp': 'GrantWriteAcp', - 'x-cos-storage-class': 'StorageClass', - // SSE-C - 'x-cos-server-side-encryption-customer-algorithm': 'SSECustomerAlgorithm', - 'x-cos-server-side-encryption-customer-key': 'SSECustomerKey', - 'x-cos-server-side-encryption-customer-key-MD5': 'SSECustomerKeyMD5', - // SSE-COS、SSE-KMS - 'x-cos-server-side-encryption': 'ServerSideEncryption', - 'x-cos-server-side-encryption-cos-kms-key-id': 'SSEKMSKeyId', - 'x-cos-server-side-encryption-context': 'SSEContext', - }; - util.each(headerMap, function (paramKey, headerKey) { - if (params[paramKey] !== undefined) { - Headers[headerKey] = params[paramKey]; - } - }); - - params.Headers = clearKey(Headers); - } - } - - return params; -}; - -var apiWrapper = function (apiName, apiFn) { - return function (params, callback) { - - var self = this; - - // 处理参数 - if (typeof params === 'function') { - callback = params; - params = {}; - } - - // 整理参数格式 - params = formatParams(apiName, params); - - // 代理回调函数 - var formatResult = function (result) { - if (result && result.headers) { - result.headers['x-cos-version-id'] && (result.VersionId = result.headers['x-cos-version-id']); - result.headers['x-cos-delete-marker'] && (result.DeleteMarker = result.headers['x-cos-delete-marker']); - } - return result; - }; - var _callback = function (err, data) { - callback && callback(formatResult(err), formatResult(data)); - }; - - var checkParams = function () { - if (apiName !== 'getService' && apiName !== 'abortUploadTask') { - // 判断参数是否完整 - var missingResult = hasMissingParams(apiName, params) - if (missingResult) { - return 'missing param ' + missingResult; - } - // 判断 region 格式 - if (params.Region) { - if (params.Region.indexOf('cos.') > -1) { - return 'param Region should not be start with "cos."'; - } else if (!/^([a-z\d-]+)$/.test(params.Region)) { - return 'Region format error.'; - } - // 判断 region 格式 - if (!self.options.CompatibilityMode - && params.Region.indexOf('-') === -1 - && params.Region !== 'yfb' - && params.Region !== 'default' - && params.Region !== 'accelerate') { - console.warn('warning: param Region format error, find help here: https://cloud.tencent.com/document/product/436/6224'); - } - } - // 兼容不带 AppId 的 Bucket - if (params.Bucket) { - if (!/^([a-z\d-]+)-(\d+)$/.test(params.Bucket)) { - if (params.AppId) { - params.Bucket = params.Bucket + '-' + params.AppId; - } else if (self.options.AppId) { - params.Bucket = params.Bucket + '-' + self.options.AppId; - } else { - return 'Bucket should format as "test-1250000000".'; - } - } - if (params.AppId) { - console.warn('warning: AppId has been deprecated, Please put it at the end of parameter Bucket(E.g Bucket:"test-1250000000" ).'); - delete params.AppId; - } - } - // 如果 Key 是 / 开头,强制去掉第一个 / - if (params.Key && params.Key.substr(0, 1) === '/') { - params.Key = params.Key.substr(1); - } - } - }; - - var errMsg = checkParams(); - var isSync = apiName === 'getAuth' || apiName === 'getObjectUrl'; - var Promise = global.Promise; - if (!isSync && Promise && !callback) { - return new Promise(function (resolve, reject) { - callback = function (err, data) { - err ? reject(err) : resolve(data); - }; - if (errMsg) return _callback({error: errMsg}); - apiFn.call(self, params, _callback); - }); - } else { - if (errMsg) return _callback({error: errMsg}); - var res = apiFn.call(self, params, _callback); - if (isSync) return res; - } - } -}; - -var throttleOnProgress = function (total, onProgress) { - var self = this; - var size0 = 0; - var size1 = 0; - var time0 = Date.now(); - var time1; - var timer; - - function update() { - timer = 0; - if (onProgress && (typeof onProgress === 'function')) { - time1 = Date.now(); - var speed = Math.max(0, Math.round((size1 - size0) / ((time1 - time0) / 1000) * 100) / 100) || 0; - var percent; - if (size1 === 0 && total === 0) { - percent = 1; - } else { - percent = Math.floor(size1 / total * 100) / 100 || 0; - } - time0 = time1; - size0 = size1; - try { - onProgress({loaded: size1, total: total, speed: speed, percent: percent}); - } catch (e) { - } - } - } - - return function (info, immediately) { - if (info) { - size1 = info.loaded; - total = info.total; - } - if (immediately) { - clearTimeout(timer); - update(); - } else { - if (timer) return; - timer = setTimeout(update, self.options.ProgressInterval); - } - }; -}; - -var getFileSize = function (api, params, callback) { - if (api === 'postObject') { - callback(); - } else if (api === 'putObject') { - if (params.Body !== undefined) { - params.ContentLength = params.Body.byteLength; - callback(null, params.ContentLength); - } else { - callback({error: 'missing param Body'}); - } - } else { - if (params.FilePath) { - wxfs.stat({ - path: params.FilePath, - success: function (res) { - var stats = res.stats; - params.FileStat = stats; - params.FileStat.FilePath = params.FilePath; - var size = stats.isDirectory() ? 0 : stats.size; - params.ContentLength = size = size || 0; - callback(null, size); - }, - fail: function (err) { - callback(err); - }, - }); - } else { - callback({error: 'missing param FilePath'}); - } - } -}; - -var getSkewTime = function (offset) { - return Date.now() + (offset || 0); -}; - -var compareVersion = function (v1, v2) { - v1 = v1.split('.') - v2 = v2.split('.') - var len = Math.max(v1.length, v2.length) - - while (v1.length < len) { - v1.push('0') - } - while (v2.length < len) { - v2.push('0') - } - - for (var i = 0; i < len; i++) { - var num1 = parseInt(v1[i]) - var num2 = parseInt(v2[i]) - - if (num1 > num2) { - return 1 - } else if (num1 < num2) { - return -1 - } - } - - return 0 -}; - -var canFileSlice = (function () { - var systemInfo = wx.getSystemInfoSync(); - var support = compareVersion(systemInfo.SDKVersion, '2.10.0') >= 0; - var needWarning = !support && systemInfo.platform === "devtools"; - return function () { - if (needWarning) console.warn('当前小程序版本小于 2.10.0,不支持分片上传,请更新软件。'); - needWarning = false; - return support; - }; -})(); - -var util = { - noop: noop, - formatParams: formatParams, - apiWrapper: apiWrapper, - xml2json: xml2json, - json2xml: json2xml, - md5: md5, - clearKey: clearKey, - fileSlice: fileSlice, - getBodyMd5: getBodyMd5, - getFileMd5: getFileMd5, - binaryBase64: binaryBase64, - extend: extend, - isArray: isArray, - isInArray: isInArray, - makeArray: makeArray, - each: each, - map: map, - filter: filter, - clone: clone, - attr: attr, - uuid: uuid, - camSafeUrlEncode: camSafeUrlEncode, - throttleOnProgress: throttleOnProgress, - getFileSize: getFileSize, - getSkewTime: getSkewTime, - getAuth: getAuth, - compareVersion: compareVersion, - canFileSlice: canFileSlice, -}; - -module.exports = util; -xml2json +/* WEBPACK VAR INJECTION */(function(global) { + +var md5 = __webpack_require__(8); +var CryptoJS = __webpack_require__(11); +var xml2json = __webpack_require__(12); +var json2xml = __webpack_require__(15); +var base64 = __webpack_require__(3); +var btoa = base64.btoa; +var wxfs = wx.getFileSystemManager(); + +function camSafeUrlEncode(str) { + return encodeURIComponent(str) + .replace(/!/g, '%21') + .replace(/'/g, '%27') + .replace(/\(/g, '%28') + .replace(/\)/g, '%29') + .replace(/\*/g, '%2A'); +} + +//测试用的key后面可以去掉 +var getAuth = function (opt) { + opt = opt || {}; + + var SecretId = opt.SecretId; + var SecretKey = opt.SecretKey; + var KeyTime = opt.KeyTime; + var method = (opt.method || opt.Method || 'get').toLowerCase(); + var queryParams = clone(opt.Query || opt.params || {}); + var headers = clone(opt.Headers || opt.headers || {}); + + var Key = opt.Key || ''; + var pathname; + if (opt.UseRawKey) { + pathname = opt.Pathname || opt.pathname || '/' + Key; + } else { + pathname = opt.Pathname || opt.pathname || Key; + pathname.indexOf('/') !== 0 && (pathname = '/' + pathname); + } + + if (!SecretId) return console.error('missing param SecretId'); + if (!SecretKey) return console.error('missing param SecretKey'); + + var getObjectKeys = function (obj, forKey) { + var list = []; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + list.push(forKey ? camSafeUrlEncode(key).toLowerCase() : key); + } + } + return list.sort(function (a, b) { + a = a.toLowerCase(); + b = b.toLowerCase(); + return a === b ? 0 : (a > b ? 1 : -1); + }); + }; + + var obj2str = function (obj) { + var i, key, val; + var list = []; + var keyList = getObjectKeys(obj); + for (i = 0; i < keyList.length; i++) { + key = keyList[i]; + val = (obj[key] === undefined || obj[key] === null) ? '' : ('' + obj[key]); + key = camSafeUrlEncode(key).toLowerCase(); + val = camSafeUrlEncode(val) || ''; + list.push(key + '=' + val) + } + return list.join('&'); + }; + + // 签名有效起止时间 + var now = Math.round(getSkewTime(opt.SystemClockOffset) / 1000) - 1; + var exp = now; + + var Expires = opt.Expires || opt.expires; + if (Expires === undefined) { + exp += 900; // 签名过期时间为当前 + 900s + } else { + exp += (Expires * 1) || 0; + } + + // 要用到的 Authorization 参数列表 + var qSignAlgorithm = 'sha1'; + var qAk = SecretId; + var qSignTime = KeyTime || now + ';' + exp; + var qKeyTime = KeyTime || now + ';' + exp; + var qHeaderList = getObjectKeys(headers, true).join(';').toLowerCase(); + var qUrlParamList = getObjectKeys(queryParams, true).join(';').toLowerCase(); + + // 签名算法说明文档:https://www.qcloud.com/document/product/436/7778 + // 步骤一:计算 SignKey + var signKey = CryptoJS.HmacSHA1(qKeyTime, SecretKey).toString(); + + // 步骤二:构成 FormatString + var formatString = [method, pathname, obj2str(queryParams), obj2str(headers), ''].join('\n'); + + // 步骤三:计算 StringToSign + var stringToSign = ['sha1', qSignTime, CryptoJS.SHA1(formatString).toString(), ''].join('\n'); + + // 步骤四:计算 Signature + var qSignature = CryptoJS.HmacSHA1(stringToSign, signKey).toString(); + + // 步骤五:构造 Authorization + var authorization = [ + 'q-sign-algorithm=' + qSignAlgorithm, + 'q-ak=' + qAk, + 'q-sign-time=' + qSignTime, + 'q-key-time=' + qKeyTime, + 'q-header-list=' + qHeaderList, + 'q-url-param-list=' + qUrlParamList, + 'q-signature=' + qSignature + ].join('&'); + + return authorization; + +}; + +var noop = function () { + +}; + +// 清除对象里值为的 undefined 或 null 的属性 +var clearKey = function (obj) { + var retObj = {}; + for (var key in obj) { + if (obj.hasOwnProperty(key) && obj[key] !== undefined && obj[key] !== null) { + retObj[key] = obj[key]; + } + } + return retObj; +}; + +// 获取文件分片 +var fileSlice = function (FilePath, start, end, callback) { + if (FilePath) { + wxfs.readFile({ + filePath: FilePath, + position: start, + length: end - start, + success: function (res) { + callback(res.data); + }, + fail: function () { + callback(null); + }, + }); + } else { + callback(null); + } +}; + +// 获取文件内容的 MD5 +var getBodyMd5 = function (UploadCheckContentMd5, Body, callback) { + callback = callback || noop; + if (UploadCheckContentMd5) { + if (Body && Body instanceof ArrayBuffer) { + util.getFileMd5(Body, function (err, md5) { + callback(md5); + }); + } else { + callback(); + } + } else { + callback(); + } +}; + +// 获取文件 md5 值 +var getFileMd5 = function (body, callback) { + var hash = md5(body); + callback && callback(hash); + return hash; +}; + +function clone(obj) { + return map(obj, function (v) { + return typeof v === 'object' ? clone(v) : v; + }); +} + +function attr(obj, name, defaultValue) { + return obj && name in obj ? obj[name] : defaultValue; +} + +function extend(target, source) { + each(source, function (val, key) { + target[key] = source[key]; + }); + return target; +} + +function isArray(arr) { + return arr instanceof Array; +} + +function isInArray(arr, item) { + var flag = false; + for (var i = 0; i < arr.length; i++) { + if (item === arr[i]) { + flag = true; + break; + } + } + return flag; +} + +function makeArray(arr) { + return isArray(arr) ? arr : [arr]; +} + +function each(obj, fn) { + for (var i in obj) { + if (obj.hasOwnProperty(i)) { + fn(obj[i], i); + } + } +} + +function map(obj, fn) { + var o = isArray(obj) ? [] : {}; + for (var i in obj) { + if (obj.hasOwnProperty(i)) { + o[i] = fn(obj[i], i); + } + } + return o; +} + +function filter(obj, fn) { + var iaArr = isArray(obj); + var o = iaArr ? [] : {}; + for (var i in obj) { + if (obj.hasOwnProperty(i)) { + if (fn(obj[i], i)) { + if (iaArr) { + o.push(obj[i]); + } else { + o[i] = obj[i]; + } + } + } + } + return o; +} + +var binaryBase64 = function (str) { + var i, len, char, res = ''; + for (i = 0, len = str.length / 2; i < len; i++) { + char = parseInt(str[i * 2] + str[i * 2 + 1], 16); + res += String.fromCharCode(char); + } + return btoa(res); +}; +var uuid = function () { + var S4 = function () { + return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); + }; + return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4()); +}; + +var hasMissingParams = function (apiName, params) { + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + if (apiName.indexOf('Bucket') > -1 || apiName === 'deleteMultipleObject' || apiName === 'multipartList' || apiName === 'listObjectVersions') { + if (!Bucket) return 'Bucket'; + if (!Region) return 'Region'; + } else if (apiName.indexOf('Object') > -1 || apiName.indexOf('multipart') > -1 || apiName === 'sliceUploadFile' || apiName === 'abortUploadTask') { + if (!Bucket) return 'Bucket'; + if (!Region) return 'Region'; + if (!Key) return 'Key'; + } + return false; +}; + +var formatParams = function (apiName, params) { + + // 复制参数对象 + params = extend({}, params); + + // 统一处理 Headers + if (apiName !== 'getAuth' && apiName !== 'getV4Auth' && apiName !== 'getObjectUrl') { + var Headers = params.Headers || {}; + if (params && typeof params === 'object') { + (function () { + for (var key in params) { + if (params.hasOwnProperty(key) && key.indexOf('x-cos-') > -1) { + Headers[key] = params[key]; + } + } + })(); + + var headerMap = { + // params headers + 'x-cos-mfa': 'MFA', + 'Content-MD5': 'ContentMD5', + 'Content-Length': 'ContentLength', + 'Content-Type': 'ContentType', + 'Expect': 'Expect', + 'Expires': 'Expires', + 'Cache-Control': 'CacheControl', + 'Content-Disposition': 'ContentDisposition', + 'Content-Encoding': 'ContentEncoding', + 'Range': 'Range', + 'If-Modified-Since': 'IfModifiedSince', + 'If-Unmodified-Since': 'IfUnmodifiedSince', + 'If-Match': 'IfMatch', + 'If-None-Match': 'IfNoneMatch', + 'x-cos-copy-source': 'CopySource', + 'x-cos-copy-source-Range': 'CopySourceRange', + 'x-cos-metadata-directive': 'MetadataDirective', + 'x-cos-copy-source-If-Modified-Since': 'CopySourceIfModifiedSince', + 'x-cos-copy-source-If-Unmodified-Since': 'CopySourceIfUnmodifiedSince', + 'x-cos-copy-source-If-Match': 'CopySourceIfMatch', + 'x-cos-copy-source-If-None-Match': 'CopySourceIfNoneMatch', + 'x-cos-acl': 'ACL', + 'x-cos-grant-read': 'GrantRead', + 'x-cos-grant-write': 'GrantWrite', + 'x-cos-grant-full-control': 'GrantFullControl', + 'x-cos-grant-read-acp': 'GrantReadAcp', + 'x-cos-grant-write-acp': 'GrantWriteAcp', + 'x-cos-storage-class': 'StorageClass', + // SSE-C + 'x-cos-server-side-encryption-customer-algorithm': 'SSECustomerAlgorithm', + 'x-cos-server-side-encryption-customer-key': 'SSECustomerKey', + 'x-cos-server-side-encryption-customer-key-MD5': 'SSECustomerKeyMD5', + // SSE-COS、SSE-KMS + 'x-cos-server-side-encryption': 'ServerSideEncryption', + 'x-cos-server-side-encryption-cos-kms-key-id': 'SSEKMSKeyId', + 'x-cos-server-side-encryption-context': 'SSEContext', + }; + util.each(headerMap, function (paramKey, headerKey) { + if (params[paramKey] !== undefined) { + Headers[headerKey] = params[paramKey]; + } + }); + + params.Headers = clearKey(Headers); + } + } + + return params; +}; + +var apiWrapper = function (apiName, apiFn) { + return function (params, callback) { + + var self = this; + + // 处理参数 + if (typeof params === 'function') { + callback = params; + params = {}; + } + + // 整理参数格式 + params = formatParams(apiName, params); + + // 代理回调函数 + var formatResult = function (result) { + if (result && result.headers) { + result.headers['x-cos-version-id'] && (result.VersionId = result.headers['x-cos-version-id']); + result.headers['x-cos-delete-marker'] && (result.DeleteMarker = result.headers['x-cos-delete-marker']); + } + return result; + }; + var _callback = function (err, data) { + callback && callback(formatResult(err), formatResult(data)); + }; + + var checkParams = function () { + if (apiName !== 'getService' && apiName !== 'abortUploadTask') { + // 判断参数是否完整 + var missingResult = hasMissingParams(apiName, params) + if (missingResult) { + return 'missing param ' + missingResult; + } + // 判断 region 格式 + if (params.Region) { + if (params.Region.indexOf('cos.') > -1) { + return 'param Region should not be start with "cos."'; + } else if (!/^([a-z\d-]+)$/.test(params.Region)) { + return 'Region format error.'; + } + // 判断 region 格式 + if (!self.options.CompatibilityMode + && params.Region.indexOf('-') === -1 + && params.Region !== 'yfb' + && params.Region !== 'default' + && params.Region !== 'accelerate') { + console.warn('warning: param Region format error, find help here: https://cloud.tencent.com/document/product/436/6224'); + } + } + // 兼容不带 AppId 的 Bucket + if (params.Bucket) { + if (!/^([a-z\d-]+)-(\d+)$/.test(params.Bucket)) { + if (params.AppId) { + params.Bucket = params.Bucket + '-' + params.AppId; + } else if (self.options.AppId) { + params.Bucket = params.Bucket + '-' + self.options.AppId; + } else { + return 'Bucket should format as "test-1250000000".'; + } + } + if (params.AppId) { + console.warn('warning: AppId has been deprecated, Please put it at the end of parameter Bucket(E.g Bucket:"test-1250000000" ).'); + delete params.AppId; + } + } + // 如果 Key 是 / 开头,强制去掉第一个 / + if (params.Key && params.Key.substr(0, 1) === '/') { + params.Key = params.Key.substr(1); + } + } + }; + + var errMsg = checkParams(); + var isSync = apiName === 'getAuth' || apiName === 'getObjectUrl'; + var Promise = global.Promise; + if (!isSync && Promise && !callback) { + return new Promise(function (resolve, reject) { + callback = function (err, data) { + err ? reject(err) : resolve(data); + }; + if (errMsg) return _callback({error: errMsg}); + apiFn.call(self, params, _callback); + }); + } else { + if (errMsg) return _callback({error: errMsg}); + var res = apiFn.call(self, params, _callback); + if (isSync) return res; + } + } +}; + +var throttleOnProgress = function (total, onProgress) { + var self = this; + var size0 = 0; + var size1 = 0; + var time0 = Date.now(); + var time1; + var timer; + + function update() { + timer = 0; + if (onProgress && (typeof onProgress === 'function')) { + time1 = Date.now(); + var speed = Math.max(0, Math.round((size1 - size0) / ((time1 - time0) / 1000) * 100) / 100) || 0; + var percent; + if (size1 === 0 && total === 0) { + percent = 1; + } else { + percent = Math.floor(size1 / total * 100) / 100 || 0; + } + time0 = time1; + size0 = size1; + try { + onProgress({loaded: size1, total: total, speed: speed, percent: percent}); + } catch (e) { + } + } + } + + return function (info, immediately) { + if (info) { + size1 = info.loaded; + total = info.total; + } + if (immediately) { + clearTimeout(timer); + update(); + } else { + if (timer) return; + timer = setTimeout(update, self.options.ProgressInterval); + } + }; +}; + +var getFileSize = function (api, params, callback) { + if (api === 'postObject') { + callback(); + } else if (api === 'putObject') { + if (params.Body !== undefined) { + params.ContentLength = params.Body.byteLength; + callback(null, params.ContentLength); + } else { + callback({error: 'missing param Body'}); + } + } else { + if (params.FilePath) { + wxfs.stat({ + path: params.FilePath, + success: function (res) { + var stats = res.stats; + params.FileStat = stats; + params.FileStat.FilePath = params.FilePath; + var size = stats.isDirectory() ? 0 : stats.size; + params.ContentLength = size = size || 0; + callback(null, size); + }, + fail: function (err) { + callback(err); + }, + }); + } else { + callback({error: 'missing param FilePath'}); + } + } +}; + +var getSkewTime = function (offset) { + return Date.now() + (offset || 0); +}; + +var compareVersion = function (v1, v2) { + v1 = v1.split('.') + v2 = v2.split('.') + var len = Math.max(v1.length, v2.length) + + while (v1.length < len) { + v1.push('0') + } + while (v2.length < len) { + v2.push('0') + } + + for (var i = 0; i < len; i++) { + var num1 = parseInt(v1[i]) + var num2 = parseInt(v2[i]) + + if (num1 > num2) { + return 1 + } else if (num1 < num2) { + return -1 + } + } + + return 0 +}; + +var canFileSlice = (function () { + var systemInfo = wx.getSystemInfoSync(); + var support = compareVersion(systemInfo.SDKVersion, '2.10.0') >= 0; + var needWarning = !support && systemInfo.platform === "devtools"; + return function () { + if (needWarning) console.warn('当前小程序版本小于 2.10.0,不支持分片上传,请更新软件。'); + needWarning = false; + return support; + }; +})(); + +var util = { + noop: noop, + formatParams: formatParams, + apiWrapper: apiWrapper, + xml2json: xml2json, + json2xml: json2xml, + md5: md5, + clearKey: clearKey, + fileSlice: fileSlice, + getBodyMd5: getBodyMd5, + getFileMd5: getFileMd5, + binaryBase64: binaryBase64, + extend: extend, + isArray: isArray, + isInArray: isInArray, + makeArray: makeArray, + each: each, + map: map, + filter: filter, + clone: clone, + attr: attr, + uuid: uuid, + camSafeUrlEncode: camSafeUrlEncode, + throttleOnProgress: throttleOnProgress, + getFileSize: getFileSize, + getSkewTime: getSkewTime, + getAuth: getAuth, + compareVersion: compareVersion, + canFileSlice: canFileSlice, +}; + +module.exports = util; +xml2json /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1))) @@ -1946,332 +1946,332 @@ try{ /* 3 */ /***/ (function(module, exports) { -/* - * $Id: base64.js,v 2.15 2014/04/05 12:58:57 dankogai Exp dankogai $ - * - * Licensed under the BSD 3-Clause License. - * http://opensource.org/licenses/BSD-3-Clause - * - * References: - * http://en.wikipedia.org/wiki/Base64 - */ - -var Base64 = (function(global) { - global = global || {}; - 'use strict'; - // existing version for noConflict() - var _Base64 = global.Base64; - var version = "2.1.9"; - // if node.js, we use Buffer - var buffer; - // constants - var b64chars - = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - var b64tab = function(bin) { - var t = {}; - for (var i = 0, l = bin.length; i < l; i++) t[bin.charAt(i)] = i; - return t; - }(b64chars); - var fromCharCode = String.fromCharCode; - // encoder stuff - var cb_utob = function(c) { - if (c.length < 2) { - var cc = c.charCodeAt(0); - return cc < 0x80 ? c - : cc < 0x800 ? (fromCharCode(0xc0 | (cc >>> 6)) - + fromCharCode(0x80 | (cc & 0x3f))) - : (fromCharCode(0xe0 | ((cc >>> 12) & 0x0f)) - + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) - + fromCharCode(0x80 | ( cc & 0x3f))); - } else { - var cc = 0x10000 - + (c.charCodeAt(0) - 0xD800) * 0x400 - + (c.charCodeAt(1) - 0xDC00); - return (fromCharCode(0xf0 | ((cc >>> 18) & 0x07)) - + fromCharCode(0x80 | ((cc >>> 12) & 0x3f)) - + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) - + fromCharCode(0x80 | ( cc & 0x3f))); - } - }; - var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g; - var utob = function(u) { - return u.replace(re_utob, cb_utob); - }; - var cb_encode = function(ccc) { - var padlen = [0, 2, 1][ccc.length % 3], - ord = ccc.charCodeAt(0) << 16 - | ((ccc.length > 1 ? ccc.charCodeAt(1) : 0) << 8) - | ((ccc.length > 2 ? ccc.charCodeAt(2) : 0)), - chars = [ - b64chars.charAt( ord >>> 18), - b64chars.charAt((ord >>> 12) & 63), - padlen >= 2 ? '=' : b64chars.charAt((ord >>> 6) & 63), - padlen >= 1 ? '=' : b64chars.charAt(ord & 63) - ]; - return chars.join(''); - }; - var btoa = global.btoa ? function(b) { - return global.btoa(b); - } : function(b) { - return b.replace(/[\s\S]{1,3}/g, cb_encode); - }; - var _encode = buffer ? function (u) { - return (u.constructor === buffer.constructor ? u : new buffer(u)) - .toString('base64') - } - : function (u) { return btoa(utob(u)) } - ; - var encode = function(u, urisafe) { - return !urisafe - ? _encode(String(u)) - : _encode(String(u)).replace(/[+\/]/g, function(m0) { - return m0 == '+' ? '-' : '_'; - }).replace(/=/g, ''); - }; - var encodeURI = function(u) { return encode(u, true) }; - // decoder stuff - var re_btou = new RegExp([ - '[\xC0-\xDF][\x80-\xBF]', - '[\xE0-\xEF][\x80-\xBF]{2}', - '[\xF0-\xF7][\x80-\xBF]{3}' - ].join('|'), 'g'); - var cb_btou = function(cccc) { - switch(cccc.length) { - case 4: - var cp = ((0x07 & cccc.charCodeAt(0)) << 18) - | ((0x3f & cccc.charCodeAt(1)) << 12) - | ((0x3f & cccc.charCodeAt(2)) << 6) - | (0x3f & cccc.charCodeAt(3)), - offset = cp - 0x10000; - return (fromCharCode((offset >>> 10) + 0xD800) - + fromCharCode((offset & 0x3FF) + 0xDC00)); - case 3: - return fromCharCode( - ((0x0f & cccc.charCodeAt(0)) << 12) - | ((0x3f & cccc.charCodeAt(1)) << 6) - | (0x3f & cccc.charCodeAt(2)) - ); - default: - return fromCharCode( - ((0x1f & cccc.charCodeAt(0)) << 6) - | (0x3f & cccc.charCodeAt(1)) - ); - } - }; - var btou = function(b) { - return b.replace(re_btou, cb_btou); - }; - var cb_decode = function(cccc) { - var len = cccc.length, - padlen = len % 4, - n = (len > 0 ? b64tab[cccc.charAt(0)] << 18 : 0) - | (len > 1 ? b64tab[cccc.charAt(1)] << 12 : 0) - | (len > 2 ? b64tab[cccc.charAt(2)] << 6 : 0) - | (len > 3 ? b64tab[cccc.charAt(3)] : 0), - chars = [ - fromCharCode( n >>> 16), - fromCharCode((n >>> 8) & 0xff), - fromCharCode( n & 0xff) - ]; - chars.length -= [0, 0, 2, 1][padlen]; - return chars.join(''); - }; - var atob = global.atob ? function(a) { - return global.atob(a); - } : function(a){ - return a.replace(/[\s\S]{1,4}/g, cb_decode); - }; - var _decode = buffer ? function(a) { - return (a.constructor === buffer.constructor - ? a : new buffer(a, 'base64')).toString(); - } - : function(a) { return btou(atob(a)) }; - var decode = function(a){ - return _decode( - String(a).replace(/[-_]/g, function(m0) { return m0 == '-' ? '+' : '/' }) - .replace(/[^A-Za-z0-9\+\/]/g, '') - ); - }; - var noConflict = function() { - var Base64 = global.Base64; - global.Base64 = _Base64; - return Base64; - }; - // export Base64 - var Base64 = { - VERSION: version, - atob: atob, - btoa: btoa, - fromBase64: decode, - toBase64: encode, - utob: utob, - encode: encode, - encodeURI: encodeURI, - btou: btou, - decode: decode, - noConflict: noConflict - }; - return Base64; -})(); - -module.exports = Base64; - +/* + * $Id: base64.js,v 2.15 2014/04/05 12:58:57 dankogai Exp dankogai $ + * + * Licensed under the BSD 3-Clause License. + * http://opensource.org/licenses/BSD-3-Clause + * + * References: + * http://en.wikipedia.org/wiki/Base64 + */ + +var Base64 = (function(global) { + global = global || {}; + 'use strict'; + // existing version for noConflict() + var _Base64 = global.Base64; + var version = "2.1.9"; + // if node.js, we use Buffer + var buffer; + // constants + var b64chars + = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + var b64tab = function(bin) { + var t = {}; + for (var i = 0, l = bin.length; i < l; i++) t[bin.charAt(i)] = i; + return t; + }(b64chars); + var fromCharCode = String.fromCharCode; + // encoder stuff + var cb_utob = function(c) { + if (c.length < 2) { + var cc = c.charCodeAt(0); + return cc < 0x80 ? c + : cc < 0x800 ? (fromCharCode(0xc0 | (cc >>> 6)) + + fromCharCode(0x80 | (cc & 0x3f))) + : (fromCharCode(0xe0 | ((cc >>> 12) & 0x0f)) + + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) + + fromCharCode(0x80 | ( cc & 0x3f))); + } else { + var cc = 0x10000 + + (c.charCodeAt(0) - 0xD800) * 0x400 + + (c.charCodeAt(1) - 0xDC00); + return (fromCharCode(0xf0 | ((cc >>> 18) & 0x07)) + + fromCharCode(0x80 | ((cc >>> 12) & 0x3f)) + + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) + + fromCharCode(0x80 | ( cc & 0x3f))); + } + }; + var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g; + var utob = function(u) { + return u.replace(re_utob, cb_utob); + }; + var cb_encode = function(ccc) { + var padlen = [0, 2, 1][ccc.length % 3], + ord = ccc.charCodeAt(0) << 16 + | ((ccc.length > 1 ? ccc.charCodeAt(1) : 0) << 8) + | ((ccc.length > 2 ? ccc.charCodeAt(2) : 0)), + chars = [ + b64chars.charAt( ord >>> 18), + b64chars.charAt((ord >>> 12) & 63), + padlen >= 2 ? '=' : b64chars.charAt((ord >>> 6) & 63), + padlen >= 1 ? '=' : b64chars.charAt(ord & 63) + ]; + return chars.join(''); + }; + var btoa = global.btoa ? function(b) { + return global.btoa(b); + } : function(b) { + return b.replace(/[\s\S]{1,3}/g, cb_encode); + }; + var _encode = buffer ? function (u) { + return (u.constructor === buffer.constructor ? u : new buffer(u)) + .toString('base64') + } + : function (u) { return btoa(utob(u)) } + ; + var encode = function(u, urisafe) { + return !urisafe + ? _encode(String(u)) + : _encode(String(u)).replace(/[+\/]/g, function(m0) { + return m0 == '+' ? '-' : '_'; + }).replace(/=/g, ''); + }; + var encodeURI = function(u) { return encode(u, true) }; + // decoder stuff + var re_btou = new RegExp([ + '[\xC0-\xDF][\x80-\xBF]', + '[\xE0-\xEF][\x80-\xBF]{2}', + '[\xF0-\xF7][\x80-\xBF]{3}' + ].join('|'), 'g'); + var cb_btou = function(cccc) { + switch(cccc.length) { + case 4: + var cp = ((0x07 & cccc.charCodeAt(0)) << 18) + | ((0x3f & cccc.charCodeAt(1)) << 12) + | ((0x3f & cccc.charCodeAt(2)) << 6) + | (0x3f & cccc.charCodeAt(3)), + offset = cp - 0x10000; + return (fromCharCode((offset >>> 10) + 0xD800) + + fromCharCode((offset & 0x3FF) + 0xDC00)); + case 3: + return fromCharCode( + ((0x0f & cccc.charCodeAt(0)) << 12) + | ((0x3f & cccc.charCodeAt(1)) << 6) + | (0x3f & cccc.charCodeAt(2)) + ); + default: + return fromCharCode( + ((0x1f & cccc.charCodeAt(0)) << 6) + | (0x3f & cccc.charCodeAt(1)) + ); + } + }; + var btou = function(b) { + return b.replace(re_btou, cb_btou); + }; + var cb_decode = function(cccc) { + var len = cccc.length, + padlen = len % 4, + n = (len > 0 ? b64tab[cccc.charAt(0)] << 18 : 0) + | (len > 1 ? b64tab[cccc.charAt(1)] << 12 : 0) + | (len > 2 ? b64tab[cccc.charAt(2)] << 6 : 0) + | (len > 3 ? b64tab[cccc.charAt(3)] : 0), + chars = [ + fromCharCode( n >>> 16), + fromCharCode((n >>> 8) & 0xff), + fromCharCode( n & 0xff) + ]; + chars.length -= [0, 0, 2, 1][padlen]; + return chars.join(''); + }; + var atob = global.atob ? function(a) { + return global.atob(a); + } : function(a){ + return a.replace(/[\s\S]{1,4}/g, cb_decode); + }; + var _decode = buffer ? function(a) { + return (a.constructor === buffer.constructor + ? a : new buffer(a, 'base64')).toString(); + } + : function(a) { return btou(atob(a)) }; + var decode = function(a){ + return _decode( + String(a).replace(/[-_]/g, function(m0) { return m0 == '-' ? '+' : '/' }) + .replace(/[^A-Za-z0-9\+\/]/g, '') + ); + }; + var noConflict = function() { + var Base64 = global.Base64; + global.Base64 = _Base64; + return Base64; + }; + // export Base64 + var Base64 = { + VERSION: version, + atob: atob, + btoa: btoa, + fromBase64: decode, + toBase64: encode, + utob: utob, + encode: encode, + encodeURI: encodeURI, + btou: btou, + decode: decode, + noConflict: noConflict + }; + return Base64; +})(); + +module.exports = Base64; + /***/ }), /* 4 */ /***/ (function(module, exports) { -var initEvent = function (cos) { - var listeners = {}; - var getList = function (action) { - !listeners[action] && (listeners[action] = []); - return listeners[action]; - }; - cos.on = function (action, callback) { - getList(action).push(callback); - }; - cos.off = function (action, callback) { - var list = getList(action); - for (var i = list.length - 1; i >= 0; i--) { - callback === list[i] && list.splice(i, 1); - } - }; - cos.emit = function (action, data) { - var list = getList(action).map(function (cb) { - return cb; - }); - for (var i = 0; i < list.length; i++) { - list[i](data); - } - }; -}; - -var EventProxy = function () { - initEvent(this); -}; - -module.exports.init = initEvent; +var initEvent = function (cos) { + var listeners = {}; + var getList = function (action) { + !listeners[action] && (listeners[action] = []); + return listeners[action]; + }; + cos.on = function (action, callback) { + getList(action).push(callback); + }; + cos.off = function (action, callback) { + var list = getList(action); + for (var i = list.length - 1; i >= 0; i--) { + callback === list[i] && list.splice(i, 1); + } + }; + cos.emit = function (action, data) { + var list = getList(action).map(function (cb) { + return cb; + }); + for (var i = 0; i < list.length; i++) { + list[i](data); + } + }; +}; + +var EventProxy = function () { + initEvent(this); +}; + +module.exports.init = initEvent; module.exports.EventProxy = EventProxy; /***/ }), /* 5 */ /***/ (function(module, exports, __webpack_require__) { -var util = __webpack_require__(0); - -// 按照文件特征值,缓存 UploadId -var cacheKey = 'cos_sdk_upload_cache'; -var expires = 30 * 24 * 3600; -var cache; -var timer; - -var getCache = function () { - try { - var val = JSON.parse(wx.getStorageSync(cacheKey)); - } catch (e) { - } - if (!val) val = []; - return val; -}; -var setCache = function () { - try { - wx.setStorageSync(cacheKey, JSON.stringify(cache)) - } catch (e) { - } -}; - -var init = function () { - if (cache) return; - cache = getCache(); - // 清理太老旧的数据 - var changed = false; - var now = Math.round(Date.now() / 1000); - for (var i = cache.length - 1; i >= 0; i--) { - var mtime = cache[i][2]; - if (!mtime || mtime + expires < now) { - cache.splice(i, 1); - changed = true; - } - } - changed && setCache(); -}; - -// 把缓存存到本地 -var save = function () { - if (timer) return; - timer = setTimeout(function () { - setCache(); - timer = null; - }, 400); -}; - -var mod = { - using: {}, - // 标记 UploadId 正在使用 - setUsing: function (uuid) { - mod.using[uuid] = true; - }, - // 标记 UploadId 已经没在使用 - removeUsing: function (uuid) { - delete mod.using[uuid]; - }, - // 用上传参数生成哈希值 - getFileId: function (FileStat, ChunkSize, Bucket, Key) { - if (FileStat.FilePath && FileStat.size && FileStat.lastModifiedTime && ChunkSize) { - return util.md5([FileStat.FilePath].join('::')) + '-' + util.md5([FileStat.size, FileStat.mode, FileStat.lastAccessedTime, FileStat.lastModifiedTime, ChunkSize, Bucket, Key].join('::')); - } else { - return null; - } - }, - // 获取文件对应的 UploadId 列表 - getUploadIdList: function (uuid) { - if (!uuid) return null; - init(); - var list = []; - for (var i = 0; i < cache.length; i++) { - if (cache[i][0] === uuid) - list.push(cache[i][1]); - } - return list.length ? list : null; - }, - // 缓存 UploadId - saveUploadId: function (uuid, UploadId, limit) { - init(); - if (!uuid) return; - // 清理没用的 UploadId - var part1 = uuid.substr(0, uuid.indexOf('-') + 1); - for (var i = cache.length - 1; i >= 0; i--) { - var item = cache[i]; - if (item[0] === uuid && item[1] === UploadId) { - cache.splice(i, 1); - } else if (uuid !== item[0] && item[0].indexOf(part1) === 0) { // 文件路径相同,但其他信息不同,说明文件改变了或上传参数(存储桶、路径、分片大小)变了,直接清理掉 - cache.splice(i, 1); - } - } - cache.unshift([uuid, UploadId, Math.round(Date.now() / 1000)]); - if (cache.length > limit) cache.splice(limit); - save(); - }, - // UploadId 已用完,移除掉 - removeUploadId: function (UploadId) { - init(); - delete mod.using[UploadId]; - for (var i = cache.length - 1; i >= 0; i--) { - if (cache[i][1] === UploadId) cache.splice(i, 1) - } - save(); - }, -}; - -module.exports = mod; +var util = __webpack_require__(0); + +// 按照文件特征值,缓存 UploadId +var cacheKey = 'cos_sdk_upload_cache'; +var expires = 30 * 24 * 3600; +var cache; +var timer; + +var getCache = function () { + try { + var val = JSON.parse(wx.getStorageSync(cacheKey)); + } catch (e) { + } + if (!val) val = []; + return val; +}; +var setCache = function () { + try { + wx.setStorageSync(cacheKey, JSON.stringify(cache)) + } catch (e) { + } +}; + +var init = function () { + if (cache) return; + cache = getCache(); + // 清理太老旧的数据 + var changed = false; + var now = Math.round(Date.now() / 1000); + for (var i = cache.length - 1; i >= 0; i--) { + var mtime = cache[i][2]; + if (!mtime || mtime + expires < now) { + cache.splice(i, 1); + changed = true; + } + } + changed && setCache(); +}; + +// 把缓存存到本地 +var save = function () { + if (timer) return; + timer = setTimeout(function () { + setCache(); + timer = null; + }, 400); +}; + +var mod = { + using: {}, + // 标记 UploadId 正在使用 + setUsing: function (uuid) { + mod.using[uuid] = true; + }, + // 标记 UploadId 已经没在使用 + removeUsing: function (uuid) { + delete mod.using[uuid]; + }, + // 用上传参数生成哈希值 + getFileId: function (FileStat, ChunkSize, Bucket, Key) { + if (FileStat.FilePath && FileStat.size && FileStat.lastModifiedTime && ChunkSize) { + return util.md5([FileStat.FilePath].join('::')) + '-' + util.md5([FileStat.size, FileStat.mode, FileStat.lastAccessedTime, FileStat.lastModifiedTime, ChunkSize, Bucket, Key].join('::')); + } else { + return null; + } + }, + // 获取文件对应的 UploadId 列表 + getUploadIdList: function (uuid) { + if (!uuid) return null; + init(); + var list = []; + for (var i = 0; i < cache.length; i++) { + if (cache[i][0] === uuid) + list.push(cache[i][1]); + } + return list.length ? list : null; + }, + // 缓存 UploadId + saveUploadId: function (uuid, UploadId, limit) { + init(); + if (!uuid) return; + // 清理没用的 UploadId + var part1 = uuid.substr(0, uuid.indexOf('-') + 1); + for (var i = cache.length - 1; i >= 0; i--) { + var item = cache[i]; + if (item[0] === uuid && item[1] === UploadId) { + cache.splice(i, 1); + } else if (uuid !== item[0] && item[0].indexOf(part1) === 0) { // 文件路径相同,但其他信息不同,说明文件改变了或上传参数(存储桶、路径、分片大小)变了,直接清理掉 + cache.splice(i, 1); + } + } + cache.unshift([uuid, UploadId, Math.round(Date.now() / 1000)]); + if (cache.length > limit) cache.splice(limit); + save(); + }, + // UploadId 已用完,移除掉 + removeUploadId: function (UploadId) { + init(); + delete mod.using[UploadId]; + for (var i = cache.length - 1; i >= 0; i--) { + if (cache[i][1] === UploadId) cache.splice(i, 1) + } + save(); + }, +}; + +module.exports = mod; /***/ }), /* 6 */ /***/ (function(module, exports, __webpack_require__) { -var COS = __webpack_require__(7); +var COS = __webpack_require__(7); module.exports = COS; /***/ }), @@ -2279,750 +2279,750 @@ module.exports = COS; /***/ (function(module, exports, __webpack_require__) { "use strict"; - - -var util = __webpack_require__(0); -var event = __webpack_require__(4); -var task = __webpack_require__(16); -var base = __webpack_require__(17); -var advance = __webpack_require__(23); - -var defaultOptions = { - SecretId: '', - SecretKey: '', - XCosSecurityToken: '', // 使用临时密钥需要注意自行刷新 Token - ChunkRetryTimes: 2, - FileParallelLimit: 3, - ChunkParallelLimit: 3, - ChunkSize: 1024 * 1024, - SliceSize: 1024 * 1024, - CopyChunkParallelLimit: 20, - CopyChunkSize: 1024 * 1024 * 10, - CopySliceSize: 1024 * 1024 * 10, - MaxPartNumber: 10000, - ProgressInterval: 1000, - UploadQueueSize: 10000, - Domain: '', - ServiceDomain: '', - Protocol: '', - CompatibilityMode: false, - ForcePathStyle: false, - Timeout: 0, // 单位毫秒,0 代表不设置超时时间 - CorrectClockSkew: true, - SystemClockOffset: 0, // 单位毫秒,ms - UploadCheckContentMd5: false, - UploadIdCacheLimit: 50, - UseAccelerate: false, -}; - -// 对外暴露的类 -var COS = function (options) { - this.options = util.extend(util.clone(defaultOptions), options || {}); - this.options.FileParallelLimit = Math.max(1, this.options.FileParallelLimit); - this.options.ChunkParallelLimit = Math.max(1, this.options.ChunkParallelLimit); - this.options.ChunkRetryTimes = Math.max(0, this.options.ChunkRetryTimes); - this.options.ChunkSize = Math.max(1024 * 1024, this.options.ChunkSize); - this.options.CopyChunkParallelLimit = Math.max(1, this.options.CopyChunkParallelLimit); - this.options.CopyChunkSize = Math.max(1024 * 1024, this.options.CopyChunkSize); - this.options.CopySliceSize = Math.max(0, this.options.CopySliceSize); - this.options.MaxPartNumber = Math.max(1024, Math.min(10000, this.options.MaxPartNumber)); - this.options.Timeout = Math.max(0, this.options.Timeout); - if (this.options.AppId) { - console.warn('warning: AppId has been deprecated, Please put it at the end of parameter Bucket(E.g: "test-1250000000").'); - } - event.init(this); - task.init(this); -}; - -base.init(COS, task); -advance.init(COS, task); - -COS.getAuthorization = util.getAuth; -COS.version = '1.0.7'; - -module.exports = COS; + + +var util = __webpack_require__(0); +var event = __webpack_require__(4); +var task = __webpack_require__(16); +var base = __webpack_require__(17); +var advance = __webpack_require__(23); + +var defaultOptions = { + SecretId: '', + SecretKey: '', + XCosSecurityToken: '', // 使用临时密钥需要注意自行刷新 Token + ChunkRetryTimes: 2, + FileParallelLimit: 3, + ChunkParallelLimit: 3, + ChunkSize: 1024 * 1024, + SliceSize: 1024 * 1024, + CopyChunkParallelLimit: 20, + CopyChunkSize: 1024 * 1024 * 10, + CopySliceSize: 1024 * 1024 * 10, + MaxPartNumber: 10000, + ProgressInterval: 1000, + UploadQueueSize: 10000, + Domain: '', + ServiceDomain: '', + Protocol: '', + CompatibilityMode: false, + ForcePathStyle: false, + Timeout: 0, // 单位毫秒,0 代表不设置超时时间 + CorrectClockSkew: true, + SystemClockOffset: 0, // 单位毫秒,ms + UploadCheckContentMd5: false, + UploadIdCacheLimit: 50, + UseAccelerate: false, +}; + +// 对外暴露的类 +var COS = function (options) { + this.options = util.extend(util.clone(defaultOptions), options || {}); + this.options.FileParallelLimit = Math.max(1, this.options.FileParallelLimit); + this.options.ChunkParallelLimit = Math.max(1, this.options.ChunkParallelLimit); + this.options.ChunkRetryTimes = Math.max(0, this.options.ChunkRetryTimes); + this.options.ChunkSize = Math.max(1024 * 1024, this.options.ChunkSize); + this.options.CopyChunkParallelLimit = Math.max(1, this.options.CopyChunkParallelLimit); + this.options.CopyChunkSize = Math.max(1024 * 1024, this.options.CopyChunkSize); + this.options.CopySliceSize = Math.max(0, this.options.CopySliceSize); + this.options.MaxPartNumber = Math.max(1024, Math.min(10000, this.options.MaxPartNumber)); + this.options.Timeout = Math.max(0, this.options.Timeout); + if (this.options.AppId) { + console.warn('warning: AppId has been deprecated, Please put it at the end of parameter Bucket(E.g: "test-1250000000").'); + } + event.init(this); + task.init(this); +}; + +base.init(COS, task); +advance.init(COS, task); + +COS.getAuthorization = util.getAuth; +COS.version = '1.0.10'; + +module.exports = COS; /***/ }), /* 8 */ /***/ (function(module, exports, __webpack_require__) { -/* WEBPACK VAR INJECTION */(function(process, global) {var __WEBPACK_AMD_DEFINE_RESULT__;/* https://github.com/emn178/js-md5 */ -(function () { - 'use strict'; - - var ERROR = 'input is invalid type'; - var WINDOW = typeof window === 'object'; - var root = WINDOW ? window : {}; - if (root.JS_MD5_NO_WINDOW) { - WINDOW = false; - } - var WEB_WORKER = !WINDOW && typeof self === 'object'; - var NODE_JS = !root.JS_MD5_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node; - if (NODE_JS) { - root = global; - } else if (WEB_WORKER) { - root = self; - } - var COMMON_JS = !root.JS_MD5_NO_COMMON_JS && typeof module === 'object' && module.exports; - var AMD = "function" === 'function' && __webpack_require__(10); - var ARRAY_BUFFER = !root.JS_MD5_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined'; - var HEX_CHARS = '0123456789abcdef'.split(''); - var EXTRA = [128, 32768, 8388608, -2147483648]; - var SHIFT = [0, 8, 16, 24]; - var OUTPUT_TYPES = ['hex', 'array', 'digest', 'buffer', 'arrayBuffer', 'base64']; - var BASE64_ENCODE_CHAR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split(''); - - var blocks = [], buffer8; - if (ARRAY_BUFFER) { - var buffer = new ArrayBuffer(68); - buffer8 = new Uint8Array(buffer); - blocks = new Uint32Array(buffer); - } - - if (root.JS_MD5_NO_NODE_JS || !Array.isArray) { - Array.isArray = function (obj) { - return Object.prototype.toString.call(obj) === '[object Array]'; - }; - } - - if (ARRAY_BUFFER && (root.JS_MD5_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) { - ArrayBuffer.isView = function (obj) { - return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer; - }; - } - - /** - * @method hex - * @memberof md5 - * @description Output hash as hex string - * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash - * @returns {String} Hex string - * @example - * md5.hex('The quick brown fox jumps over the lazy dog'); - * // equal to - * md5('The quick brown fox jumps over the lazy dog'); - */ - /** - * @method digest - * @memberof md5 - * @description Output hash as bytes array - * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash - * @returns {Array} Bytes array - * @example - * md5.digest('The quick brown fox jumps over the lazy dog'); - */ - /** - * @method array - * @memberof md5 - * @description Output hash as bytes array - * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash - * @returns {Array} Bytes array - * @example - * md5.array('The quick brown fox jumps over the lazy dog'); - */ - /** - * @method arrayBuffer - * @memberof md5 - * @description Output hash as ArrayBuffer - * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash - * @returns {ArrayBuffer} ArrayBuffer - * @example - * md5.arrayBuffer('The quick brown fox jumps over the lazy dog'); - */ - /** - * @method buffer - * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead. - * @memberof md5 - * @description Output hash as ArrayBuffer - * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash - * @returns {ArrayBuffer} ArrayBuffer - * @example - * md5.buffer('The quick brown fox jumps over the lazy dog'); - */ - /** - * @method base64 - * @memberof md5 - * @description Output hash as base64 string - * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash - * @returns {String} base64 string - * @example - * md5.base64('The quick brown fox jumps over the lazy dog'); - */ - var createOutputMethod = function (outputType) { - return function (message) { - return new Md5(true).update(message)[outputType](); - }; - }; - - /** - * @method create - * @memberof md5 - * @description Create Md5 object - * @returns {Md5} Md5 object. - * @example - * var hash = md5.create(); - */ - /** - * @method update - * @memberof md5 - * @description Create and update Md5 object - * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash - * @returns {Md5} Md5 object. - * @example - * var hash = md5.update('The quick brown fox jumps over the lazy dog'); - * // equal to - * var hash = md5.create(); - * hash.update('The quick brown fox jumps over the lazy dog'); - */ - var createMethod = function () { - var method = createOutputMethod('hex'); - if (NODE_JS) { - method = nodeWrap(method); - } - method.getCtx = method.create = function () { - return new Md5(); - }; - method.update = function (message) { - return method.create().update(message); - }; - for (var i = 0; i < OUTPUT_TYPES.length; ++i) { - var type = OUTPUT_TYPES[i]; - method[type] = createOutputMethod(type); - } - return method; - }; - - var nodeWrap = function (method) { - var crypto = eval("require('crypto')"); - var Buffer = eval("require('buffer').Buffer"); - var nodeMethod = function (message) { - if (typeof message === 'string') { - return crypto.createHash('md5').update(message, 'utf8').digest('hex'); - } else { - if (message === null || message === undefined) { - throw ERROR; - } else if (message.constructor === ArrayBuffer) { - message = new Uint8Array(message); - } - } - if (Array.isArray(message) || ArrayBuffer.isView(message) || - message.constructor === Buffer) { - return crypto.createHash('md5').update(new Buffer(message)).digest('hex'); - } else { - return method(message); - } - }; - return nodeMethod; - }; - - /** - * Md5 class - * @class Md5 - * @description This is internal class. - * @see {@link md5.create} - */ - function Md5(sharedMemory) { - if (sharedMemory) { - blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] = - blocks[4] = blocks[5] = blocks[6] = blocks[7] = - blocks[8] = blocks[9] = blocks[10] = blocks[11] = - blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; - this.blocks = blocks; - this.buffer8 = buffer8; - } else { - if (ARRAY_BUFFER) { - var buffer = new ArrayBuffer(68); - this.buffer8 = new Uint8Array(buffer); - this.blocks = new Uint32Array(buffer); - } else { - this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - } - } - this.h0 = this.h1 = this.h2 = this.h3 = this.start = this.bytes = this.hBytes = 0; - this.finalized = this.hashed = false; - this.first = true; - } - - /** - * @method update - * @memberof Md5 - * @instance - * @description Update hash - * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash - * @returns {Md5} Md5 object. - * @see {@link md5.update} - */ - Md5.prototype.update = function (message) { - if (this.finalized) { - return; - } - - var notString, type = typeof message; - if (type !== 'string') { - if (type === 'object') { - if (message === null) { - throw ERROR; - } else if (ARRAY_BUFFER && (message.constructor === ArrayBuffer || message.constructor.name === 'ArrayBuffer')) { - message = new Uint8Array(message); - } else if (!Array.isArray(message)) { - if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) { - throw ERROR; - } - } - } else { - throw ERROR; - } - notString = true; - } - var code, index = 0, i, length = message.length, blocks = this.blocks; - var buffer8 = this.buffer8; - - while (index < length) { - if (this.hashed) { - this.hashed = false; - blocks[0] = blocks[16]; - blocks[16] = blocks[1] = blocks[2] = blocks[3] = - blocks[4] = blocks[5] = blocks[6] = blocks[7] = - blocks[8] = blocks[9] = blocks[10] = blocks[11] = - blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; - } - - if (notString) { - if (ARRAY_BUFFER) { - for (i = this.start; index < length && i < 64; ++index) { - buffer8[i++] = message[index]; - } - } else { - for (i = this.start; index < length && i < 64; ++index) { - blocks[i >> 2] |= message[index] << SHIFT[i++ & 3]; - } - } - } else { - if (ARRAY_BUFFER) { - for (i = this.start; index < length && i < 64; ++index) { - code = message.charCodeAt(index); - if (code < 0x80) { - buffer8[i++] = code; - } else if (code < 0x800) { - buffer8[i++] = 0xc0 | (code >> 6); - buffer8[i++] = 0x80 | (code & 0x3f); - } else if (code < 0xd800 || code >= 0xe000) { - buffer8[i++] = 0xe0 | (code >> 12); - buffer8[i++] = 0x80 | ((code >> 6) & 0x3f); - buffer8[i++] = 0x80 | (code & 0x3f); - } else { - code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff)); - buffer8[i++] = 0xf0 | (code >> 18); - buffer8[i++] = 0x80 | ((code >> 12) & 0x3f); - buffer8[i++] = 0x80 | ((code >> 6) & 0x3f); - buffer8[i++] = 0x80 | (code & 0x3f); - } - } - } else { - for (i = this.start; index < length && i < 64; ++index) { - code = message.charCodeAt(index); - if (code < 0x80) { - blocks[i >> 2] |= code << SHIFT[i++ & 3]; - } else if (code < 0x800) { - blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3]; - blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; - } else if (code < 0xd800 || code >= 0xe000) { - blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3]; - blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; - blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; - } else { - code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff)); - blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3]; - blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3]; - blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; - blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; - } - } - } - } - this.lastByteIndex = i; - this.bytes += i - this.start; - if (i >= 64) { - this.start = i - 64; - this.hash(); - this.hashed = true; - } else { - this.start = i; - } - } - if (this.bytes > 4294967295) { - this.hBytes += this.bytes / 4294967296 << 0; - this.bytes = this.bytes % 4294967296; - } - return this; - }; - - Md5.prototype.finalize = function () { - if (this.finalized) { - return; - } - this.finalized = true; - var blocks = this.blocks, i = this.lastByteIndex; - blocks[i >> 2] |= EXTRA[i & 3]; - if (i >= 56) { - if (!this.hashed) { - this.hash(); - } - blocks[0] = blocks[16]; - blocks[16] = blocks[1] = blocks[2] = blocks[3] = - blocks[4] = blocks[5] = blocks[6] = blocks[7] = - blocks[8] = blocks[9] = blocks[10] = blocks[11] = - blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; - } - blocks[14] = this.bytes << 3; - blocks[15] = this.hBytes << 3 | this.bytes >>> 29; - this.hash(); - }; - - Md5.prototype.hash = function () { - var a, b, c, d, bc, da, blocks = this.blocks; - - if (this.first) { - a = blocks[0] - 680876937; - a = (a << 7 | a >>> 25) - 271733879 << 0; - d = (-1732584194 ^ a & 2004318071) + blocks[1] - 117830708; - d = (d << 12 | d >>> 20) + a << 0; - c = (-271733879 ^ (d & (a ^ -271733879))) + blocks[2] - 1126478375; - c = (c << 17 | c >>> 15) + d << 0; - b = (a ^ (c & (d ^ a))) + blocks[3] - 1316259209; - b = (b << 22 | b >>> 10) + c << 0; - } else { - a = this.h0; - b = this.h1; - c = this.h2; - d = this.h3; - a += (d ^ (b & (c ^ d))) + blocks[0] - 680876936; - a = (a << 7 | a >>> 25) + b << 0; - d += (c ^ (a & (b ^ c))) + blocks[1] - 389564586; - d = (d << 12 | d >>> 20) + a << 0; - c += (b ^ (d & (a ^ b))) + blocks[2] + 606105819; - c = (c << 17 | c >>> 15) + d << 0; - b += (a ^ (c & (d ^ a))) + blocks[3] - 1044525330; - b = (b << 22 | b >>> 10) + c << 0; - } - - a += (d ^ (b & (c ^ d))) + blocks[4] - 176418897; - a = (a << 7 | a >>> 25) + b << 0; - d += (c ^ (a & (b ^ c))) + blocks[5] + 1200080426; - d = (d << 12 | d >>> 20) + a << 0; - c += (b ^ (d & (a ^ b))) + blocks[6] - 1473231341; - c = (c << 17 | c >>> 15) + d << 0; - b += (a ^ (c & (d ^ a))) + blocks[7] - 45705983; - b = (b << 22 | b >>> 10) + c << 0; - a += (d ^ (b & (c ^ d))) + blocks[8] + 1770035416; - a = (a << 7 | a >>> 25) + b << 0; - d += (c ^ (a & (b ^ c))) + blocks[9] - 1958414417; - d = (d << 12 | d >>> 20) + a << 0; - c += (b ^ (d & (a ^ b))) + blocks[10] - 42063; - c = (c << 17 | c >>> 15) + d << 0; - b += (a ^ (c & (d ^ a))) + blocks[11] - 1990404162; - b = (b << 22 | b >>> 10) + c << 0; - a += (d ^ (b & (c ^ d))) + blocks[12] + 1804603682; - a = (a << 7 | a >>> 25) + b << 0; - d += (c ^ (a & (b ^ c))) + blocks[13] - 40341101; - d = (d << 12 | d >>> 20) + a << 0; - c += (b ^ (d & (a ^ b))) + blocks[14] - 1502002290; - c = (c << 17 | c >>> 15) + d << 0; - b += (a ^ (c & (d ^ a))) + blocks[15] + 1236535329; - b = (b << 22 | b >>> 10) + c << 0; - a += (c ^ (d & (b ^ c))) + blocks[1] - 165796510; - a = (a << 5 | a >>> 27) + b << 0; - d += (b ^ (c & (a ^ b))) + blocks[6] - 1069501632; - d = (d << 9 | d >>> 23) + a << 0; - c += (a ^ (b & (d ^ a))) + blocks[11] + 643717713; - c = (c << 14 | c >>> 18) + d << 0; - b += (d ^ (a & (c ^ d))) + blocks[0] - 373897302; - b = (b << 20 | b >>> 12) + c << 0; - a += (c ^ (d & (b ^ c))) + blocks[5] - 701558691; - a = (a << 5 | a >>> 27) + b << 0; - d += (b ^ (c & (a ^ b))) + blocks[10] + 38016083; - d = (d << 9 | d >>> 23) + a << 0; - c += (a ^ (b & (d ^ a))) + blocks[15] - 660478335; - c = (c << 14 | c >>> 18) + d << 0; - b += (d ^ (a & (c ^ d))) + blocks[4] - 405537848; - b = (b << 20 | b >>> 12) + c << 0; - a += (c ^ (d & (b ^ c))) + blocks[9] + 568446438; - a = (a << 5 | a >>> 27) + b << 0; - d += (b ^ (c & (a ^ b))) + blocks[14] - 1019803690; - d = (d << 9 | d >>> 23) + a << 0; - c += (a ^ (b & (d ^ a))) + blocks[3] - 187363961; - c = (c << 14 | c >>> 18) + d << 0; - b += (d ^ (a & (c ^ d))) + blocks[8] + 1163531501; - b = (b << 20 | b >>> 12) + c << 0; - a += (c ^ (d & (b ^ c))) + blocks[13] - 1444681467; - a = (a << 5 | a >>> 27) + b << 0; - d += (b ^ (c & (a ^ b))) + blocks[2] - 51403784; - d = (d << 9 | d >>> 23) + a << 0; - c += (a ^ (b & (d ^ a))) + blocks[7] + 1735328473; - c = (c << 14 | c >>> 18) + d << 0; - b += (d ^ (a & (c ^ d))) + blocks[12] - 1926607734; - b = (b << 20 | b >>> 12) + c << 0; - bc = b ^ c; - a += (bc ^ d) + blocks[5] - 378558; - a = (a << 4 | a >>> 28) + b << 0; - d += (bc ^ a) + blocks[8] - 2022574463; - d = (d << 11 | d >>> 21) + a << 0; - da = d ^ a; - c += (da ^ b) + blocks[11] + 1839030562; - c = (c << 16 | c >>> 16) + d << 0; - b += (da ^ c) + blocks[14] - 35309556; - b = (b << 23 | b >>> 9) + c << 0; - bc = b ^ c; - a += (bc ^ d) + blocks[1] - 1530992060; - a = (a << 4 | a >>> 28) + b << 0; - d += (bc ^ a) + blocks[4] + 1272893353; - d = (d << 11 | d >>> 21) + a << 0; - da = d ^ a; - c += (da ^ b) + blocks[7] - 155497632; - c = (c << 16 | c >>> 16) + d << 0; - b += (da ^ c) + blocks[10] - 1094730640; - b = (b << 23 | b >>> 9) + c << 0; - bc = b ^ c; - a += (bc ^ d) + blocks[13] + 681279174; - a = (a << 4 | a >>> 28) + b << 0; - d += (bc ^ a) + blocks[0] - 358537222; - d = (d << 11 | d >>> 21) + a << 0; - da = d ^ a; - c += (da ^ b) + blocks[3] - 722521979; - c = (c << 16 | c >>> 16) + d << 0; - b += (da ^ c) + blocks[6] + 76029189; - b = (b << 23 | b >>> 9) + c << 0; - bc = b ^ c; - a += (bc ^ d) + blocks[9] - 640364487; - a = (a << 4 | a >>> 28) + b << 0; - d += (bc ^ a) + blocks[12] - 421815835; - d = (d << 11 | d >>> 21) + a << 0; - da = d ^ a; - c += (da ^ b) + blocks[15] + 530742520; - c = (c << 16 | c >>> 16) + d << 0; - b += (da ^ c) + blocks[2] - 995338651; - b = (b << 23 | b >>> 9) + c << 0; - a += (c ^ (b | ~d)) + blocks[0] - 198630844; - a = (a << 6 | a >>> 26) + b << 0; - d += (b ^ (a | ~c)) + blocks[7] + 1126891415; - d = (d << 10 | d >>> 22) + a << 0; - c += (a ^ (d | ~b)) + blocks[14] - 1416354905; - c = (c << 15 | c >>> 17) + d << 0; - b += (d ^ (c | ~a)) + blocks[5] - 57434055; - b = (b << 21 | b >>> 11) + c << 0; - a += (c ^ (b | ~d)) + blocks[12] + 1700485571; - a = (a << 6 | a >>> 26) + b << 0; - d += (b ^ (a | ~c)) + blocks[3] - 1894986606; - d = (d << 10 | d >>> 22) + a << 0; - c += (a ^ (d | ~b)) + blocks[10] - 1051523; - c = (c << 15 | c >>> 17) + d << 0; - b += (d ^ (c | ~a)) + blocks[1] - 2054922799; - b = (b << 21 | b >>> 11) + c << 0; - a += (c ^ (b | ~d)) + blocks[8] + 1873313359; - a = (a << 6 | a >>> 26) + b << 0; - d += (b ^ (a | ~c)) + blocks[15] - 30611744; - d = (d << 10 | d >>> 22) + a << 0; - c += (a ^ (d | ~b)) + blocks[6] - 1560198380; - c = (c << 15 | c >>> 17) + d << 0; - b += (d ^ (c | ~a)) + blocks[13] + 1309151649; - b = (b << 21 | b >>> 11) + c << 0; - a += (c ^ (b | ~d)) + blocks[4] - 145523070; - a = (a << 6 | a >>> 26) + b << 0; - d += (b ^ (a | ~c)) + blocks[11] - 1120210379; - d = (d << 10 | d >>> 22) + a << 0; - c += (a ^ (d | ~b)) + blocks[2] + 718787259; - c = (c << 15 | c >>> 17) + d << 0; - b += (d ^ (c | ~a)) + blocks[9] - 343485551; - b = (b << 21 | b >>> 11) + c << 0; - - if (this.first) { - this.h0 = a + 1732584193 << 0; - this.h1 = b - 271733879 << 0; - this.h2 = c - 1732584194 << 0; - this.h3 = d + 271733878 << 0; - this.first = false; - } else { - this.h0 = this.h0 + a << 0; - this.h1 = this.h1 + b << 0; - this.h2 = this.h2 + c << 0; - this.h3 = this.h3 + d << 0; - } - }; - - /** - * @method hex - * @memberof Md5 - * @instance - * @description Output hash as hex string - * @returns {String} Hex string - * @see {@link md5.hex} - * @example - * hash.hex(); - */ - Md5.prototype.hex = function () { - this.finalize(); - - var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3; - - return HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] + - HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] + - HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] + - HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] + - HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] + - HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] + - HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] + - HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] + - HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] + - HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] + - HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] + - HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] + - HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] + - HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] + - HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] + - HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F]; - }; - - /** - * @method toString - * @memberof Md5 - * @instance - * @description Output hash as hex string - * @returns {String} Hex string - * @see {@link md5.hex} - * @example - * hash.toString(); - */ - Md5.prototype.toString = Md5.prototype.hex; - - /** - * @method digest - * @memberof Md5 - * @instance - * @description Output hash as bytes array - * @returns {Array} Bytes array - * @see {@link md5.digest} - * @example - * hash.digest(); - */ - Md5.prototype.digest = function () { - this.finalize(); - - var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3; - return [ - h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 24) & 0xFF, - h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 24) & 0xFF, - h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 24) & 0xFF, - h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 24) & 0xFF - ]; - }; - - /** - * @method array - * @memberof Md5 - * @instance - * @description Output hash as bytes array - * @returns {Array} Bytes array - * @see {@link md5.array} - * @example - * hash.array(); - */ - Md5.prototype.array = Md5.prototype.digest; - - /** - * @method arrayBuffer - * @memberof Md5 - * @instance - * @description Output hash as ArrayBuffer - * @returns {ArrayBuffer} ArrayBuffer - * @see {@link md5.arrayBuffer} - * @example - * hash.arrayBuffer(); - */ - Md5.prototype.arrayBuffer = function () { - this.finalize(); - - var buffer = new ArrayBuffer(16); - var blocks = new Uint32Array(buffer); - blocks[0] = this.h0; - blocks[1] = this.h1; - blocks[2] = this.h2; - blocks[3] = this.h3; - return buffer; - }; - - /** - * @method buffer - * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead. - * @memberof Md5 - * @instance - * @description Output hash as ArrayBuffer - * @returns {ArrayBuffer} ArrayBuffer - * @see {@link md5.buffer} - * @example - * hash.buffer(); - */ - Md5.prototype.buffer = Md5.prototype.arrayBuffer; - - /** - * @method base64 - * @memberof Md5 - * @instance - * @description Output hash as base64 string - * @returns {String} base64 string - * @see {@link md5.base64} - * @example - * hash.base64(); - */ - Md5.prototype.base64 = function () { - var v1, v2, v3, base64Str = '', bytes = this.array(); - for (var i = 0; i < 15;) { - v1 = bytes[i++]; - v2 = bytes[i++]; - v3 = bytes[i++]; - base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] + - BASE64_ENCODE_CHAR[(v1 << 4 | v2 >>> 4) & 63] + - BASE64_ENCODE_CHAR[(v2 << 2 | v3 >>> 6) & 63] + - BASE64_ENCODE_CHAR[v3 & 63]; - } - v1 = bytes[i]; - base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] + - BASE64_ENCODE_CHAR[(v1 << 4) & 63] + - '=='; - return base64Str; - }; - - var exports = createMethod(); - - if (COMMON_JS) { - module.exports = exports; - } else { - /** - * @method md5 - * @description Md5 hash function, export to global in browsers. - * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash - * @returns {String} md5 hashes - * @example - * md5(''); // d41d8cd98f00b204e9800998ecf8427e - * md5('The quick brown fox jumps over the lazy dog'); // 9e107d9d372bb6826bd81d3542a419d6 - * md5('The quick brown fox jumps over the lazy dog.'); // e4d909c290d0fb1ca068ffaddf22cbd0 - * - * // It also supports UTF-8 encoding - * md5('中文'); // a7bac2239fcdcb3a067903d8077c4a07 - * - * // It also supports byte `Array`, `Uint8Array`, `ArrayBuffer` - * md5([]); // d41d8cd98f00b204e9800998ecf8427e - * md5(new Uint8Array([])); // d41d8cd98f00b204e9800998ecf8427e - */ - root.md5 = exports; - if (AMD) { - !(__WEBPACK_AMD_DEFINE_RESULT__ = (function () { - return exports; +/* WEBPACK VAR INJECTION */(function(process, global) {var __WEBPACK_AMD_DEFINE_RESULT__;/* https://github.com/emn178/js-md5 */ +(function () { + 'use strict'; + + var ERROR = 'input is invalid type'; + var WINDOW = typeof window === 'object'; + var root = WINDOW ? window : {}; + if (root.JS_MD5_NO_WINDOW) { + WINDOW = false; + } + var WEB_WORKER = !WINDOW && typeof self === 'object'; + var NODE_JS = !root.JS_MD5_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node; + if (NODE_JS) { + root = global; + } else if (WEB_WORKER) { + root = self; + } + var COMMON_JS = !root.JS_MD5_NO_COMMON_JS && typeof module === 'object' && module.exports; + var AMD = "function" === 'function' && __webpack_require__(10); + var ARRAY_BUFFER = !root.JS_MD5_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined'; + var HEX_CHARS = '0123456789abcdef'.split(''); + var EXTRA = [128, 32768, 8388608, -2147483648]; + var SHIFT = [0, 8, 16, 24]; + var OUTPUT_TYPES = ['hex', 'array', 'digest', 'buffer', 'arrayBuffer', 'base64']; + var BASE64_ENCODE_CHAR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split(''); + + var blocks = [], buffer8; + if (ARRAY_BUFFER) { + var buffer = new ArrayBuffer(68); + buffer8 = new Uint8Array(buffer); + blocks = new Uint32Array(buffer); + } + + if (root.JS_MD5_NO_NODE_JS || !Array.isArray) { + Array.isArray = function (obj) { + return Object.prototype.toString.call(obj) === '[object Array]'; + }; + } + + if (ARRAY_BUFFER && (root.JS_MD5_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) { + ArrayBuffer.isView = function (obj) { + return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer; + }; + } + + /** + * @method hex + * @memberof md5 + * @description Output hash as hex string + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {String} Hex string + * @example + * md5.hex('The quick brown fox jumps over the lazy dog'); + * // equal to + * md5('The quick brown fox jumps over the lazy dog'); + */ + /** + * @method digest + * @memberof md5 + * @description Output hash as bytes array + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {Array} Bytes array + * @example + * md5.digest('The quick brown fox jumps over the lazy dog'); + */ + /** + * @method array + * @memberof md5 + * @description Output hash as bytes array + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {Array} Bytes array + * @example + * md5.array('The quick brown fox jumps over the lazy dog'); + */ + /** + * @method arrayBuffer + * @memberof md5 + * @description Output hash as ArrayBuffer + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {ArrayBuffer} ArrayBuffer + * @example + * md5.arrayBuffer('The quick brown fox jumps over the lazy dog'); + */ + /** + * @method buffer + * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead. + * @memberof md5 + * @description Output hash as ArrayBuffer + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {ArrayBuffer} ArrayBuffer + * @example + * md5.buffer('The quick brown fox jumps over the lazy dog'); + */ + /** + * @method base64 + * @memberof md5 + * @description Output hash as base64 string + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {String} base64 string + * @example + * md5.base64('The quick brown fox jumps over the lazy dog'); + */ + var createOutputMethod = function (outputType) { + return function (message) { + return new Md5(true).update(message)[outputType](); + }; + }; + + /** + * @method create + * @memberof md5 + * @description Create Md5 object + * @returns {Md5} Md5 object. + * @example + * var hash = md5.create(); + */ + /** + * @method update + * @memberof md5 + * @description Create and update Md5 object + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {Md5} Md5 object. + * @example + * var hash = md5.update('The quick brown fox jumps over the lazy dog'); + * // equal to + * var hash = md5.create(); + * hash.update('The quick brown fox jumps over the lazy dog'); + */ + var createMethod = function () { + var method = createOutputMethod('hex'); + if (NODE_JS) { + method = nodeWrap(method); + } + method.getCtx = method.create = function () { + return new Md5(); + }; + method.update = function (message) { + return method.create().update(message); + }; + for (var i = 0; i < OUTPUT_TYPES.length; ++i) { + var type = OUTPUT_TYPES[i]; + method[type] = createOutputMethod(type); + } + return method; + }; + + var nodeWrap = function (method) { + var crypto = eval("require('crypto')"); + var Buffer = eval("require('buffer').Buffer"); + var nodeMethod = function (message) { + if (typeof message === 'string') { + return crypto.createHash('md5').update(message, 'utf8').digest('hex'); + } else { + if (message === null || message === undefined) { + throw ERROR; + } else if (message.constructor === ArrayBuffer) { + message = new Uint8Array(message); + } + } + if (Array.isArray(message) || ArrayBuffer.isView(message) || + message.constructor === Buffer) { + return crypto.createHash('md5').update(new Buffer(message)).digest('hex'); + } else { + return method(message); + } + }; + return nodeMethod; + }; + + /** + * Md5 class + * @class Md5 + * @description This is internal class. + * @see {@link md5.create} + */ + function Md5(sharedMemory) { + if (sharedMemory) { + blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] = + blocks[4] = blocks[5] = blocks[6] = blocks[7] = + blocks[8] = blocks[9] = blocks[10] = blocks[11] = + blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; + this.blocks = blocks; + this.buffer8 = buffer8; + } else { + if (ARRAY_BUFFER) { + var buffer = new ArrayBuffer(68); + this.buffer8 = new Uint8Array(buffer); + this.blocks = new Uint32Array(buffer); + } else { + this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + } + } + this.h0 = this.h1 = this.h2 = this.h3 = this.start = this.bytes = this.hBytes = 0; + this.finalized = this.hashed = false; + this.first = true; + } + + /** + * @method update + * @memberof Md5 + * @instance + * @description Update hash + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {Md5} Md5 object. + * @see {@link md5.update} + */ + Md5.prototype.update = function (message) { + if (this.finalized) { + return; + } + + var notString, type = typeof message; + if (type !== 'string') { + if (type === 'object') { + if (message === null) { + throw ERROR; + } else if (ARRAY_BUFFER && (message.constructor === ArrayBuffer || message.constructor.name === 'ArrayBuffer')) { + message = new Uint8Array(message); + } else if (!Array.isArray(message)) { + if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) { + throw ERROR; + } + } + } else { + throw ERROR; + } + notString = true; + } + var code, index = 0, i, length = message.length, blocks = this.blocks; + var buffer8 = this.buffer8; + + while (index < length) { + if (this.hashed) { + this.hashed = false; + blocks[0] = blocks[16]; + blocks[16] = blocks[1] = blocks[2] = blocks[3] = + blocks[4] = blocks[5] = blocks[6] = blocks[7] = + blocks[8] = blocks[9] = blocks[10] = blocks[11] = + blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; + } + + if (notString) { + if (ARRAY_BUFFER) { + for (i = this.start; index < length && i < 64; ++index) { + buffer8[i++] = message[index]; + } + } else { + for (i = this.start; index < length && i < 64; ++index) { + blocks[i >> 2] |= message[index] << SHIFT[i++ & 3]; + } + } + } else { + if (ARRAY_BUFFER) { + for (i = this.start; index < length && i < 64; ++index) { + code = message.charCodeAt(index); + if (code < 0x80) { + buffer8[i++] = code; + } else if (code < 0x800) { + buffer8[i++] = 0xc0 | (code >> 6); + buffer8[i++] = 0x80 | (code & 0x3f); + } else if (code < 0xd800 || code >= 0xe000) { + buffer8[i++] = 0xe0 | (code >> 12); + buffer8[i++] = 0x80 | ((code >> 6) & 0x3f); + buffer8[i++] = 0x80 | (code & 0x3f); + } else { + code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff)); + buffer8[i++] = 0xf0 | (code >> 18); + buffer8[i++] = 0x80 | ((code >> 12) & 0x3f); + buffer8[i++] = 0x80 | ((code >> 6) & 0x3f); + buffer8[i++] = 0x80 | (code & 0x3f); + } + } + } else { + for (i = this.start; index < length && i < 64; ++index) { + code = message.charCodeAt(index); + if (code < 0x80) { + blocks[i >> 2] |= code << SHIFT[i++ & 3]; + } else if (code < 0x800) { + blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; + } else if (code < 0xd800 || code >= 0xe000) { + blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; + } else { + code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff)); + blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; + } + } + } + } + this.lastByteIndex = i; + this.bytes += i - this.start; + if (i >= 64) { + this.start = i - 64; + this.hash(); + this.hashed = true; + } else { + this.start = i; + } + } + if (this.bytes > 4294967295) { + this.hBytes += this.bytes / 4294967296 << 0; + this.bytes = this.bytes % 4294967296; + } + return this; + }; + + Md5.prototype.finalize = function () { + if (this.finalized) { + return; + } + this.finalized = true; + var blocks = this.blocks, i = this.lastByteIndex; + blocks[i >> 2] |= EXTRA[i & 3]; + if (i >= 56) { + if (!this.hashed) { + this.hash(); + } + blocks[0] = blocks[16]; + blocks[16] = blocks[1] = blocks[2] = blocks[3] = + blocks[4] = blocks[5] = blocks[6] = blocks[7] = + blocks[8] = blocks[9] = blocks[10] = blocks[11] = + blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; + } + blocks[14] = this.bytes << 3; + blocks[15] = this.hBytes << 3 | this.bytes >>> 29; + this.hash(); + }; + + Md5.prototype.hash = function () { + var a, b, c, d, bc, da, blocks = this.blocks; + + if (this.first) { + a = blocks[0] - 680876937; + a = (a << 7 | a >>> 25) - 271733879 << 0; + d = (-1732584194 ^ a & 2004318071) + blocks[1] - 117830708; + d = (d << 12 | d >>> 20) + a << 0; + c = (-271733879 ^ (d & (a ^ -271733879))) + blocks[2] - 1126478375; + c = (c << 17 | c >>> 15) + d << 0; + b = (a ^ (c & (d ^ a))) + blocks[3] - 1316259209; + b = (b << 22 | b >>> 10) + c << 0; + } else { + a = this.h0; + b = this.h1; + c = this.h2; + d = this.h3; + a += (d ^ (b & (c ^ d))) + blocks[0] - 680876936; + a = (a << 7 | a >>> 25) + b << 0; + d += (c ^ (a & (b ^ c))) + blocks[1] - 389564586; + d = (d << 12 | d >>> 20) + a << 0; + c += (b ^ (d & (a ^ b))) + blocks[2] + 606105819; + c = (c << 17 | c >>> 15) + d << 0; + b += (a ^ (c & (d ^ a))) + blocks[3] - 1044525330; + b = (b << 22 | b >>> 10) + c << 0; + } + + a += (d ^ (b & (c ^ d))) + blocks[4] - 176418897; + a = (a << 7 | a >>> 25) + b << 0; + d += (c ^ (a & (b ^ c))) + blocks[5] + 1200080426; + d = (d << 12 | d >>> 20) + a << 0; + c += (b ^ (d & (a ^ b))) + blocks[6] - 1473231341; + c = (c << 17 | c >>> 15) + d << 0; + b += (a ^ (c & (d ^ a))) + blocks[7] - 45705983; + b = (b << 22 | b >>> 10) + c << 0; + a += (d ^ (b & (c ^ d))) + blocks[8] + 1770035416; + a = (a << 7 | a >>> 25) + b << 0; + d += (c ^ (a & (b ^ c))) + blocks[9] - 1958414417; + d = (d << 12 | d >>> 20) + a << 0; + c += (b ^ (d & (a ^ b))) + blocks[10] - 42063; + c = (c << 17 | c >>> 15) + d << 0; + b += (a ^ (c & (d ^ a))) + blocks[11] - 1990404162; + b = (b << 22 | b >>> 10) + c << 0; + a += (d ^ (b & (c ^ d))) + blocks[12] + 1804603682; + a = (a << 7 | a >>> 25) + b << 0; + d += (c ^ (a & (b ^ c))) + blocks[13] - 40341101; + d = (d << 12 | d >>> 20) + a << 0; + c += (b ^ (d & (a ^ b))) + blocks[14] - 1502002290; + c = (c << 17 | c >>> 15) + d << 0; + b += (a ^ (c & (d ^ a))) + blocks[15] + 1236535329; + b = (b << 22 | b >>> 10) + c << 0; + a += (c ^ (d & (b ^ c))) + blocks[1] - 165796510; + a = (a << 5 | a >>> 27) + b << 0; + d += (b ^ (c & (a ^ b))) + blocks[6] - 1069501632; + d = (d << 9 | d >>> 23) + a << 0; + c += (a ^ (b & (d ^ a))) + blocks[11] + 643717713; + c = (c << 14 | c >>> 18) + d << 0; + b += (d ^ (a & (c ^ d))) + blocks[0] - 373897302; + b = (b << 20 | b >>> 12) + c << 0; + a += (c ^ (d & (b ^ c))) + blocks[5] - 701558691; + a = (a << 5 | a >>> 27) + b << 0; + d += (b ^ (c & (a ^ b))) + blocks[10] + 38016083; + d = (d << 9 | d >>> 23) + a << 0; + c += (a ^ (b & (d ^ a))) + blocks[15] - 660478335; + c = (c << 14 | c >>> 18) + d << 0; + b += (d ^ (a & (c ^ d))) + blocks[4] - 405537848; + b = (b << 20 | b >>> 12) + c << 0; + a += (c ^ (d & (b ^ c))) + blocks[9] + 568446438; + a = (a << 5 | a >>> 27) + b << 0; + d += (b ^ (c & (a ^ b))) + blocks[14] - 1019803690; + d = (d << 9 | d >>> 23) + a << 0; + c += (a ^ (b & (d ^ a))) + blocks[3] - 187363961; + c = (c << 14 | c >>> 18) + d << 0; + b += (d ^ (a & (c ^ d))) + blocks[8] + 1163531501; + b = (b << 20 | b >>> 12) + c << 0; + a += (c ^ (d & (b ^ c))) + blocks[13] - 1444681467; + a = (a << 5 | a >>> 27) + b << 0; + d += (b ^ (c & (a ^ b))) + blocks[2] - 51403784; + d = (d << 9 | d >>> 23) + a << 0; + c += (a ^ (b & (d ^ a))) + blocks[7] + 1735328473; + c = (c << 14 | c >>> 18) + d << 0; + b += (d ^ (a & (c ^ d))) + blocks[12] - 1926607734; + b = (b << 20 | b >>> 12) + c << 0; + bc = b ^ c; + a += (bc ^ d) + blocks[5] - 378558; + a = (a << 4 | a >>> 28) + b << 0; + d += (bc ^ a) + blocks[8] - 2022574463; + d = (d << 11 | d >>> 21) + a << 0; + da = d ^ a; + c += (da ^ b) + blocks[11] + 1839030562; + c = (c << 16 | c >>> 16) + d << 0; + b += (da ^ c) + blocks[14] - 35309556; + b = (b << 23 | b >>> 9) + c << 0; + bc = b ^ c; + a += (bc ^ d) + blocks[1] - 1530992060; + a = (a << 4 | a >>> 28) + b << 0; + d += (bc ^ a) + blocks[4] + 1272893353; + d = (d << 11 | d >>> 21) + a << 0; + da = d ^ a; + c += (da ^ b) + blocks[7] - 155497632; + c = (c << 16 | c >>> 16) + d << 0; + b += (da ^ c) + blocks[10] - 1094730640; + b = (b << 23 | b >>> 9) + c << 0; + bc = b ^ c; + a += (bc ^ d) + blocks[13] + 681279174; + a = (a << 4 | a >>> 28) + b << 0; + d += (bc ^ a) + blocks[0] - 358537222; + d = (d << 11 | d >>> 21) + a << 0; + da = d ^ a; + c += (da ^ b) + blocks[3] - 722521979; + c = (c << 16 | c >>> 16) + d << 0; + b += (da ^ c) + blocks[6] + 76029189; + b = (b << 23 | b >>> 9) + c << 0; + bc = b ^ c; + a += (bc ^ d) + blocks[9] - 640364487; + a = (a << 4 | a >>> 28) + b << 0; + d += (bc ^ a) + blocks[12] - 421815835; + d = (d << 11 | d >>> 21) + a << 0; + da = d ^ a; + c += (da ^ b) + blocks[15] + 530742520; + c = (c << 16 | c >>> 16) + d << 0; + b += (da ^ c) + blocks[2] - 995338651; + b = (b << 23 | b >>> 9) + c << 0; + a += (c ^ (b | ~d)) + blocks[0] - 198630844; + a = (a << 6 | a >>> 26) + b << 0; + d += (b ^ (a | ~c)) + blocks[7] + 1126891415; + d = (d << 10 | d >>> 22) + a << 0; + c += (a ^ (d | ~b)) + blocks[14] - 1416354905; + c = (c << 15 | c >>> 17) + d << 0; + b += (d ^ (c | ~a)) + blocks[5] - 57434055; + b = (b << 21 | b >>> 11) + c << 0; + a += (c ^ (b | ~d)) + blocks[12] + 1700485571; + a = (a << 6 | a >>> 26) + b << 0; + d += (b ^ (a | ~c)) + blocks[3] - 1894986606; + d = (d << 10 | d >>> 22) + a << 0; + c += (a ^ (d | ~b)) + blocks[10] - 1051523; + c = (c << 15 | c >>> 17) + d << 0; + b += (d ^ (c | ~a)) + blocks[1] - 2054922799; + b = (b << 21 | b >>> 11) + c << 0; + a += (c ^ (b | ~d)) + blocks[8] + 1873313359; + a = (a << 6 | a >>> 26) + b << 0; + d += (b ^ (a | ~c)) + blocks[15] - 30611744; + d = (d << 10 | d >>> 22) + a << 0; + c += (a ^ (d | ~b)) + blocks[6] - 1560198380; + c = (c << 15 | c >>> 17) + d << 0; + b += (d ^ (c | ~a)) + blocks[13] + 1309151649; + b = (b << 21 | b >>> 11) + c << 0; + a += (c ^ (b | ~d)) + blocks[4] - 145523070; + a = (a << 6 | a >>> 26) + b << 0; + d += (b ^ (a | ~c)) + blocks[11] - 1120210379; + d = (d << 10 | d >>> 22) + a << 0; + c += (a ^ (d | ~b)) + blocks[2] + 718787259; + c = (c << 15 | c >>> 17) + d << 0; + b += (d ^ (c | ~a)) + blocks[9] - 343485551; + b = (b << 21 | b >>> 11) + c << 0; + + if (this.first) { + this.h0 = a + 1732584193 << 0; + this.h1 = b - 271733879 << 0; + this.h2 = c - 1732584194 << 0; + this.h3 = d + 271733878 << 0; + this.first = false; + } else { + this.h0 = this.h0 + a << 0; + this.h1 = this.h1 + b << 0; + this.h2 = this.h2 + c << 0; + this.h3 = this.h3 + d << 0; + } + }; + + /** + * @method hex + * @memberof Md5 + * @instance + * @description Output hash as hex string + * @returns {String} Hex string + * @see {@link md5.hex} + * @example + * hash.hex(); + */ + Md5.prototype.hex = function () { + this.finalize(); + + var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3; + + return HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] + + HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] + + HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] + + HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] + + HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] + + HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] + + HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] + + HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] + + HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] + + HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] + + HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] + + HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] + + HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] + + HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] + + HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] + + HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F]; + }; + + /** + * @method toString + * @memberof Md5 + * @instance + * @description Output hash as hex string + * @returns {String} Hex string + * @see {@link md5.hex} + * @example + * hash.toString(); + */ + Md5.prototype.toString = Md5.prototype.hex; + + /** + * @method digest + * @memberof Md5 + * @instance + * @description Output hash as bytes array + * @returns {Array} Bytes array + * @see {@link md5.digest} + * @example + * hash.digest(); + */ + Md5.prototype.digest = function () { + this.finalize(); + + var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3; + return [ + h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 24) & 0xFF, + h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 24) & 0xFF, + h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 24) & 0xFF, + h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 24) & 0xFF + ]; + }; + + /** + * @method array + * @memberof Md5 + * @instance + * @description Output hash as bytes array + * @returns {Array} Bytes array + * @see {@link md5.array} + * @example + * hash.array(); + */ + Md5.prototype.array = Md5.prototype.digest; + + /** + * @method arrayBuffer + * @memberof Md5 + * @instance + * @description Output hash as ArrayBuffer + * @returns {ArrayBuffer} ArrayBuffer + * @see {@link md5.arrayBuffer} + * @example + * hash.arrayBuffer(); + */ + Md5.prototype.arrayBuffer = function () { + this.finalize(); + + var buffer = new ArrayBuffer(16); + var blocks = new Uint32Array(buffer); + blocks[0] = this.h0; + blocks[1] = this.h1; + blocks[2] = this.h2; + blocks[3] = this.h3; + return buffer; + }; + + /** + * @method buffer + * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead. + * @memberof Md5 + * @instance + * @description Output hash as ArrayBuffer + * @returns {ArrayBuffer} ArrayBuffer + * @see {@link md5.buffer} + * @example + * hash.buffer(); + */ + Md5.prototype.buffer = Md5.prototype.arrayBuffer; + + /** + * @method base64 + * @memberof Md5 + * @instance + * @description Output hash as base64 string + * @returns {String} base64 string + * @see {@link md5.base64} + * @example + * hash.base64(); + */ + Md5.prototype.base64 = function () { + var v1, v2, v3, base64Str = '', bytes = this.array(); + for (var i = 0; i < 15;) { + v1 = bytes[i++]; + v2 = bytes[i++]; + v3 = bytes[i++]; + base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] + + BASE64_ENCODE_CHAR[(v1 << 4 | v2 >>> 4) & 63] + + BASE64_ENCODE_CHAR[(v2 << 2 | v3 >>> 6) & 63] + + BASE64_ENCODE_CHAR[v3 & 63]; + } + v1 = bytes[i]; + base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] + + BASE64_ENCODE_CHAR[(v1 << 4) & 63] + + '=='; + return base64Str; + }; + + var exports = createMethod(); + + if (COMMON_JS) { + module.exports = exports; + } else { + /** + * @method md5 + * @description Md5 hash function, export to global in browsers. + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {String} md5 hashes + * @example + * md5(''); // d41d8cd98f00b204e9800998ecf8427e + * md5('The quick brown fox jumps over the lazy dog'); // 9e107d9d372bb6826bd81d3542a419d6 + * md5('The quick brown fox jumps over the lazy dog.'); // e4d909c290d0fb1ca068ffaddf22cbd0 + * + * // It also supports UTF-8 encoding + * md5('中文'); // a7bac2239fcdcb3a067903d8077c4a07 + * + * // It also supports byte `Array`, `Uint8Array`, `ArrayBuffer` + * md5([]); // d41d8cd98f00b204e9800998ecf8427e + * md5(new Uint8Array([])); // d41d8cd98f00b204e9800998ecf8427e + */ + root.md5 = exports; + if (AMD) { + !(__WEBPACK_AMD_DEFINE_RESULT__ = (function () { + return exports; }).call(exports, __webpack_require__, exports, module), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - } - } -})(); + __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + } + } +})(); /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(9), __webpack_require__(1))) @@ -3229,733 +3229,733 @@ module.exports = __webpack_amd_options__; /* 11 */ /***/ (function(module, exports) { -/* - CryptoJS v3.1.2 - code.google.com/p/crypto-js - (c) 2009-2013 by Jeff Mott. All rights reserved. - code.google.com/p/crypto-js/wiki/License - */ -var CryptoJS=CryptoJS||function(g,l){var e={},d=e.lib={},m=function(){},k=d.Base={extend:function(a){m.prototype=this;var c=new m;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}}, - p=d.WordArray=k.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=l?c:4*a.length},toString:function(a){return(a||n).stringify(this)},concat:function(a){var c=this.words,q=a.words,f=this.sigBytes;a=a.sigBytes;this.clamp();if(f%4)for(var b=0;b>>2]|=(q[b>>>2]>>>24-8*(b%4)&255)<<24-8*((f+b)%4);else if(65535>>2]=q[b>>>2];else c.push.apply(c,q);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<< - 32-8*(c%4);a.length=g.ceil(c/4)},clone:function(){var a=k.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],b=0;b>>2]>>>24-8*(f%4)&255;b.push((d>>>4).toString(16));b.push((d&15).toString(16))}return b.join("")},parse:function(a){for(var c=a.length,b=[],f=0;f>>3]|=parseInt(a.substr(f, - 2),16)<<24-4*(f%8);return new p.init(b,c/2)}},j=b.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var b=[],f=0;f>>2]>>>24-8*(f%4)&255));return b.join("")},parse:function(a){for(var c=a.length,b=[],f=0;f>>2]|=(a.charCodeAt(f)&255)<<24-8*(f%4);return new p.init(b,c)}},h=b.Utf8={stringify:function(a){try{return decodeURIComponent(escape(j.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return j.parse(unescape(encodeURIComponent(a)))}}, - r=d.BufferedBlockAlgorithm=k.extend({reset:function(){this._data=new p.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=h.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,b=c.words,f=c.sigBytes,d=this.blockSize,e=f/(4*d),e=a?g.ceil(e):g.max((e|0)-this._minBufferSize,0);a=e*d;f=g.min(4*a,f);if(a){for(var k=0;ka;a++){if(16>a)m[a]=d[e+a]|0;else{var c=m[a-3]^m[a-8]^m[a-14]^m[a-16];m[a]=c<<1|c>>>31}c=(n<<5|n>>>27)+l+m[a];c=20>a?c+((j&h|~j&g)+1518500249):40>a?c+((j^h^g)+1859775393):60>a?c+((j&h|j&g|h&g)-1894007588):c+((j^h^ -g)-899497514);l=g;g=h;h=j<<30|j>>>2;j=n;n=c}b[0]=b[0]+n|0;b[1]=b[1]+j|0;b[2]=b[2]+h|0;b[3]=b[3]+g|0;b[4]=b[4]+l|0},_doFinalize:function(){var d=this._data,e=d.words,b=8*this._nDataBytes,g=8*d.sigBytes;e[g>>>5]|=128<<24-g%32;e[(g+64>>>9<<4)+14]=Math.floor(b/4294967296);e[(g+64>>>9<<4)+15]=b;d.sigBytes=4*e.length;this._process();return this._hash},clone:function(){var e=d.clone.call(this);e._hash=this._hash.clone();return e}});g.SHA1=d._createHelper(l);g.HmacSHA1=d._createHmacHelper(l)})(); -(function(){var g=CryptoJS,l=g.enc.Utf8;g.algo.HMAC=g.lib.Base.extend({init:function(e,d){e=this._hasher=new e.init;"string"==typeof d&&(d=l.parse(d));var g=e.blockSize,k=4*g;d.sigBytes>k&&(d=e.finalize(d));d.clamp();for(var p=this._oKey=d.clone(),b=this._iKey=d.clone(),n=p.words,j=b.words,h=0;h>> 2] >>> (24 - (i % 4) * 8)) & 0xff; - var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; - var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; - - var triplet = (byte1 << 16) | (byte2 << 8) | byte3; - - for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) { - base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); - } - } - - // Add padding - var paddingChar = map.charAt(64); - if (paddingChar) { - while (base64Chars.length % 4) { - base64Chars.push(paddingChar); - } - } - - return base64Chars.join(''); - }, - - /** - * Converts a Base64 string to a word array. - * - * @param {string} base64Str The Base64 string. - * - * @return {WordArray} The word array. - * - * @static - * - * @example - * - * var wordArray = CryptoJS.enc.Base64.parse(base64String); - */ - parse: function (base64Str) { - // Shortcuts - var base64StrLength = base64Str.length; - var map = this._map; - - // Ignore padding - var paddingChar = map.charAt(64); - if (paddingChar) { - var paddingIndex = base64Str.indexOf(paddingChar); - if (paddingIndex != -1) { - base64StrLength = paddingIndex; - } - } - - // Convert - var words = []; - var nBytes = 0; - for (var i = 0; i < base64StrLength; i++) { - if (i % 4) { - var bits1 = map.indexOf(base64Str.charAt(i - 1)) << ((i % 4) * 2); - var bits2 = map.indexOf(base64Str.charAt(i)) >>> (6 - (i % 4) * 2); - words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8); - nBytes++; - } - } - - return WordArray.create(words, nBytes); - }, - - _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' - }; -}()); - -module.exports = CryptoJS; +/* + CryptoJS v3.1.2 + code.google.com/p/crypto-js + (c) 2009-2013 by Jeff Mott. All rights reserved. + code.google.com/p/crypto-js/wiki/License + */ +var CryptoJS=CryptoJS||function(g,l){var e={},d=e.lib={},m=function(){},k=d.Base={extend:function(a){m.prototype=this;var c=new m;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}}, + p=d.WordArray=k.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=l?c:4*a.length},toString:function(a){return(a||n).stringify(this)},concat:function(a){var c=this.words,q=a.words,f=this.sigBytes;a=a.sigBytes;this.clamp();if(f%4)for(var b=0;b>>2]|=(q[b>>>2]>>>24-8*(b%4)&255)<<24-8*((f+b)%4);else if(65535>>2]=q[b>>>2];else c.push.apply(c,q);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<< + 32-8*(c%4);a.length=g.ceil(c/4)},clone:function(){var a=k.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],b=0;b>>2]>>>24-8*(f%4)&255;b.push((d>>>4).toString(16));b.push((d&15).toString(16))}return b.join("")},parse:function(a){for(var c=a.length,b=[],f=0;f>>3]|=parseInt(a.substr(f, + 2),16)<<24-4*(f%8);return new p.init(b,c/2)}},j=b.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var b=[],f=0;f>>2]>>>24-8*(f%4)&255));return b.join("")},parse:function(a){for(var c=a.length,b=[],f=0;f>>2]|=(a.charCodeAt(f)&255)<<24-8*(f%4);return new p.init(b,c)}},h=b.Utf8={stringify:function(a){try{return decodeURIComponent(escape(j.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return j.parse(unescape(encodeURIComponent(a)))}}, + r=d.BufferedBlockAlgorithm=k.extend({reset:function(){this._data=new p.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=h.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,b=c.words,f=c.sigBytes,d=this.blockSize,e=f/(4*d),e=a?g.ceil(e):g.max((e|0)-this._minBufferSize,0);a=e*d;f=g.min(4*a,f);if(a){for(var k=0;ka;a++){if(16>a)m[a]=d[e+a]|0;else{var c=m[a-3]^m[a-8]^m[a-14]^m[a-16];m[a]=c<<1|c>>>31}c=(n<<5|n>>>27)+l+m[a];c=20>a?c+((j&h|~j&g)+1518500249):40>a?c+((j^h^g)+1859775393):60>a?c+((j&h|j&g|h&g)-1894007588):c+((j^h^ +g)-899497514);l=g;g=h;h=j<<30|j>>>2;j=n;n=c}b[0]=b[0]+n|0;b[1]=b[1]+j|0;b[2]=b[2]+h|0;b[3]=b[3]+g|0;b[4]=b[4]+l|0},_doFinalize:function(){var d=this._data,e=d.words,b=8*this._nDataBytes,g=8*d.sigBytes;e[g>>>5]|=128<<24-g%32;e[(g+64>>>9<<4)+14]=Math.floor(b/4294967296);e[(g+64>>>9<<4)+15]=b;d.sigBytes=4*e.length;this._process();return this._hash},clone:function(){var e=d.clone.call(this);e._hash=this._hash.clone();return e}});g.SHA1=d._createHelper(l);g.HmacSHA1=d._createHmacHelper(l)})(); +(function(){var g=CryptoJS,l=g.enc.Utf8;g.algo.HMAC=g.lib.Base.extend({init:function(e,d){e=this._hasher=new e.init;"string"==typeof d&&(d=l.parse(d));var g=e.blockSize,k=4*g;d.sigBytes>k&&(d=e.finalize(d));d.clamp();for(var p=this._oKey=d.clone(),b=this._iKey=d.clone(),n=p.words,j=b.words,h=0;h>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; + var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; + + var triplet = (byte1 << 16) | (byte2 << 8) | byte3; + + for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) { + base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); + } + } + + // Add padding + var paddingChar = map.charAt(64); + if (paddingChar) { + while (base64Chars.length % 4) { + base64Chars.push(paddingChar); + } + } + + return base64Chars.join(''); + }, + + /** + * Converts a Base64 string to a word array. + * + * @param {string} base64Str The Base64 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Base64.parse(base64String); + */ + parse: function (base64Str) { + // Shortcuts + var base64StrLength = base64Str.length; + var map = this._map; + + // Ignore padding + var paddingChar = map.charAt(64); + if (paddingChar) { + var paddingIndex = base64Str.indexOf(paddingChar); + if (paddingIndex != -1) { + base64StrLength = paddingIndex; + } + } + + // Convert + var words = []; + var nBytes = 0; + for (var i = 0; i < base64StrLength; i++) { + if (i % 4) { + var bits1 = map.indexOf(base64Str.charAt(i - 1)) << ((i % 4) * 2); + var bits2 = map.indexOf(base64Str.charAt(i)) >>> (6 - (i % 4) * 2); + words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8); + nBytes++; + } + } + + return WordArray.create(words, nBytes); + }, + + _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' + }; +}()); + +module.exports = CryptoJS; /***/ }), /* 12 */ /***/ (function(module, exports, __webpack_require__) { -/* - Copyright 2011-2013 Abdulla Abdurakhmanov - Original sources are available at https://code.google.com/p/x2js/ - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ -var DOMParser = __webpack_require__(13).DOMParser; - -var x2js = function (config) { - 'use strict'; - - var VERSION = "1.2.0"; - - config = config || {}; - initConfigDefaults(); - initRequiredPolyfills(); - - function initConfigDefaults() { - if(config.escapeMode === undefined) { - config.escapeMode = true; - } - - config.attributePrefix = config.attributePrefix || "_"; - config.arrayAccessForm = config.arrayAccessForm || "none"; - config.emptyNodeForm = config.emptyNodeForm || "text"; - - if(config.enableToStringFunc === undefined) { - config.enableToStringFunc = true; - } - config.arrayAccessFormPaths = config.arrayAccessFormPaths || []; - if(config.skipEmptyTextNodesForObj === undefined) { - config.skipEmptyTextNodesForObj = true; - } - if(config.stripWhitespaces === undefined) { - config.stripWhitespaces = true; - } - config.datetimeAccessFormPaths = config.datetimeAccessFormPaths || []; - - if(config.useDoubleQuotes === undefined) { - config.useDoubleQuotes = false; - } - - config.xmlElementsFilter = config.xmlElementsFilter || []; - config.jsonPropertiesFilter = config.jsonPropertiesFilter || []; - - if(config.keepCData === undefined) { - config.keepCData = false; - } - } - - var DOMNodeTypes = { - ELEMENT_NODE : 1, - TEXT_NODE : 3, - CDATA_SECTION_NODE : 4, - COMMENT_NODE : 8, - DOCUMENT_NODE : 9 - }; - - function initRequiredPolyfills() { - } - - function getNodeLocalName( node ) { - var nodeLocalName = node.localName; - if(nodeLocalName == null) // Yeah, this is IE!! - nodeLocalName = node.baseName; - if(nodeLocalName == null || nodeLocalName=="") // =="" is IE too - nodeLocalName = node.nodeName; - return nodeLocalName; - } - - function getNodePrefix(node) { - return node.prefix; - } - - function escapeXmlChars(str) { - if(typeof(str) == "string") - return str.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, '''); - else - return str; - } - - function unescapeXmlChars(str) { - return str.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, '&'); - } - - function checkInStdFiltersArrayForm(stdFiltersArrayForm, obj, name, path) { - var idx = 0; - for(; idx < stdFiltersArrayForm.length; idx++) { - var filterPath = stdFiltersArrayForm[idx]; - if( typeof filterPath === "string" ) { - if(filterPath == path) - break; - } - else - if( filterPath instanceof RegExp) { - if(filterPath.test(path)) - break; - } - else - if( typeof filterPath === "function") { - if(filterPath(obj, name, path)) - break; - } - } - return idx!=stdFiltersArrayForm.length; - } - - function toArrayAccessForm(obj, childName, path) { - switch(config.arrayAccessForm) { - case "property": - if(!(obj[childName] instanceof Array)) - obj[childName+"_asArray"] = [obj[childName]]; - else - obj[childName+"_asArray"] = obj[childName]; - break; - /*case "none": - break;*/ - } - - if(!(obj[childName] instanceof Array) && config.arrayAccessFormPaths.length > 0) { - if(checkInStdFiltersArrayForm(config.arrayAccessFormPaths, obj, childName, path)) { - obj[childName] = [obj[childName]]; - } - } - } - - function fromXmlDateTime(prop) { - // Implementation based up on http://stackoverflow.com/questions/8178598/xml-datetime-to-javascript-date-object - // Improved to support full spec and optional parts - var bits = prop.split(/[-T:+Z]/g); - - var d = new Date(bits[0], bits[1]-1, bits[2]); - var secondBits = bits[5].split("\."); - d.setHours(bits[3], bits[4], secondBits[0]); - if(secondBits.length>1) - d.setMilliseconds(secondBits[1]); - - // Get supplied time zone offset in minutes - if(bits[6] && bits[7]) { - var offsetMinutes = bits[6] * 60 + Number(bits[7]); - var sign = /\d\d-\d\d:\d\d$/.test(prop)? '-' : '+'; - - // Apply the sign - offsetMinutes = 0 + (sign == '-'? -1 * offsetMinutes : offsetMinutes); - - // Apply offset and local timezone - d.setMinutes(d.getMinutes() - offsetMinutes - d.getTimezoneOffset()) - } - else - if(prop.indexOf("Z", prop.length - 1) !== -1) { - d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds())); - } - - // d is now a local time equivalent to the supplied time - return d; - } - - function checkFromXmlDateTimePaths(value, childName, fullPath) { - if(config.datetimeAccessFormPaths.length > 0) { - var path = fullPath.split("\.#")[0]; - if(checkInStdFiltersArrayForm(config.datetimeAccessFormPaths, value, childName, path)) { - return fromXmlDateTime(value); - } - else - return value; - } - else - return value; - } - - function checkXmlElementsFilter(obj, childType, childName, childPath) { - if( childType == DOMNodeTypes.ELEMENT_NODE && config.xmlElementsFilter.length > 0) { - return checkInStdFiltersArrayForm(config.xmlElementsFilter, obj, childName, childPath); - } - else - return true; - } - - function parseDOMChildren( node, path ) { - if(node.nodeType == DOMNodeTypes.DOCUMENT_NODE) { - var result = new Object; - var nodeChildren = node.childNodes; - // Alternative for firstElementChild which is not supported in some environments - for(var cidx=0; cidx 1 && result.__text!=null && config.skipEmptyTextNodesForObj) { - if( (config.stripWhitespaces && result.__text=="") || (result.__text.trim()=="")) { - delete result.__text; - } - } - delete result.__cnt; - - if( config.enableToStringFunc && (result.__text!=null || result.__cdata!=null )) { - result.toString = function() { - return (this.__text!=null? this.__text:'')+( this.__cdata!=null ? this.__cdata:''); - }; - } - - return result; - } - else - if(node.nodeType == DOMNodeTypes.TEXT_NODE || node.nodeType == DOMNodeTypes.CDATA_SECTION_NODE) { - return node.nodeValue; - } - } - - function startTag(jsonObj, element, attrList, closed) { - var resultStr = "<"+ ( (jsonObj!=null && jsonObj.__prefix!=null)? (jsonObj.__prefix+":"):"") + element; - if(attrList!=null) { - for(var aidx = 0; aidx < attrList.length; aidx++) { - var attrName = attrList[aidx]; - var attrVal = jsonObj[attrName]; - if(config.escapeMode) - attrVal=escapeXmlChars(attrVal); - resultStr+=" "+attrName.substr(config.attributePrefix.length)+"="; - if(config.useDoubleQuotes) - resultStr+='"'+attrVal+'"'; - else - resultStr+="'"+attrVal+"'"; - } - } - if(!closed) - resultStr+=">"; - else - resultStr+="/>"; - return resultStr; - } - - function endTag(jsonObj,elementName) { - return ""; - } - - function endsWith(str, suffix) { - return str.indexOf(suffix, str.length - suffix.length) !== -1; - } - - function jsonXmlSpecialElem ( jsonObj, jsonObjField ) { - if((config.arrayAccessForm=="property" && endsWith(jsonObjField.toString(),("_asArray"))) - || jsonObjField.toString().indexOf(config.attributePrefix)==0 - || jsonObjField.toString().indexOf("__")==0 - || (jsonObj[jsonObjField] instanceof Function) ) - return true; - else - return false; - } - - function jsonXmlElemCount ( jsonObj ) { - var elementsCnt = 0; - if(jsonObj instanceof Object ) { - for( var it in jsonObj ) { - if(jsonXmlSpecialElem ( jsonObj, it) ) - continue; - elementsCnt++; - } - } - return elementsCnt; - } - - function checkJsonObjPropertiesFilter(jsonObj, propertyName, jsonObjPath) { - return config.jsonPropertiesFilter.length == 0 - || jsonObjPath=="" - || checkInStdFiltersArrayForm(config.jsonPropertiesFilter, jsonObj, propertyName, jsonObjPath); - } - - function parseJSONAttributes ( jsonObj ) { - var attrList = []; - if(jsonObj instanceof Object ) { - for( var ait in jsonObj ) { - if(ait.toString().indexOf("__")== -1 && ait.toString().indexOf(config.attributePrefix)==0) { - attrList.push(ait); - } - } - } - return attrList; - } - - function parseJSONTextAttrs ( jsonTxtObj ) { - var result =""; - - if(jsonTxtObj.__cdata!=null) { - result+=""; - } - - if(jsonTxtObj.__text!=null) { - if(config.escapeMode) - result+=escapeXmlChars(jsonTxtObj.__text); - else - result+=jsonTxtObj.__text; - } - return result; - } - - function parseJSONTextObject ( jsonTxtObj ) { - var result =""; - - if( jsonTxtObj instanceof Object ) { - result+=parseJSONTextAttrs ( jsonTxtObj ); - } - else - if(jsonTxtObj!=null) { - if(config.escapeMode) - result+=escapeXmlChars(jsonTxtObj); - else - result+=jsonTxtObj; - } - - return result; - } - - function getJsonPropertyPath(jsonObjPath, jsonPropName) { - if (jsonObjPath==="") { - return jsonPropName; - } - else - return jsonObjPath+"."+jsonPropName; - } - - function parseJSONArray ( jsonArrRoot, jsonArrObj, attrList, jsonObjPath ) { - var result = ""; - if(jsonArrRoot.length == 0) { - result+=startTag(jsonArrRoot, jsonArrObj, attrList, true); - } - else { - for(var arIdx = 0; arIdx < jsonArrRoot.length; arIdx++) { - result+=startTag(jsonArrRoot[arIdx], jsonArrObj, parseJSONAttributes(jsonArrRoot[arIdx]), false); - result+=parseJSONObject(jsonArrRoot[arIdx], getJsonPropertyPath(jsonObjPath,jsonArrObj)); - result+=endTag(jsonArrRoot[arIdx],jsonArrObj); - } - } - return result; - } - - function parseJSONObject ( jsonObj, jsonObjPath ) { - var result = ""; - - var elementsCnt = jsonXmlElemCount ( jsonObj ); - - if(elementsCnt > 0) { - for( var it in jsonObj ) { - - if(jsonXmlSpecialElem ( jsonObj, it) || (jsonObjPath!="" && !checkJsonObjPropertiesFilter(jsonObj, it, getJsonPropertyPath(jsonObjPath,it))) ) - continue; - - var subObj = jsonObj[it]; - - var attrList = parseJSONAttributes( subObj ) - - if(subObj == null || subObj == undefined) { - result+=startTag(subObj, it, attrList, true); - } - else - if(subObj instanceof Object) { - - if(subObj instanceof Array) { - result+=parseJSONArray( subObj, it, attrList, jsonObjPath ); - } - else if(subObj instanceof Date) { - result+=startTag(subObj, it, attrList, false); - result+=subObj.toISOString(); - result+=endTag(subObj,it); - } - else { - var subObjElementsCnt = jsonXmlElemCount ( subObj ); - if(subObjElementsCnt > 0 || subObj.__text!=null || subObj.__cdata!=null) { - result+=startTag(subObj, it, attrList, false); - result+=parseJSONObject(subObj, getJsonPropertyPath(jsonObjPath,it)); - result+=endTag(subObj,it); - } - else { - result+=startTag(subObj, it, attrList, true); - } - } - } - else { - result+=startTag(subObj, it, attrList, false); - result+=parseJSONTextObject(subObj); - result+=endTag(subObj,it); - } - } - } - result+=parseJSONTextObject(jsonObj); - - return result; - } - - this.parseXmlString = function(xmlDocStr) { - // var isIEParser = window.ActiveXObject || "ActiveXObject" in window; - var isIEParser = false; - if (xmlDocStr === undefined) { - return null; - } - var xmlDoc; - if (DOMParser) { - var parser=new DOMParser(); - var parsererrorNS = null; - // IE9+ now is here - if(!isIEParser) { - try { - parsererrorNS = parser.parseFromString("INVALID", "text/xml").getElementsByTagName("parsererror")[0].namespaceURI; - } - catch(err) { - parsererrorNS = null; - } - } - try { - xmlDoc = parser.parseFromString( xmlDocStr, "text/xml" ); - if( parsererrorNS!= null && xmlDoc.getElementsByTagNameNS(parsererrorNS, "parsererror").length > 0) { - //throw new Error('Error parsing XML: '+xmlDocStr); - xmlDoc = null; - } - } - catch(err) { - xmlDoc = null; - } - } - else { - // IE :( - if(xmlDocStr.indexOf("") + 2 ); - } - xmlDoc=new ActiveXObject("Microsoft.XMLDOM"); - xmlDoc.async="false"; - xmlDoc.loadXML(xmlDocStr); - } - return xmlDoc; - }; - - this.asArray = function(prop) { - if (prop === undefined || prop == null) - return []; - else - if(prop instanceof Array) - return prop; - else - return [prop]; - }; - - this.toXmlDateTime = function(dt) { - if(dt instanceof Date) - return dt.toISOString(); - else - if(typeof(dt) === 'number' ) - return new Date(dt).toISOString(); - else - return null; - }; - - this.asDateTime = function(prop) { - if(typeof(prop) == "string") { - return fromXmlDateTime(prop); - } - else - return prop; - }; - - this.xml2json = function (xmlDoc) { - return parseDOMChildren ( xmlDoc ); - }; - - this.xml_str2json = function (xmlDocStr) { - var xmlDoc = this.parseXmlString(xmlDocStr); - if(xmlDoc!=null) - return this.xml2json(xmlDoc); - else - return null; - }; - - this.json2xml_str = function (jsonObj) { - return parseJSONObject ( jsonObj, "" ); - }; - - this.json2xml = function (jsonObj) { - var xmlDocStr = this.json2xml_str (jsonObj); - return this.parseXmlString(xmlDocStr); - }; - - this.getVersion = function () { - return VERSION; - }; -}; - -var xml2json = function (str) { - if (!str) return null; - var parser = new DOMParser(); - var xmlDoc = parser.parseFromString(str, "text/xml"); - var x2jsObj = new x2js(); - var data = x2jsObj.xml2json(xmlDoc); - if (data.html && data.getElementsByTagName('parsererror').length) { - return null; - } else { - return data; - } -}; - -var json2xml = function (data) { - var x2jsObj = new x2js(); - return x2jsObj.json2xml(data); -}; - -module.exports = xml2json; +/* + Copyright 2011-2013 Abdulla Abdurakhmanov + Original sources are available at https://code.google.com/p/x2js/ + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ +var DOMParser = __webpack_require__(13).DOMParser; + +var x2js = function (config) { + 'use strict'; + + var VERSION = "1.2.0"; + + config = config || {}; + initConfigDefaults(); + initRequiredPolyfills(); + + function initConfigDefaults() { + if(config.escapeMode === undefined) { + config.escapeMode = true; + } + + config.attributePrefix = config.attributePrefix || "_"; + config.arrayAccessForm = config.arrayAccessForm || "none"; + config.emptyNodeForm = config.emptyNodeForm || "text"; + + if(config.enableToStringFunc === undefined) { + config.enableToStringFunc = true; + } + config.arrayAccessFormPaths = config.arrayAccessFormPaths || []; + if(config.skipEmptyTextNodesForObj === undefined) { + config.skipEmptyTextNodesForObj = true; + } + if(config.stripWhitespaces === undefined) { + config.stripWhitespaces = true; + } + config.datetimeAccessFormPaths = config.datetimeAccessFormPaths || []; + + if(config.useDoubleQuotes === undefined) { + config.useDoubleQuotes = false; + } + + config.xmlElementsFilter = config.xmlElementsFilter || []; + config.jsonPropertiesFilter = config.jsonPropertiesFilter || []; + + if(config.keepCData === undefined) { + config.keepCData = false; + } + } + + var DOMNodeTypes = { + ELEMENT_NODE : 1, + TEXT_NODE : 3, + CDATA_SECTION_NODE : 4, + COMMENT_NODE : 8, + DOCUMENT_NODE : 9 + }; + + function initRequiredPolyfills() { + } + + function getNodeLocalName( node ) { + var nodeLocalName = node.localName; + if(nodeLocalName == null) // Yeah, this is IE!! + nodeLocalName = node.baseName; + if(nodeLocalName == null || nodeLocalName=="") // =="" is IE too + nodeLocalName = node.nodeName; + return nodeLocalName; + } + + function getNodePrefix(node) { + return node.prefix; + } + + function escapeXmlChars(str) { + if(typeof(str) == "string") + return str.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, '''); + else + return str; + } + + function unescapeXmlChars(str) { + return str.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, '&'); + } + + function checkInStdFiltersArrayForm(stdFiltersArrayForm, obj, name, path) { + var idx = 0; + for(; idx < stdFiltersArrayForm.length; idx++) { + var filterPath = stdFiltersArrayForm[idx]; + if( typeof filterPath === "string" ) { + if(filterPath == path) + break; + } + else + if( filterPath instanceof RegExp) { + if(filterPath.test(path)) + break; + } + else + if( typeof filterPath === "function") { + if(filterPath(obj, name, path)) + break; + } + } + return idx!=stdFiltersArrayForm.length; + } + + function toArrayAccessForm(obj, childName, path) { + switch(config.arrayAccessForm) { + case "property": + if(!(obj[childName] instanceof Array)) + obj[childName+"_asArray"] = [obj[childName]]; + else + obj[childName+"_asArray"] = obj[childName]; + break; + /*case "none": + break;*/ + } + + if(!(obj[childName] instanceof Array) && config.arrayAccessFormPaths.length > 0) { + if(checkInStdFiltersArrayForm(config.arrayAccessFormPaths, obj, childName, path)) { + obj[childName] = [obj[childName]]; + } + } + } + + function fromXmlDateTime(prop) { + // Implementation based up on http://stackoverflow.com/questions/8178598/xml-datetime-to-javascript-date-object + // Improved to support full spec and optional parts + var bits = prop.split(/[-T:+Z]/g); + + var d = new Date(bits[0], bits[1]-1, bits[2]); + var secondBits = bits[5].split("\."); + d.setHours(bits[3], bits[4], secondBits[0]); + if(secondBits.length>1) + d.setMilliseconds(secondBits[1]); + + // Get supplied time zone offset in minutes + if(bits[6] && bits[7]) { + var offsetMinutes = bits[6] * 60 + Number(bits[7]); + var sign = /\d\d-\d\d:\d\d$/.test(prop)? '-' : '+'; + + // Apply the sign + offsetMinutes = 0 + (sign == '-'? -1 * offsetMinutes : offsetMinutes); + + // Apply offset and local timezone + d.setMinutes(d.getMinutes() - offsetMinutes - d.getTimezoneOffset()) + } + else + if(prop.indexOf("Z", prop.length - 1) !== -1) { + d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds())); + } + + // d is now a local time equivalent to the supplied time + return d; + } + + function checkFromXmlDateTimePaths(value, childName, fullPath) { + if(config.datetimeAccessFormPaths.length > 0) { + var path = fullPath.split("\.#")[0]; + if(checkInStdFiltersArrayForm(config.datetimeAccessFormPaths, value, childName, path)) { + return fromXmlDateTime(value); + } + else + return value; + } + else + return value; + } + + function checkXmlElementsFilter(obj, childType, childName, childPath) { + if( childType == DOMNodeTypes.ELEMENT_NODE && config.xmlElementsFilter.length > 0) { + return checkInStdFiltersArrayForm(config.xmlElementsFilter, obj, childName, childPath); + } + else + return true; + } + + function parseDOMChildren( node, path ) { + if(node.nodeType == DOMNodeTypes.DOCUMENT_NODE) { + var result = new Object; + var nodeChildren = node.childNodes; + // Alternative for firstElementChild which is not supported in some environments + for(var cidx=0; cidx 1 && result.__text!=null && config.skipEmptyTextNodesForObj) { + if( (config.stripWhitespaces && result.__text=="") || (result.__text.trim()=="")) { + delete result.__text; + } + } + delete result.__cnt; + + if( config.enableToStringFunc && (result.__text!=null || result.__cdata!=null )) { + result.toString = function() { + return (this.__text!=null? this.__text:'')+( this.__cdata!=null ? this.__cdata:''); + }; + } + + return result; + } + else + if(node.nodeType == DOMNodeTypes.TEXT_NODE || node.nodeType == DOMNodeTypes.CDATA_SECTION_NODE) { + return node.nodeValue; + } + } + + function startTag(jsonObj, element, attrList, closed) { + var resultStr = "<"+ ( (jsonObj!=null && jsonObj.__prefix!=null)? (jsonObj.__prefix+":"):"") + element; + if(attrList!=null) { + for(var aidx = 0; aidx < attrList.length; aidx++) { + var attrName = attrList[aidx]; + var attrVal = jsonObj[attrName]; + if(config.escapeMode) + attrVal=escapeXmlChars(attrVal); + resultStr+=" "+attrName.substr(config.attributePrefix.length)+"="; + if(config.useDoubleQuotes) + resultStr+='"'+attrVal+'"'; + else + resultStr+="'"+attrVal+"'"; + } + } + if(!closed) + resultStr+=">"; + else + resultStr+="/>"; + return resultStr; + } + + function endTag(jsonObj,elementName) { + return ""; + } + + function endsWith(str, suffix) { + return str.indexOf(suffix, str.length - suffix.length) !== -1; + } + + function jsonXmlSpecialElem ( jsonObj, jsonObjField ) { + if((config.arrayAccessForm=="property" && endsWith(jsonObjField.toString(),("_asArray"))) + || jsonObjField.toString().indexOf(config.attributePrefix)==0 + || jsonObjField.toString().indexOf("__")==0 + || (jsonObj[jsonObjField] instanceof Function) ) + return true; + else + return false; + } + + function jsonXmlElemCount ( jsonObj ) { + var elementsCnt = 0; + if(jsonObj instanceof Object ) { + for( var it in jsonObj ) { + if(jsonXmlSpecialElem ( jsonObj, it) ) + continue; + elementsCnt++; + } + } + return elementsCnt; + } + + function checkJsonObjPropertiesFilter(jsonObj, propertyName, jsonObjPath) { + return config.jsonPropertiesFilter.length == 0 + || jsonObjPath=="" + || checkInStdFiltersArrayForm(config.jsonPropertiesFilter, jsonObj, propertyName, jsonObjPath); + } + + function parseJSONAttributes ( jsonObj ) { + var attrList = []; + if(jsonObj instanceof Object ) { + for( var ait in jsonObj ) { + if(ait.toString().indexOf("__")== -1 && ait.toString().indexOf(config.attributePrefix)==0) { + attrList.push(ait); + } + } + } + return attrList; + } + + function parseJSONTextAttrs ( jsonTxtObj ) { + var result =""; + + if(jsonTxtObj.__cdata!=null) { + result+=""; + } + + if(jsonTxtObj.__text!=null) { + if(config.escapeMode) + result+=escapeXmlChars(jsonTxtObj.__text); + else + result+=jsonTxtObj.__text; + } + return result; + } + + function parseJSONTextObject ( jsonTxtObj ) { + var result =""; + + if( jsonTxtObj instanceof Object ) { + result+=parseJSONTextAttrs ( jsonTxtObj ); + } + else + if(jsonTxtObj!=null) { + if(config.escapeMode) + result+=escapeXmlChars(jsonTxtObj); + else + result+=jsonTxtObj; + } + + return result; + } + + function getJsonPropertyPath(jsonObjPath, jsonPropName) { + if (jsonObjPath==="") { + return jsonPropName; + } + else + return jsonObjPath+"."+jsonPropName; + } + + function parseJSONArray ( jsonArrRoot, jsonArrObj, attrList, jsonObjPath ) { + var result = ""; + if(jsonArrRoot.length == 0) { + result+=startTag(jsonArrRoot, jsonArrObj, attrList, true); + } + else { + for(var arIdx = 0; arIdx < jsonArrRoot.length; arIdx++) { + result+=startTag(jsonArrRoot[arIdx], jsonArrObj, parseJSONAttributes(jsonArrRoot[arIdx]), false); + result+=parseJSONObject(jsonArrRoot[arIdx], getJsonPropertyPath(jsonObjPath,jsonArrObj)); + result+=endTag(jsonArrRoot[arIdx],jsonArrObj); + } + } + return result; + } + + function parseJSONObject ( jsonObj, jsonObjPath ) { + var result = ""; + + var elementsCnt = jsonXmlElemCount ( jsonObj ); + + if(elementsCnt > 0) { + for( var it in jsonObj ) { + + if(jsonXmlSpecialElem ( jsonObj, it) || (jsonObjPath!="" && !checkJsonObjPropertiesFilter(jsonObj, it, getJsonPropertyPath(jsonObjPath,it))) ) + continue; + + var subObj = jsonObj[it]; + + var attrList = parseJSONAttributes( subObj ) + + if(subObj == null || subObj == undefined) { + result+=startTag(subObj, it, attrList, true); + } + else + if(subObj instanceof Object) { + + if(subObj instanceof Array) { + result+=parseJSONArray( subObj, it, attrList, jsonObjPath ); + } + else if(subObj instanceof Date) { + result+=startTag(subObj, it, attrList, false); + result+=subObj.toISOString(); + result+=endTag(subObj,it); + } + else { + var subObjElementsCnt = jsonXmlElemCount ( subObj ); + if(subObjElementsCnt > 0 || subObj.__text!=null || subObj.__cdata!=null) { + result+=startTag(subObj, it, attrList, false); + result+=parseJSONObject(subObj, getJsonPropertyPath(jsonObjPath,it)); + result+=endTag(subObj,it); + } + else { + result+=startTag(subObj, it, attrList, true); + } + } + } + else { + result+=startTag(subObj, it, attrList, false); + result+=parseJSONTextObject(subObj); + result+=endTag(subObj,it); + } + } + } + result+=parseJSONTextObject(jsonObj); + + return result; + } + + this.parseXmlString = function(xmlDocStr) { + // var isIEParser = window.ActiveXObject || "ActiveXObject" in window; + var isIEParser = false; + if (xmlDocStr === undefined) { + return null; + } + var xmlDoc; + if (DOMParser) { + var parser=new DOMParser(); + var parsererrorNS = null; + // IE9+ now is here + if(!isIEParser) { + try { + parsererrorNS = parser.parseFromString("INVALID", "text/xml").getElementsByTagName("parsererror")[0].namespaceURI; + } + catch(err) { + parsererrorNS = null; + } + } + try { + xmlDoc = parser.parseFromString( xmlDocStr, "text/xml" ); + if( parsererrorNS!= null && xmlDoc.getElementsByTagNameNS(parsererrorNS, "parsererror").length > 0) { + //throw new Error('Error parsing XML: '+xmlDocStr); + xmlDoc = null; + } + } + catch(err) { + xmlDoc = null; + } + } + else { + // IE :( + if(xmlDocStr.indexOf("") + 2 ); + } + xmlDoc=new ActiveXObject("Microsoft.XMLDOM"); + xmlDoc.async="false"; + xmlDoc.loadXML(xmlDocStr); + } + return xmlDoc; + }; + + this.asArray = function(prop) { + if (prop === undefined || prop == null) + return []; + else + if(prop instanceof Array) + return prop; + else + return [prop]; + }; + + this.toXmlDateTime = function(dt) { + if(dt instanceof Date) + return dt.toISOString(); + else + if(typeof(dt) === 'number' ) + return new Date(dt).toISOString(); + else + return null; + }; + + this.asDateTime = function(prop) { + if(typeof(prop) == "string") { + return fromXmlDateTime(prop); + } + else + return prop; + }; + + this.xml2json = function (xmlDoc) { + return parseDOMChildren ( xmlDoc ); + }; + + this.xml_str2json = function (xmlDocStr) { + var xmlDoc = this.parseXmlString(xmlDocStr); + if(xmlDoc!=null) + return this.xml2json(xmlDoc); + else + return null; + }; + + this.json2xml_str = function (jsonObj) { + return parseJSONObject ( jsonObj, "" ); + }; + + this.json2xml = function (jsonObj) { + var xmlDocStr = this.json2xml_str (jsonObj); + return this.parseXmlString(xmlDocStr); + }; + + this.getVersion = function () { + return VERSION; + }; +}; + +var xml2json = function (str) { + if (!str) return null; + var parser = new DOMParser(); + var xmlDoc = parser.parseFromString(str, "text/xml"); + var x2jsObj = new x2js(); + var data = x2jsObj.xml2json(xmlDoc); + if (data.html && data.getElementsByTagName('parsererror').length) { + return null; + } else { + return data; + } +}; + +var json2xml = function (data) { + var x2jsObj = new x2js(); + return x2jsObj.json2xml(data); +}; + +module.exports = xml2json; /***/ }), @@ -4858,5432 +4858,5486 @@ exports.XMLReader = XMLReader; /* 15 */ /***/ (function(module, exports) { -//copyright Ryan Day 2010 , Joscha Feth 2013 [MIT Licensed] - -var element_start_char = - "a-zA-Z_\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FFF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD"; -var element_non_start_char = "\-.0-9\u00B7\u0300-\u036F\u203F\u2040"; -var element_replace = new RegExp("^([^" + element_start_char + "])|^((x|X)(m|M)(l|L))|([^" + element_start_char + element_non_start_char + "])", "g"); -var not_safe_in_xml = /[^\x09\x0A\x0D\x20-\xFF\x85\xA0-\uD7FF\uE000-\uFDCF\uFDE0-\uFFFD]/gm; - -var objKeys = function (obj) { - var l = []; - if (obj instanceof Object) { - for (var k in obj) { - if (obj.hasOwnProperty(k)) { - l.push(k); - } - } - } - return l; -}; -var process_to_xml = function (node_data, options) { - - var makeNode = function (name, content, attributes, level, hasSubNodes) { - var indent_value = options.indent !== undefined ? options.indent : "\t"; - var indent = options.prettyPrint ? '\n' + new Array(level).join(indent_value) : ''; - if (options.removeIllegalNameCharacters) { - name = name.replace(element_replace, '_'); - } - - var node = [indent, '<', name, (attributes || '')]; - if (content && content.length > 0) { - node.push('>') - node.push(content); - hasSubNodes && node.push(indent); - node.push(''); - } else { - node.push('/>'); - } - return node.join(''); - }; - - return (function fn(node_data, node_descriptor, level) { - var type = typeof node_data; - if ((Array.isArray) ? Array.isArray(node_data) : node_data instanceof Array) { - type = 'array'; - } else if (node_data instanceof Date) { - type = 'date'; - } - - switch (type) { - //if value is an array create child nodes from values - case 'array': - var ret = []; - node_data.map(function (v) { - ret.push(fn(v, 1, level + 1)); - //entries that are values of an array are the only ones that can be special node descriptors - }); - options.prettyPrint && ret.push('\n'); - return ret.join(''); - break; - - case 'date': - // cast dates to ISO 8601 date (soap likes it) - return node_data.toJSON ? node_data.toJSON() : node_data + ''; - break; - - case 'object': - var nodes = []; - for (var name in node_data) { - if (node_data.hasOwnProperty(name)) { - if (node_data[name] instanceof Array) { - for (var j in node_data[name]) { - if (node_data[name].hasOwnProperty(j)) - nodes.push(makeNode(name, fn(node_data[name][j], 0, level + 1), null, level + 1, objKeys(node_data[name][j]).length)); - } - } else { - nodes.push(makeNode(name, fn(node_data[name], 0, level + 1), null, level + 1)); - } - } - } - options.prettyPrint && nodes.length > 0 && nodes.push('\n'); - return nodes.join(''); - break; - - case 'function': - return node_data(); - break; - - default: - return options.escape ? esc(node_data) : '' + node_data; - } - - }(node_data, 0, 0)) -}; - - -var xml_header = function (standalone) { - var ret = [''); - - return ret.join(''); -}; - -function esc(str) { - return ('' + str).replace(/&/g, '&') - .replace(//g, '>') - .replace(/'/g, ''') - .replace(/"/g, '"') - .replace(not_safe_in_xml, ''); -} - -var json2xml = function (obj, options) { - - if (!options) { - options = { - xmlHeader: { - standalone: true - }, - prettyPrint: true, - indent: " " - }; - } - - if (typeof obj == 'string') { - try { - obj = JSON.parse(obj.toString()); - } catch (e) { - return false; - } - } - - var xmlheader = ''; - var docType = ''; - if (options) { - if (typeof options == 'object') { - // our config is an object - - if (options.xmlHeader) { - // the user wants an xml header - xmlheader = xml_header(!!options.xmlHeader.standalone); - } - - if (typeof options.docType != 'undefined') { - docType = '' - } - } else { - // our config is a boolean value, so just add xml header - xmlheader = xml_header(); - } - } - options = options || {} - - var ret = [ - xmlheader, - (options.prettyPrint && docType ? '\n' : ''), - docType, - process_to_xml(obj, options) - ]; - return ret.join('').replace(/\n{2,}/g, '\n').replace(/\s+$/g, ''); -}; - -module.exports = json2xml; +//copyright Ryan Day 2010 , Joscha Feth 2013 [MIT Licensed] +var element_start_char = + "a-zA-Z_\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FFF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD"; +var element_non_start_char = "\-.0-9\u00B7\u0300-\u036F\u203F\u2040"; +var element_replace = new RegExp("^([^" + element_start_char + "])|^((x|X)(m|M)(l|L))|([^" + element_start_char + element_non_start_char + "])", "g"); +var not_safe_in_xml = /[^\x09\x0A\x0D\x20-\xFF\x85\xA0-\uD7FF\uE000-\uFDCF\uFDE0-\uFFFD]/gm; -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { +var objKeys = function (obj) { + var l = []; + if (obj instanceof Object) { + for (var k in obj) { + if (obj.hasOwnProperty(k)) { + l.push(k); + } + } + } + return l; +}; +var process_to_xml = function (node_data, options) { -var session = __webpack_require__(5); -var util = __webpack_require__(0); - -var originApiMap = {}; -var transferToTaskMethod = function (apiMap, apiName) { - originApiMap[apiName] = apiMap[apiName]; - apiMap[apiName] = function (params, callback) { - if (params.SkipTask) { - originApiMap[apiName].call(this, params, callback); - } else { - this._addTask(apiName, params, callback); - } - }; -}; - -var initTask = function (cos) { - - var queue = []; - var tasks = {}; - var uploadingFileCount = 0; - var nextUploadIndex = 0; - - // 接口返回简略的任务信息 - var formatTask = function (task) { - var t = { - id: task.id, - Bucket: task.Bucket, - Region: task.Region, - Key: task.Key, - FilePath: task.FilePath, - state: task.state, - loaded: task.loaded, - size: task.size, - speed: task.speed, - percent: task.percent, - hashPercent: task.hashPercent, - error: task.error, - }; - if (task.FilePath) t.FilePath = task.FilePath; - return t; - }; - - var emitListUpdate = (function () { - var timer; - var emit = function () { - timer = 0; - cos.emit('task-list-update', {list: util.map(queue, formatTask)}); - cos.emit('list-update', {list: util.map(queue, formatTask)}); - }; - return function () { - if (!timer) timer = setTimeout(emit); - } - })(); - - var clearQueue = function () { - if (queue.length <= cos.options.UploadQueueSize) return; - for (var i = 0; - i < nextUploadIndex && // 小于当前操作的 index 才清理 - i < queue.length && // 大于队列才清理 - queue.length > cos.options.UploadQueueSize // 如果还太多,才继续清理 - ;) { - var isActive = queue[i].state === 'waiting' || queue[i].state === 'checking' || queue[i].state === 'uploading'; - if (!queue[i] || !isActive) { - tasks[queue[i].id] && (delete tasks[queue[i].id]); - queue.splice(i, 1); - nextUploadIndex--; - } else { - i++; - } - } - emitListUpdate(); - }; - - var startNextTask = function () { - // 检查是否允许增加执行进程 - if (uploadingFileCount >= cos.options.FileParallelLimit) return; - // 跳过不可执行的任务 - while (queue[nextUploadIndex] && queue[nextUploadIndex].state !== 'waiting') nextUploadIndex++; - // 检查是否已遍历结束 - if (nextUploadIndex >= queue.length) return; - // 上传该遍历到的任务 - var task = queue[nextUploadIndex]; - nextUploadIndex++; - uploadingFileCount++; - task.state = 'checking'; - task.params.onTaskStart && task.params.onTaskStart(formatTask(task)); - !task.params.UploadData && (task.params.UploadData = {}); - var apiParams = util.formatParams(task.api, task.params); - originApiMap[task.api].call(cos, apiParams, function (err, data) { - if (!cos._isRunningTask(task.id)) return; - if (task.state === 'checking' || task.state === 'uploading') { - task.state = err ? 'error' : 'success'; - err && (task.error = err); - uploadingFileCount--; - emitListUpdate(); - startNextTask(); - task.callback && task.callback(err, data); - if (task.state === 'success') { - if (task.params) { - delete task.params.UploadData; - delete task.params.Body; - delete task.params; - } - delete task.callback; - } - } - clearQueue(); - }); - emitListUpdate(); - // 异步执行下一个任务 - setTimeout(startNextTask); - }; - - var killTask = function (id, switchToState) { - var task = tasks[id]; - if (!task) return; - var waiting = task && task.state === 'waiting'; - var running = task && (task.state === 'checking' || task.state === 'uploading'); - if (switchToState === 'canceled' && task.state !== 'canceled' || - switchToState === 'paused' && waiting || - switchToState === 'paused' && running) { - if (switchToState === 'paused' && task.params.Body && typeof task.params.Body.pipe === 'function') { - console.error('stream not support pause'); - return; - } - task.state = switchToState; - cos.emit('inner-kill-task', {TaskId: id, toState: switchToState}); - try { - var UploadId = task && task.params && task.params.UploadData.UploadId - } catch(e) {} - if (switchToState === 'canceled' && UploadId) session.removeUsing(UploadId) - emitListUpdate(); - if (running) { - uploadingFileCount--; - startNextTask(); - } - if (switchToState === 'canceled') { - if (task.params) { - delete task.params.UploadData; - delete task.params.Body; - delete task.params; - } - delete task.callback; - } - } - clearQueue(); - }; - - cos._addTasks = function (taskList) { - util.each(taskList, function (task) { - cos._addTask(task.api, task.params, task.callback, true); - }); - emitListUpdate(); - }; - - cos._addTask = function (api, params, callback, ignoreAddEvent) { - - // 如果小程序版本不支持获取文件分片内容,统一转到 postObject 接口上传 - if (api === 'sliceUploadFile' && !util.canFileSlice()) api = 'postObject'; - - // 复制参数对象 - params = util.formatParams(api, params); - - // 生成 id - var id = util.uuid(); - params.TaskId = id; - params.onTaskReady && params.onTaskReady(id); - - var task = { - // env - params: params, - callback: callback, - api: api, - index: queue.length, - // task - id: id, - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - FilePath: params.FilePath || '', - state: 'waiting', - loaded: 0, - size: 0, - speed: 0, - percent: 0, - hashPercent: 0, - error: null, - }; - var onHashProgress = params.onHashProgress; - params.onHashProgress = function (info) { - if (!cos._isRunningTask(task.id)) return; - task.hashPercent = info.percent; - onHashProgress && onHashProgress(info); - emitListUpdate(); - }; - var onProgress = params.onProgress; - params.onProgress = function (info) { - if (!cos._isRunningTask(task.id)) return; - task.state === 'checking' && (task.state = 'uploading'); - task.loaded = info.loaded; - task.size = info.total; - task.speed = info.speed; - task.percent = info.percent; - onProgress && onProgress(info); - emitListUpdate(); - }; - - // 异步获取 filesize - util.getFileSize(api, params, function (err, size) { - // 开始处理上传 - if (err) { // 如果获取大小出错,不加入队列 - callback(err); - return; - } - // 获取完文件大小再把任务加入队列 - tasks[id] = task; - queue.push(task); - task.size = size; - !ignoreAddEvent && emitListUpdate(); - startNextTask(); - clearQueue(); - }); - return id; - }; - cos._isRunningTask = function (id) { - var task = tasks[id]; - return !!(task && (task.state === 'checking' || task.state === 'uploading')); - }; - cos.getTaskList = function () { - return util.map(queue, formatTask); - }; - cos.cancelTask = function (id) { - killTask(id, 'canceled'); - }; - cos.pauseTask = function (id) { - killTask(id, 'paused'); - }; - cos.restartTask = function (id) { - var task = tasks[id]; - if (task && (task.state === 'paused' || task.state === 'error')) { - task.state = 'waiting'; - emitListUpdate(); - nextUploadIndex = Math.min(nextUploadIndex, task.index); - startNextTask(); - } - }; - cos.isUploadRunning = function () { - return uploadingFileCount || nextUploadIndex < queue.length; - }; - -}; - -module.exports.transferToTaskMethod = transferToTaskMethod; -module.exports.init = initTask; + var makeNode = function (name, content, attributes, level, hasSubNodes) { + var indent_value = options.indent !== undefined ? options.indent : "\t"; + var indent = options.prettyPrint ? '\n' + new Array(level).join(indent_value) : ''; + if (options.removeIllegalNameCharacters) { + name = name.replace(element_replace, '_'); + } + + var node = [indent, '<', name, (attributes || '')]; + if (content && content.length > 0) { + node.push('>') + node.push(content); + hasSubNodes && node.push(indent); + node.push(''); + } else { + node.push('/>'); + } + return node.join(''); + }; + + return (function fn(node_data, node_descriptor, level) { + var type = typeof node_data; + if ((Array.isArray) ? Array.isArray(node_data) : node_data instanceof Array) { + type = 'array'; + } else if (node_data instanceof Date) { + type = 'date'; + } + + switch (type) { + //if value is an array create child nodes from values + case 'array': + var ret = []; + node_data.map(function (v) { + ret.push(fn(v, 1, level + 1)); + //entries that are values of an array are the only ones that can be special node descriptors + }); + options.prettyPrint && ret.push('\n'); + return ret.join(''); + break; + + case 'date': + // cast dates to ISO 8601 date (soap likes it) + return node_data.toJSON ? node_data.toJSON() : node_data + ''; + break; + + case 'object': + var nodes = []; + for (var name in node_data) { + if (node_data.hasOwnProperty(name)) { + if (node_data[name] instanceof Array) { + for (var j in node_data[name]) { + if (node_data[name].hasOwnProperty(j)) + nodes.push(makeNode(name, fn(node_data[name][j], 0, level + 1), null, level + 1, objKeys(node_data[name][j]).length)); + } + } else { + nodes.push(makeNode(name, fn(node_data[name], 0, level + 1), null, level + 1)); + } + } + } + options.prettyPrint && nodes.length > 0 && nodes.push('\n'); + return nodes.join(''); + break; + + case 'function': + return node_data(); + break; + + default: + return options.escape ? esc(node_data) : '' + node_data; + } + + }(node_data, 0, 0)) +}; + + +var xml_header = function (standalone) { + var ret = [''); + + return ret.join(''); +}; + +function esc(str) { + return ('' + str).replace(/&/g, '&') + .replace(//g, '>') + .replace(/'/g, ''') + .replace(/"/g, '"') + .replace(not_safe_in_xml, ''); +} + +var json2xml = function (obj, options) { + + if (!options) { + options = { + xmlHeader: { + standalone: true + }, + prettyPrint: true, + indent: " " + }; + } + + if (typeof obj == 'string') { + try { + obj = JSON.parse(obj.toString()); + } catch (e) { + return false; + } + } + + var xmlheader = ''; + var docType = ''; + if (options) { + if (typeof options == 'object') { + // our config is an object + + if (options.xmlHeader) { + // the user wants an xml header + xmlheader = xml_header(!!options.xmlHeader.standalone); + } + + if (typeof options.docType != 'undefined') { + docType = '' + } + } else { + // our config is a boolean value, so just add xml header + xmlheader = xml_header(); + } + } + options = options || {} + + var ret = [ + xmlheader, + (options.prettyPrint && docType ? '\n' : ''), + docType, + process_to_xml(obj, options) + ]; + return ret.join('').replace(/\n{2,}/g, '\n').replace(/\s+$/g, ''); +}; + +module.exports = json2xml; /***/ }), -/* 17 */ +/* 16 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; - -var REQUEST = __webpack_require__(18); -var base64 = __webpack_require__(3); -var util = __webpack_require__(0); -var mime = __webpack_require__(19); - - -// Bucket 相关 - -/** - * 获取用户的 bucket 列表 - * @param {Object} params 回调函数,必须,下面为参数列表 - * 无特殊参数 - * @param {Function} callback 回调函数,必须 - */ -function getService(params, callback) { - - if (typeof params === 'function') { - callback = params; - params = {}; - } - var protocol = 'https:'; - var domain = this.options.ServiceDomain; - var region = params.Region; - if (domain) { - domain = domain.replace(/\{\{Region\}\}/ig, region || '').replace(/\{\{.*?\}\}/ig, ''); - if (!/^[a-zA-Z]+:\/\//.test(domain)) { - domain = protocol + '//' + domain; - } - if (domain.slice(-1) === '/') { - domain = domain.slice(0, -1); - } - } else if (region) { - domain = protocol + '//cos.' + region + '.myqcloud.com'; - } else { - domain = protocol + '//service.cos.myqcloud.com'; - } - - submitRequest.call(this, { - Action: 'name/cos:GetService', - url: domain, - method: 'GET', - headers: params.Headers, - }, function (err, data) { - if (err) return callback(err); - var buckets = (data && data.ListAllMyBucketsResult && data.ListAllMyBucketsResult.Buckets - && data.ListAllMyBucketsResult.Buckets.Bucket) || []; - buckets = util.isArray(buckets) ? buckets : [buckets]; - var owner = (data && data.ListAllMyBucketsResult && data.ListAllMyBucketsResult.Owner) || {}; - callback(null, { - Buckets: buckets, - Owner: owner, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 创建 Bucket,并初始化访问权限 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.ACL 用户自定义文件权限,可以设置:private,public-read;默认值:private,非必须 - * @param {String} params.GrantRead 赋予被授权者读的权限,格式x-cos-grant-read: uin=" ",uin=" ",非必须 - * @param {String} params.GrantWrite 赋予被授权者写的权限,格式x-cos-grant-write: uin=" ",uin=" ",非必须 - * @param {String} params.GrantFullControl 赋予被授权者读写权限,格式x-cos-grant-full-control: uin=" ",uin=" ",非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {String} data.Location 操作地址 - */ -function putBucket(params, callback) { - - var self = this; - - var xml = ''; - if(params['BucketAZConfig']){ - var CreateBucketConfiguration = { - BucketAZConfig: params.BucketAZConfig - }; - xml = util.json2xml({CreateBucketConfiguration: CreateBucketConfiguration}); - } - - submitRequest.call(this, { - Action: 'name/cos:PutBucket', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - body: xml, - }, function (err, data) { - if (err) return callback(err); - var url = getUrl({ - protocol: self.options.Protocol, - domain: self.options.Domain, - bucket: params.Bucket, - region: params.Region, - isLocation: true, - }); - callback(null, { - Location: url, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 查看是否存在该Bucket,是否有权限访问 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {Boolean} data.BucketExist Bucket是否存在 - * @return {Boolean} data.BucketAuth 是否有 Bucket 的访问权限 - */ -function headBucket(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:HeadBucket', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - method: 'HEAD', - }, function (err, data) { - callback(err, data); - }); -} - -/** - * 获取 Bucket 下的 object 列表 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Prefix 前缀匹配,用来规定返回的文件前缀地址,非必须 - * @param {String} params.Delimiter 定界符为一个符号,如果有Prefix,则将Prefix到delimiter之间的相同路径归为一类,非必须 - * @param {String} params.Marker 默认以UTF-8二进制顺序列出条目,所有列出条目从marker开始,非必须 - * @param {String} params.MaxKeys 单次返回最大的条目数量,默认1000,非必须 - * @param {String} params.EncodingType 规定返回值的编码方式,非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {Object} data.ListBucketResult 返回的 object 列表信息 - */ -function getBucket(params, callback) { - var reqParams = {}; - reqParams['prefix'] = params['Prefix'] || ''; - reqParams['delimiter'] = params['Delimiter']; - reqParams['marker'] = params['Marker']; - reqParams['max-keys'] = params['MaxKeys']; - reqParams['encoding-type'] = params['EncodingType']; - - submitRequest.call(this, { - Action: 'name/cos:GetBucket', - ResourceKey: reqParams['prefix'], - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - qs: reqParams, - }, function (err, data) { - if (err) return callback(err); - var ListBucketResult = data.ListBucketResult || {}; - var Contents = ListBucketResult.Contents || []; - var CommonPrefixes = ListBucketResult.CommonPrefixes || []; - - Contents = util.isArray(Contents) ? Contents : [Contents]; - CommonPrefixes = util.isArray(CommonPrefixes) ? CommonPrefixes : [CommonPrefixes]; - - var result = util.clone(ListBucketResult); - util.extend(result, { - Contents: Contents, - CommonPrefixes: CommonPrefixes, - statusCode: data.statusCode, - headers: data.headers, - }); - - callback(null, result); - }); -} - -/** - * 删除 Bucket - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {String} data.Location 操作地址 - */ -function deleteBucket(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucket', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - method: 'DELETE', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 设置 Bucket 的 权限列表 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.ACL 用户自定义文件权限,可以设置:private,public-read;默认值:private,非必须 - * @param {String} params.GrantRead 赋予被授权者读的权限,格式x-cos-grant-read: uin=" ",uin=" ",非必须 - * @param {String} params.GrantWrite 赋予被授权者写的权限,格式x-cos-grant-write: uin=" ",uin=" ",非必须 - * @param {String} params.GrantFullControl 赋予被授权者读写权限,格式x-cos-grant-full-control: uin=" ",uin=" ",非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ -function putBucketAcl(params, callback) { - var headers = params.Headers; - - var xml = ''; - if (params['AccessControlPolicy']) { - var AccessControlPolicy = util.clone(params['AccessControlPolicy'] || {}); - var Grants = AccessControlPolicy.Grants || AccessControlPolicy.Grant; - Grants = util.isArray(Grants) ? Grants : [Grants]; - delete AccessControlPolicy.Grant; - delete AccessControlPolicy.Grants; - AccessControlPolicy.AccessControlList = {Grant: Grants}; - xml = util.json2xml({AccessControlPolicy: AccessControlPolicy}); - - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - } - - // Grant Header 去重 - util.each(headers, function (val, key) { - if (key.indexOf('x-cos-grant-') === 0) { - headers[key] = uniqGrant(headers[key]); - } - }); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketACL', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - headers: headers, - action: 'acl', - body: xml, - }, function (err, data) { - if (err) return callback(err); - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的 权限列表 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {Object} data.AccessControlPolicy 访问权限信息 - */ -function getBucketAcl(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:GetBucketACL', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'acl', - }, function (err, data) { - if (err) return callback(err); - var AccessControlPolicy = data.AccessControlPolicy || {}; - var Owner = AccessControlPolicy.Owner || {}; - var Grant = AccessControlPolicy.AccessControlList.Grant || []; - Grant = util.isArray(Grant) ? Grant : [Grant]; - var result = decodeAcl(AccessControlPolicy); - if (data.headers && data.headers['x-cos-acl']) { - result.ACL = data.headers['x-cos-acl']; - } - result = util.extend(result, { - Owner: Owner, - Grants: Grant, - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); -} - -/** - * 设置 Bucket 的 跨域设置 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Object} params.CORSConfiguration 相关的跨域设置,必须 - * @param {Array} params.CORSConfiguration.CORSRules 对应的跨域规则 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ -function putBucketCors(params, callback) { - - var CORSConfiguration = params['CORSConfiguration'] || {}; - var CORSRules = CORSConfiguration['CORSRules'] || params['CORSRules'] || []; - CORSRules = util.clone(util.isArray(CORSRules) ? CORSRules : [CORSRules]); - util.each(CORSRules, function (rule) { - util.each(['AllowedOrigin', 'AllowedHeader', 'AllowedMethod', 'ExposeHeader'], function (key) { - var sKey = key + 's'; - var val = rule[sKey] || rule[key] || []; - delete rule[sKey]; - rule[key] = util.isArray(val) ? val : [val]; - }); - }); - - var xml = util.json2xml({CORSConfiguration: {CORSRule: CORSRules}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketCORS', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'cors', - headers: headers, - }, function (err, data) { - if (err) return callback(err); - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的 跨域设置 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {Object} data.CORSRules Bucket的跨域设置 - */ -function getBucketCors(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketCORS', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'cors', - }, function (err, data) { - if (err) { - if (err.statusCode === 404 && err.error && err.error.Code === 'NoSuchCORSConfiguration') { - var result = { - CORSRules: [], - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; - } - var CORSConfiguration = data.CORSConfiguration || {}; - var CORSRules = CORSConfiguration.CORSRules || CORSConfiguration.CORSRule || []; - CORSRules = util.clone(util.isArray(CORSRules) ? CORSRules : [CORSRules]); - - util.each(CORSRules, function (rule) { - util.each(['AllowedOrigin', 'AllowedHeader', 'AllowedMethod', 'ExposeHeader'], function (key) { - var sKey = key + 's'; - var val = rule[sKey] || rule[key] || []; - delete rule[key]; - rule[sKey] = util.isArray(val) ? val : [val]; - }); - }); - - callback(null, { - CORSRules: CORSRules, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 删除 Bucket 的 跨域设置 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ -function deleteBucketCors(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketCORS', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'cors', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode || err.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的 地域信息 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据,包含地域信息 LocationConstraint - */ -function getBucketLocation(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketLocation', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'location', - }, function (err, data) { - if (err) return callback(err); - callback(null, data); - }); -} - -function putBucketPolicy(params, callback) { - var Policy = params['Policy']; - var PolicyStr = Policy; - try { - if (typeof Policy === 'string') { - Policy = JSON.parse(PolicyStr); - } else { - PolicyStr = JSON.stringify(Policy); - } - } catch (e) { - callback({error: 'Policy format error'}); - } - - var headers = params.Headers; - headers['Content-Type'] = 'application/json'; - headers['Content-MD5'] = util.binaryBase64(util.md5(PolicyStr)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketPolicy', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - action: 'policy', - body: PolicyStr, - headers: headers, - json: true, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的读取权限策略 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function getBucketPolicy(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketPolicy', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'policy', - rawBody: true, - }, function (err, data) { - if (err) { - if (err.statusCode && err.statusCode === 403) { - return callback({ErrorStatus: 'Access Denied'}); - } - if (err.statusCode && err.statusCode === 405) { - return callback({ErrorStatus: 'Method Not Allowed'}); - } - if (err.statusCode && err.statusCode === 404) { - return callback({ErrorStatus: 'Policy Not Found'}); - } - return callback(err); - } - var Policy = {}; - try { - Policy = JSON.parse(data.body); - } catch (e) { - } - callback(null, { - Policy: Policy, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 删除 Bucket 的 跨域设置 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ -function deleteBucketPolicy(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketPolicy', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'policy', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode || err.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 设置 Bucket 的标签 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Array} params.TagSet 标签设置,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function putBucketTagging(params, callback) { - - var Tagging = params['Tagging'] || {}; - var Tags = Tagging.TagSet || Tagging.Tags || params['Tags'] || []; - Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); - var xml = util.json2xml({Tagging: {TagSet: {Tag: Tags}}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketTagging', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'tagging', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的标签设置 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function getBucketTagging(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:GetBucketTagging', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'tagging', - }, function (err, data) { - if (err) { - if (err.statusCode === 404 && err.error && (err.error === "Not Found" || err.error.Code === 'NoSuchTagSet')) { - var result = { - Tags: [], - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; - } - var Tags = []; - try { - Tags = data.Tagging.TagSet.Tag || []; - } catch (e) { - } - Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); - callback(null, { - Tags: Tags, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 删除 Bucket 的 标签设置 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ -function deleteBucketTagging(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketTagging', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'tagging', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -function putBucketLifecycle(params, callback) { - - var LifecycleConfiguration = params['LifecycleConfiguration'] || {}; - var Rules = LifecycleConfiguration.Rules || params.Rules || []; - Rules = util.clone(Rules); - var xml = util.json2xml({LifecycleConfiguration: {Rule: Rules}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketLifecycle', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'lifecycle', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -function getBucketLifecycle(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketLifecycle', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'lifecycle', - }, function (err, data) { - if (err) { - if (err.statusCode === 404 && err.error && err.error.Code === 'NoSuchLifecycleConfiguration') { - var result = { - Rules: [], - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; - } - var Rules = []; - try { - Rules = data.LifecycleConfiguration.Rule || []; - } catch (e) { - } - Rules = util.clone(util.isArray(Rules) ? Rules : [Rules]); - callback(null, { - Rules: Rules, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -function deleteBucketLifecycle(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketLifecycle', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'lifecycle', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -function putBucketVersioning(params, callback) { - - if (!params['VersioningConfiguration']) { - callback({error: 'missing param VersioningConfiguration'}); - return; - } - var VersioningConfiguration = params['VersioningConfiguration'] || {}; - var xml = util.json2xml({VersioningConfiguration: VersioningConfiguration}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketVersioning', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'versioning', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -function getBucketVersioning(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketVersioning', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'versioning', - }, function (err, data) { - if (!err) { - !data.VersioningConfiguration && (data.VersioningConfiguration = {}); - } - callback(err, data); - }); -} - -function putBucketReplication(params, callback) { - var ReplicationConfiguration = util.clone(params.ReplicationConfiguration); - var xml = util.json2xml({ReplicationConfiguration: ReplicationConfiguration}); - xml = xml.replace(/<(\/?)Rules>/ig, '<$1Rule>'); - xml = xml.replace(/<(\/?)Tags>/ig, '<$1Tag>'); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketReplication', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'replication', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -function getBucketReplication(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketReplication', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'replication', - }, function (err, data) { - if (err) { - if (err.statusCode === 404 && err.error && (err.error === 'Not Found' || err.error.Code === 'ReplicationConfigurationnotFoundError')) { - var result = { - ReplicationConfiguration: {Rules: []}, - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; - } - if (!err) { - !data.ReplicationConfiguration && (data.ReplicationConfiguration = {}); - } - if (data.ReplicationConfiguration.Rule) { - data.ReplicationConfiguration.Rules = data.ReplicationConfiguration.Rule; - delete data.ReplicationConfiguration.Rule; - } - callback(err, data); - }); -} - -function deleteBucketReplication(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketReplication', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'replication', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 设置 Bucket 静态网站配置信息 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Object} params.WebsiteConfiguration 地域名称,必须 - * @param {Object} WebsiteConfiguration.IndexDocument 索引文档,必须 - * @param {Object} WebsiteConfiguration.ErrorDocument 错误文档,非必须 - * @param {Object} WebsiteConfiguration.RedirectAllRequestsTo 重定向所有请求,非必须 - * @param {Array} params.RoutingRules 重定向规则,非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function putBucketWebsite(params, callback) { - - if (!params['WebsiteConfiguration']) { - callback({ error: 'missing param WebsiteConfiguration' }); - return; - } - - var WebsiteConfiguration = util.clone(params['WebsiteConfiguration'] || {}); - var RoutingRules = WebsiteConfiguration['RoutingRules'] || WebsiteConfiguration['RoutingRule'] || []; - RoutingRules = util.isArray(RoutingRules) ? RoutingRules : [RoutingRules]; - delete WebsiteConfiguration.RoutingRule; - delete WebsiteConfiguration.RoutingRules; - if (RoutingRules.length) WebsiteConfiguration.RoutingRules = { RoutingRule: RoutingRules }; - var xml = util.json2xml({ WebsiteConfiguration: WebsiteConfiguration }); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketWebsite', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'website', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的静态网站配置信息 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function getBucketWebsite(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:GetBucketWebsite', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - action: 'website', - }, function (err, data) { - if (err) { - if(err.statusCode === 404 && err.error.Code === 'NoSuchWebsiteConfiguration'){ - var result = { - WebsiteConfiguration: {}, - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; - } - - var WebsiteConfiguration = data.WebsiteConfiguration || {}; - if (WebsiteConfiguration['RoutingRules']) { - var RoutingRules = util.clone(WebsiteConfiguration['RoutingRules'].RoutingRule || []); - RoutingRules = util.makeArray(RoutingRules); - WebsiteConfiguration.RoutingRules = RoutingRules; - } - - callback(null, { - WebsiteConfiguration: WebsiteConfiguration, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 删除 Bucket 的静态网站配置 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function deleteBucketWebsite(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketWebsite', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'website', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 设置 Bucket 的防盗链白名单或者黑名单 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Object} params.RefererConfiguration 地域名称,必须 - * @param {String} RefererConfiguration.Status 是否开启防盗链,枚举值:Enabled、Disabled - * @param {String} RefererConfiguration.RefererType 防盗链类型,枚举值:Black-List、White-List,必须 - * @param {Array} RefererConfiguration.DomianList.Domain 生效域名,必须 - * @param {String} RefererConfiguration.EmptyReferConfiguration ,非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function putBucketReferer(params, callback) { - - if (!params['RefererConfiguration']) { - callback({ error: 'missing param RefererConfiguration' }); - return; - } - - var RefererConfiguration = util.clone(params['RefererConfiguration'] || {}); - var DomainList = RefererConfiguration['DomainList'] || {}; - var Domains = DomainList['Domains'] || DomainList['Domain'] || []; - Domains = util.isArray(Domains) ? Domains : [Domains]; - if (Domains.length) RefererConfiguration.DomainList = {Domain: Domains}; - var xml = util.json2xml({ RefererConfiguration: RefererConfiguration }); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketReferer', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'referer', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的防盗链白名单或者黑名单 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function getBucketReferer(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:GetBucketReferer', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - action: 'referer', - }, function (err, data) { - if (err) { - if(err.statusCode === 404 && err.error.Code === 'NoSuchRefererConfiguration'){ - var result = { - WebsiteConfiguration: {}, - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; - } - - var RefererConfiguration = data.RefererConfiguration || {}; - if (RefererConfiguration['DomainList']) { - var Domains = util.clone(RefererConfiguration['DomainList'].Domain || []); - Domains = util.makeArray(Domains); - RefererConfiguration.DomainList = {Domains: Domains}; - } - - callback(null, { - RefererConfiguration: RefererConfiguration, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 设置 Bucket 自定义域名 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function putBucketDomain(params, callback) { - - var DomainConfiguration = params['DomainConfiguration'] || {}; - var DomainRule = DomainConfiguration.DomainRule || params.DomainRule || []; - DomainRule = util.clone(DomainRule); - var xml = util.json2xml({DomainConfiguration: {DomainRule: DomainRule}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketDomain', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'domain', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的自定义域名 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function getBucketDomain(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:GetBucketDomain', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'domain', - }, function (err, data) { - if (err) return callback(err); - - var DomainRule = []; - try { - DomainRule = data.DomainConfiguration.DomainRule || []; - } catch (e) { - } - DomainRule = util.clone(util.isArray(DomainRule) ? DomainRule : [DomainRule]); - callback(null, { - DomainRule: DomainRule, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 删除 Bucket 自定义域名 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function deleteBucketDomain(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketDomain', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'domain', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 设置 Bucket 的回源 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function putBucketOrigin(params, callback){ - var OriginConfiguration = params['OriginConfiguration'] || {}; - var OriginRule = OriginConfiguration.OriginRule || params.OriginRule || []; - OriginRule = util.clone(OriginRule); - var xml = util.json2xml({OriginConfiguration: {OriginRule: OriginRule}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketOrigin', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'origin', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的回源 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function getBucketOrigin(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:GetBucketOrigin', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'origin', - }, function (err, data) { - if (err) return callback(err); - - var OriginRule = []; - try { - OriginRule = data.OriginConfiguration.OriginRule || []; - } catch (e) { - } - OriginRule = util.clone(util.isArray(OriginRule) ? OriginRule : [OriginRule]); - callback(null, { - OriginRule: OriginRule, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 删除 Bucket 的回源 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function deleteBucketOrigin(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketOrigin', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'origin', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 设置 Bucket 的日志记录 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {(Object|String)} params.BucketLoggingStatus 说明日志记录配置的状态,如果无子节点信息则意为关闭日志记录,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function putBucketLogging(params, callback) { - var xml = util.json2xml({ - BucketLoggingStatus: params['BucketLoggingStatus'] || '' - }); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketLogging', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'logging', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的日志记录 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function getBucketLogging(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketLogging', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'logging', - }, function (err, data) { - if (err) return callback(err); - delete data.BucketLoggingStatus._xmlns; - callback(null, { - BucketLoggingStatus: data.BucketLoggingStatus, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 创建/编辑 Bucket 的清单任务 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Id 清单任务的名称,必须 - * @param {Object} params.InventoryConfiguration 包含清单的配置参数,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function putBucketInventory(params, callback) { - var InventoryConfiguration = util.clone(params['InventoryConfiguration']); - - if (InventoryConfiguration.OptionalFields) { - var Field = InventoryConfiguration.OptionalFields || []; - InventoryConfiguration.OptionalFields = { - Field: Field - }; - } - - if (InventoryConfiguration.Destination - && InventoryConfiguration.Destination.COSBucketDestination - && InventoryConfiguration.Destination.COSBucketDestination.Encryption - ) { - var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption; - if (Object.keys(Encryption).indexOf('SSECOS') > -1) { - Encryption['SSE-COS'] = Encryption['SSECOS']; - delete Encryption['SSECOS']; - } - } - - var xml = util.json2xml({ - InventoryConfiguration: InventoryConfiguration - }); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketInventory', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'inventory', - qs: { - id: params['Id'] - }, - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的清单任务信息 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Id 清单任务的名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function getBucketInventory(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketInventory', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'inventory', - qs: { - id: params['Id'] - } - }, function (err, data) { - if (err) return callback(err); - - var InventoryConfiguration = data['InventoryConfiguration']; - if (InventoryConfiguration && InventoryConfiguration.OptionalFields && InventoryConfiguration.OptionalFields.Field) { - var Field = InventoryConfiguration.OptionalFields.Field; - if (!util.isArray(Field)) { - Field = [Field]; - } - InventoryConfiguration.OptionalFields = Field; - } - if (InventoryConfiguration.Destination - && InventoryConfiguration.Destination.COSBucketDestination - && InventoryConfiguration.Destination.COSBucketDestination.Encryption - ) { - var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption; - if (Object.keys(Encryption).indexOf('SSE-COS') > -1) { - Encryption['SSECOS'] = Encryption['SSE-COS']; - delete Encryption['SSE-COS']; - } - } - - callback(null, { - InventoryConfiguration: InventoryConfiguration, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的清单任务信息 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.ContinuationToken 当 COS 响应体中 IsTruncated 为 true,且 NextContinuationToken 节点中存在参数值时,您可以将这个参数作为 continuation-token 参数值,以获取下一页的清单任务信息,非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function listBucketInventory(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:ListBucketInventory', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'inventory', - qs: { - 'continuation-token': params['ContinuationToken'] - } - }, function (err, data) { - if (err) return callback(err); - var ListInventoryConfigurationResult = data['ListInventoryConfigurationResult']; - var InventoryConfigurations = ListInventoryConfigurationResult.InventoryConfiguration || []; - InventoryConfigurations = util.isArray(InventoryConfigurations) ? InventoryConfigurations : [InventoryConfigurations]; - delete ListInventoryConfigurationResult['InventoryConfiguration']; - util.each(InventoryConfigurations, function (InventoryConfiguration) { - if (InventoryConfiguration && InventoryConfiguration.OptionalFields && InventoryConfiguration.OptionalFields.Field) { - var Field = InventoryConfiguration.OptionalFields.Field; - if (!util.isArray(Field)) { - Field = [Field]; - } - InventoryConfiguration.OptionalFields = Field; - } - - if (InventoryConfiguration.Destination - && InventoryConfiguration.Destination.COSBucketDestination - && InventoryConfiguration.Destination.COSBucketDestination.Encryption - ) { - var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption; - if (Object.keys(Encryption).indexOf('SSE-COS') > -1) { - Encryption['SSECOS'] = Encryption['SSE-COS']; - delete Encryption['SSE-COS']; - } - } - }); - ListInventoryConfigurationResult.InventoryConfigurations = InventoryConfigurations; - util.extend(ListInventoryConfigurationResult, { - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, ListInventoryConfigurationResult); - }); -} - -/** - * 删除 Bucket 的清单任务 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Id 清单任务的名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function deleteBucketInventory(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketInventory', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'inventory', - qs: { - id: params['Id'] - } - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/* 全球加速 */ -function putBucketAccelerate(params, callback) { - - if (!params['AccelerateConfiguration']) { - callback({error: 'missing param AccelerateConfiguration'}); - return; - } - - var configuration = { AccelerateConfiguration: params.AccelerateConfiguration || {} }; - - var xml = util.json2xml(configuration); - - var headers = {}; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Interface: 'putBucketAccelerate', - Action: 'name/cos:PutBucketAccelerate', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'accelerate', - headers: headers, - }, function (err, data) { - if (err) return callback(err); - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -function getBucketAccelerate(params, callback) { - submitRequest.call(this, { - Interface: 'getBucketAccelerate', - Action: 'name/cos:GetBucketAccelerate', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - action: 'accelerate', - }, function (err, data) { - if (!err) { - !data.AccelerateConfiguration && (data.AccelerateConfiguration = {}); - } - callback(err, data); - }); -} - -// Object 相关 - -/** - * 取回对应Object的元数据,Head的权限与Get的权限一致 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key 文件名称,必须 - * @param {String} params.IfModifiedSince 当Object在指定时间后被修改,则返回对应Object元信息,否则返回304,非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 为指定 object 的元数据,如果设置了 IfModifiedSince ,且文件未修改,则返回一个对象,NotModified 属性为 true - * @return {Boolean} data.NotModified 是否在 IfModifiedSince 时间点之后未修改该 object,则为 true - */ -function headObject(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:HeadObject', - method: 'HEAD', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - VersionId: params.VersionId, - headers: params.Headers, - }, function (err, data) { - if (err) { - var statusCode = err.statusCode; - if (params.Headers['If-Modified-Since'] && statusCode && statusCode === 304) { - return callback(null, { - NotModified: true, - statusCode: statusCode, - }); - } - return callback(err); - } - data.ETag = util.attr(data.headers, 'etag', ''); - callback(null, data); - }); -} - - -function listObjectVersions(params, callback) { - var reqParams = {}; - reqParams['prefix'] = params['Prefix'] || ''; - reqParams['delimiter'] = params['Delimiter']; - reqParams['key-marker'] = params['KeyMarker']; - reqParams['version-id-marker'] = params['VersionIdMarker']; - reqParams['max-keys'] = params['MaxKeys']; - reqParams['encoding-type'] = params['EncodingType']; - - submitRequest.call(this, { - Action: 'name/cos:GetBucketObjectVersions', - ResourceKey: reqParams['prefix'], - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - qs: reqParams, - action: 'versions', - }, function (err, data) { - if (err) return callback(err); - var ListVersionsResult = data.ListVersionsResult || {}; - var DeleteMarkers = ListVersionsResult.DeleteMarker || []; - DeleteMarkers = util.isArray(DeleteMarkers) ? DeleteMarkers : [DeleteMarkers]; - var Versions = ListVersionsResult.Version || []; - Versions = util.isArray(Versions) ? Versions : [Versions]; - - var result = util.clone(ListVersionsResult); - delete result.DeleteMarker; - delete result.Version; - util.extend(result, { - DeleteMarkers: DeleteMarkers, - Versions: Versions, - statusCode: data.statusCode, - headers: data.headers, - }); - - callback(null, result); - }); -} - -/** - * 下载 object - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key 文件名称,必须 - * @param {WriteStream} params.Output 文件写入流,非必须 - * @param {String} params.IfModifiedSince 当Object在指定时间后被修改,则返回对应Object元信息,否则返回304,非必须 - * @param {String} params.IfUnmodifiedSince 如果文件修改时间早于或等于指定时间,才返回文件内容。否则返回 412 (precondition failed),非必须 - * @param {String} params.IfMatch 当 ETag 与指定的内容一致,才返回文件。否则返回 412 (precondition failed),非必须 - * @param {String} params.IfNoneMatch 当 ETag 与指定的内容不一致,才返回文件。否则返回304 (not modified),非必须 - * @param {String} params.ResponseContentType 设置返回头部中的 Content-Type 参数,非必须 - * @param {String} params.ResponseContentLanguage 设置返回头部中的 Content-Language 参数,非必须 - * @param {String} params.ResponseExpires 设置返回头部中的 Content-Expires 参数,非必须 - * @param {String} params.ResponseCacheControl 设置返回头部中的 Cache-Control 参数,非必须 - * @param {String} params.ResponseContentDisposition 设置返回头部中的 Content-Disposition 参数,非必须 - * @param {String} params.ResponseContentEncoding 设置返回头部中的 Content-Encoding 参数,非必须 - * @param {Function} callback 回调函数,必须 - * @param {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @param {Object} data 为对应的 object 数据,包括 body 和 headers - */ -function getObject(params, callback) { - var reqParams = params.Query || {}; - var reqParamsStr = params.QueryString || ''; - - reqParams['response-content-type'] = params['ResponseContentType']; - reqParams['response-content-language'] = params['ResponseContentLanguage']; - reqParams['response-expires'] = params['ResponseExpires']; - reqParams['response-cache-control'] = params['ResponseCacheControl']; - reqParams['response-content-disposition'] = params['ResponseContentDisposition']; - reqParams['response-content-encoding'] = params['ResponseContentEncoding']; - - // 如果用户自己传入了 output - submitRequest.call(this, { - Action: 'name/cos:GetObject', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - VersionId: params.VersionId, - headers: params.Headers, - qs: reqParams, - qsStr: reqParamsStr, - rawBody: true, - }, function (err, data) { - if (err) { - var statusCode = err.statusCode; - if (params.Headers['If-Modified-Since'] && statusCode && statusCode === 304) { - return callback(null, { - NotModified: true - }); - } - return callback(err); - } - callback(null, { - Body: data.body, - ETag: util.attr(data.headers, 'etag', ''), - statusCode: data.statusCode, - headers: data.headers, - }); - }); - -} - -/** - * 上传 object - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key 文件名称,必须 - * @param {String} params.Body 上传文件的内容,只支持字符串 - * @param {String} params.CacheControl RFC 2616 中定义的缓存策略,将作为 Object 元数据保存,非必须 - * @param {String} params.ContentDisposition RFC 2616 中定义的文件名称,将作为 Object 元数据保存,非必须 - * @param {String} params.ContentEncoding RFC 2616 中定义的编码格式,将作为 Object 元数据保存,非必须 - * @param {String} params.ContentLength RFC 2616 中定义的 HTTP 请求内容长度(字节),必须 - * @param {String} params.ContentType RFC 2616 中定义的内容类型(MIME),将作为 Object 元数据保存,非必须 - * @param {String} params.Expect 当使用 Expect: 100-continue 时,在收到服务端确认后,才会发送请求内容,非必须 - * @param {String} params.Expires RFC 2616 中定义的过期时间,将作为 Object 元数据保存,非必须 - * @param {String} params.ContentSha1 RFC 3174 中定义的 160-bit 内容 SHA-1 算法校验,非必须 - * @param {String} params.ACL 允许用户自定义文件权限,有效值:private | public-read,非必须 - * @param {String} params.GrantRead 赋予被授权者读的权限,格式 x-cos-grant-read: uin=" ",uin=" ",非必须 - * @param {String} params.GrantWrite 赋予被授权者写的权限,格式 x-cos-grant-write: uin=" ",uin=" ",非必须 - * @param {String} params.GrantFullControl 赋予被授权者读写权限,格式 x-cos-grant-full-control: uin=" ",uin=" ",非必须 - * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须 - * @param {Function} params.onProgress 上传进度回调函数 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 为对应的 object 数据 - * @return {String} data.ETag 为对应上传文件的 ETag 值 - */ -function putObject(params, callback) { - var self = this; - var FileSize = params.ContentLength; - var onProgress = util.throttleOnProgress.call(self, FileSize, params.onProgress); - - // 特殊处理 Cache-Control、Content-Type,避免代理更改这两个字段导致写入到 Object 属性里 - var headers = params.Headers; - if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = ''; - if (!headers['Content-Type'] && !headers['content-type']) headers['Content-Type'] = mime.getType(params.Key) || 'application/octet-stream'; - - util.getBodyMd5(self.options.UploadCheckContentMd5, params.Body, function (md5) { - if (md5) headers['Content-MD5'] = util.binaryBase64(md5); - if (params.ContentLength !== undefined) headers['Content-Length'] = params.ContentLength; - onProgress(null, true); // 任务状态开始 uploading - submitRequest.call(self, { - Action: 'name/cos:PutObject', - TaskId: params.TaskId, - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - qs: params.Query, - body: params.Body, - onProgress: onProgress, - }, function (err, data) { - if (err) { - onProgress(null, true); - return callback(err); - } - onProgress({loaded: FileSize, total: FileSize}, true); - var url = getUrl({ - ForcePathStyle: self.options.ForcePathStyle, - protocol: self.options.Protocol, - domain: self.options.Domain, - bucket: params.Bucket, - region: !self.options.UseAccelerate ? params.Region : 'accelerate', - object: params.Key, - }); - url = url.substr(url.indexOf('://') + 3); - data.Location = url; - data.ETag = util.attr(data.headers, 'etag', ''); - callback(null, data); - }); - }); -} - -/** - * 上传 object - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key 文件名称,必须 - * @param {FilePath} params.FilePath 要上传的文件路径 - * @param {Function} params.onProgress 上传进度回调函数 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 为对应的 object 数据 - * @return {String} data.ETag 为对应上传文件的 ETag 值 - */ -function postObject(params, callback) { - var self = this; - var headers = {}; - var filePath = params.FilePath; - if (!filePath) { - callback({error: 'missing param FilePath'}); - return; - } - - headers['Cache-Control'] = params['CacheControl']; - headers['Content-Disposition'] = params['ContentDisposition']; - headers['Content-Encoding'] = params['ContentEncoding']; - headers['Content-MD5'] = params['ContentMD5']; - headers['Content-Length'] = params['ContentLength']; - headers['Content-Type'] = params['ContentType']; - headers['Expect'] = params['Expect']; - headers['Expires'] = params['Expires']; - headers['x-cos-acl'] = params['ACL']; - headers['x-cos-grant-read'] = params['GrantRead']; - headers['x-cos-grant-write'] = params['GrantWrite']; - headers['x-cos-grant-full-control'] = params['GrantFullControl']; - headers['x-cos-storage-class'] = params['StorageClass']; - - // 删除 Content-Length 避免签名错误 - delete headers['Content-Length']; - delete headers['content-length']; - - for (var key in params) { - if (key.indexOf('x-cos-meta-') > -1) { - headers[key] = params[key]; - } - } - - var onProgress = util.throttleOnProgress.call(self, headers['Content-Length'], params.onProgress); - - submitRequest.call(this, { - Action: 'name/cos:PostObject', - method: 'POST', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: headers, - qs: params.Query, - filePath: filePath, - onProgress: onProgress, - }, function (err, data) { - onProgress(null, true); - if (err) return callback(err); - if (data && data.headers) { - var headers = data.headers; - var ETag = headers.etag || headers.Etag || headers.ETag || ''; - var filename = filePath.substr(filePath.lastIndexOf('/') + 1); - var url = getUrl({ - ForcePathStyle: self.options.ForcePathStyle, - protocol: self.options.Protocol, - domain: self.options.Domain, - bucket: params.Bucket, - region: params.Region, - object: params.Key.replace(/\$\{filename\}/g, filename), - isLocation: true, - }); - - return callback(null, { - Location: url, - statusCode: data.statusCode, - headers: headers, - ETag: ETag, - }); - } - callback(null, data); - }); -} - -/** - * 删除 object - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {Function} callback 回调函数,必须 - * @param {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @param {Object} data 删除操作成功之后返回的数据 - */ -function deleteObject(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteObject', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - VersionId: params.VersionId, - }, function (err, data) { - if (err) { - var statusCode = err.statusCode; - if (statusCode && statusCode === 204) { - return callback(null, {statusCode: statusCode}); - } else if (statusCode && statusCode === 404) { - return callback(null, {BucketNotFound: true, statusCode: statusCode,}); - } else { - return callback(err); - } - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 object 的 权限列表 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {Object} data.AccessControlPolicy 权限列表 - */ -function getObjectAcl(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:GetObjectACL', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - action: 'acl', - }, function (err, data) { - if (err) return callback(err); - var AccessControlPolicy = data.AccessControlPolicy || {}; - var Owner = AccessControlPolicy.Owner || {}; - var Grant = AccessControlPolicy.AccessControlList && AccessControlPolicy.AccessControlList.Grant || []; - Grant = util.isArray(Grant) ? Grant : [Grant]; - var result = decodeAcl(AccessControlPolicy); - if (data.headers && data.headers['x-cos-acl']) { - result.ACL = data.headers['x-cos-acl']; - } - result = util.extend(result, { - Owner: Owner, - Grants: Grant, - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); -} - -/** - * 设置 object 的 权限列表 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ -function putObjectAcl(params, callback) { - var headers = params.Headers; - - var xml = ''; - if (params['AccessControlPolicy']) { - var AccessControlPolicy = util.clone(params['AccessControlPolicy'] || {}); - var Grants = AccessControlPolicy.Grants || AccessControlPolicy.Grant; - Grants = util.isArray(Grants) ? Grants : [Grants]; - delete AccessControlPolicy.Grant; - delete AccessControlPolicy.Grants; - AccessControlPolicy.AccessControlList = {Grant: Grants}; - xml = util.json2xml({AccessControlPolicy: AccessControlPolicy}); - - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - } - - // Grant Header 去重 - util.each(headers, function (val, key) { - if (key.indexOf('x-cos-grant-') === 0) { - headers[key] = uniqGrant(headers[key]); - } - }); - - submitRequest.call(this, { - Action: 'name/cos:PutObjectACL', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - action: 'acl', - headers: headers, - body: xml, - }, function (err, data) { - if (err) return callback(err); - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * Options Object请求实现跨域访问的预请求。即发出一个 OPTIONS 请求给服务器以确认是否可以进行跨域操作。 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ -function optionsObject(params, callback) { - - var headers = params.Headers; - headers['Origin'] = params['Origin']; - headers['Access-Control-Request-Method'] = params['AccessControlRequestMethod']; - headers['Access-Control-Request-Headers'] = params['AccessControlRequestHeaders']; - - submitRequest.call(this, { - Action: 'name/cos:OptionsObject', - method: 'OPTIONS', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: headers, - }, function (err, data) { - if (err) { - if (err.statusCode && err.statusCode === 403) { - return callback(null, { - OptionsForbidden: true, - statusCode: err.statusCode - }); - } - return callback(err); - } - - var headers = data.headers || {}; - callback(null, { - AccessControlAllowOrigin: headers['access-control-allow-origin'], - AccessControlAllowMethods: headers['access-control-allow-methods'], - AccessControlAllowHeaders: headers['access-control-allow-headers'], - AccessControlExposeHeaders: headers['access-control-expose-headers'], - AccessControlMaxAge: headers['access-control-max-age'], - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * @param {Object} 参数列表 - * @param {String} Bucket Bucket 名称 - * @param {String} Region 地域名称 - * @param {String} Key 文件名称 - * @param {String} CopySource 源文件URL绝对路径,可以通过versionid子资源指定历史版本 - * @param {String} ACL 允许用户自定义文件权限。有效值:private,public-read默认值:private。 - * @param {String} GrantRead 赋予被授权者读的权限,格式 x-cos-grant-read: uin=" ",uin=" ",当需要给子账户授权时,uin="RootAcountID/SubAccountID",当需要给根账户授权时,uin="RootAcountID"。 - * @param {String} GrantWrite 赋予被授权者写的权限,格式 x-cos-grant-write: uin=" ",uin=" ",当需要给子账户授权时,uin="RootAcountID/SubAccountID",当需要给根账户授权时,uin="RootAcountID"。 - * @param {String} GrantFullControl 赋予被授权者读写权限,格式 x-cos-grant-full-control: uin=" ",uin=" ",当需要给子账户授权时,uin="RootAcountID/SubAccountID",当需要给根账户授权时,uin="RootAcountID"。 - * @param {String} MetadataDirective 是否拷贝元数据,枚举值:Copy, Replaced,默认值Copy。假如标记为Copy,忽略Header中的用户元数据信息直接复制;假如标记为Replaced,按Header信息修改元数据。当目标路径和原路径一致,即用户试图修改元数据时,必须为Replaced - * @param {String} CopySourceIfModifiedSince 当Object在指定时间后被修改,则执行操作,否则返回412。可与x-cos-copy-source-If-None-Match一起使用,与其他条件联合使用返回冲突。 - * @param {String} CopySourceIfUnmodifiedSince 当Object在指定时间后未被修改,则执行操作,否则返回412。可与x-cos-copy-source-If-Match一起使用,与其他条件联合使用返回冲突。 - * @param {String} CopySourceIfMatch 当Object的ETag和给定一致时,则执行操作,否则返回412。可与x-cos-copy-source-If-Unmodified-Since一起使用,与其他条件联合使用返回冲突。 - * @param {String} CopySourceIfNoneMatch 当Object的ETag和给定不一致时,则执行操作,否则返回412。可与x-cos-copy-source-If-Modified-Since一起使用,与其他条件联合使用返回冲突。 - * @param {String} StorageClass 存储级别,枚举值:存储级别,枚举值:Standard, Standard_IA,Archive;默认值:Standard - * @param {String} CacheControl 指定所有缓存机制在整个请求/响应链中必须服从的指令。 - * @param {String} ContentDisposition MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件 - * @param {String} ContentEncoding HTTP 中用来对「采用何种编码格式传输正文」进行协定的一对头部字段 - * @param {String} ContentLength 设置响应消息的实体内容的大小,单位为字节 - * @param {String} ContentType RFC 2616 中定义的 HTTP 请求内容类型(MIME),例如text/plain - * @param {String} Expect 请求的特定的服务器行为 - * @param {String} Expires 响应过期的日期和时间 - * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须 - * @param {String} ContentLanguage 指定内容语言 - * @param {String} x-cos-meta-* 允许用户自定义的头部信息,将作为 Object 元数据返回。大小限制2K。 - */ -function putObjectCopy(params, callback) { - - // 特殊处理 Cache-Control - var headers = params.Headers; - if (!headers['Cache-Control'] && !!headers['cache-control']) headers['Cache-Control'] = ''; - - var CopySource = params.CopySource || ''; - var m = CopySource.match(/^([^.]+-\d+)\.cos(v6)?\.([^.]+)\.[^/]+\/(.+)$/); - if (!m) { - callback({error: 'CopySource format error'}); - return; - } - - var SourceBucket = m[1]; - var SourceRegion = m[3]; - var SourceKey = decodeURIComponent(m[4]); - - submitRequest.call(this, { - Scope: [{ - action: 'name/cos:GetObject', - bucket: SourceBucket, - region: SourceRegion, - prefix: SourceKey, - }, { - action: 'name/cos:PutObject', - bucket: params.Bucket, - region: params.Region, - prefix: params.Key, - }], - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - VersionId: params.VersionId, - headers: params.Headers, - }, function (err, data) { - if (err) return callback(err); - var result = util.clone(data.CopyObjectResult || {}); - util.extend(result, { - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); -} - -function uploadPartCopy(params, callback) { - - var CopySource = params.CopySource || ''; - var m = CopySource.match(/^([^.]+-\d+)\.cos(v6)?\.([^.]+)\.[^/]+\/(.+)$/); - if (!m) { - callback({error: 'CopySource format error'}); - return; - } - - var SourceBucket = m[1]; - var SourceRegion = m[3]; - var SourceKey = decodeURIComponent(m[4]); - - submitRequest.call(this, { - Scope: [{ - action: 'name/cos:GetObject', - bucket: SourceBucket, - region: SourceRegion, - prefix: SourceKey, - }, { - action: 'name/cos:PutObject', - bucket: params.Bucket, - region: params.Region, - prefix: params.Key, - }], - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - VersionId: params.VersionId, - qs: { - partNumber: params['PartNumber'], - uploadId: params['UploadId'], - }, - headers: params.Headers, - }, function (err, data) { - if (err) return callback(err); - var result = util.clone(data.CopyPartResult || {}); - util.extend(result, { - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); -} - -function deleteMultipleObject(params, callback) { - var Objects = params.Objects || []; - var Quiet = params.Quiet; - Objects = util.isArray(Objects) ? Objects : [Objects]; - - var xml = util.json2xml({Delete: {Object: Objects, Quiet: Quiet || false}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - var Scope = util.map(Objects, function (v) { - return { - action: 'name/cos:DeleteObject', - bucket: params.Bucket, - region: params.Region, - prefix: v.Key, - }; - }); - - submitRequest.call(this, { - Scope: Scope, - method: 'POST', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'delete', - headers: headers, - }, function (err, data) { - if (err) return callback(err); - var DeleteResult = data.DeleteResult || {}; - var Deleted = DeleteResult.Deleted || []; - var Errors = DeleteResult.Error || []; - - Deleted = util.isArray(Deleted) ? Deleted : [Deleted]; - Errors = util.isArray(Errors) ? Errors : [Errors]; - - var result = util.clone(DeleteResult); - util.extend(result, { - Error: Errors, - Deleted: Deleted, - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); -} - -function restoreObject(params, callback) { - var headers = params.Headers; - if (!params['RestoreRequest']) { - callback({error: 'missing param RestoreRequest'}); - return; - } - - var RestoreRequest = params.RestoreRequest || {}; - var xml = util.json2xml({RestoreRequest: RestoreRequest}); - - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:RestoreObject', - method: 'POST', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - VersionId: params.VersionId, - body: xml, - action: 'restore', - headers: headers, - }, function (err, data) { - callback(err, data); - }); -} - -/** - * 设置 Object 的标签 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Object名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Array} params.TagSet 标签设置,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/42998 - * @return {Object} data 返回数据 - */ -function putObjectTagging(params, callback) { - - var Tagging = params['Tagging'] || {}; - var Tags = Tagging.TagSet || Tagging.Tags || params['Tags'] || []; - Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); - var xml = util.json2xml({Tagging: {TagSet: {Tag: Tags}}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Interface: 'putObjectTagging', - Action: 'name/cos:PutObjectTagging', - method: 'PUT', - Bucket: params.Bucket, - Key: params.Key, - Region: params.Region, - body: xml, - action: 'tagging', - headers: headers, - VersionId: params.VersionId, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Object 的标签设置 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/42998 - * @return {Object} data 返回数据 - */ -function getObjectTagging(params, callback) { - - submitRequest.call(this, { - Interface: 'getObjectTagging', - Action: 'name/cos:GetObjectTagging', - method: 'GET', - Key: params.Key, - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'tagging', - VersionId: params.VersionId, - }, function (err, data) { - if (err) { - if (err.statusCode === 404 && err.error && (err.error === "Not Found" || err.error.Code === 'NoSuchTagSet')) { - var result = { - Tags: [], - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; - } - var Tags = []; - try { - Tags = data.Tagging.TagSet.Tag || []; - } catch (e) { - } - Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); - callback(null, { - Tags: Tags, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 删除 Object 的 标签设置 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Object名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/42998 - * @return {Object} data 返回的数据 - */ -function deleteObjectTagging(params, callback) { - submitRequest.call(this, { - Interface: 'deleteObjectTagging', - Action: 'name/cos:DeleteObjectTagging', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - action: 'tagging', - VersionId: params.VersionId, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - - -// 分块上传 - - -/** - * 初始化分块上传 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {String} params.UploadId object名称,必须 - * @param {String} params.CacheControl RFC 2616 中定义的缓存策略,将作为 Object 元数据保存,非必须 - * @param {String} params.ContentDisposition RFC 2616 中定义的文件名称,将作为 Object 元数据保存 ,非必须 - * @param {String} params.ContentEncoding RFC 2616 中定义的编码格式,将作为 Object 元数据保存,非必须 - * @param {String} params.ContentType RFC 2616 中定义的内容类型(MIME),将作为 Object 元数据保存,非必须 - * @param {String} params.Expires RFC 2616 中定义的过期时间,将作为 Object 元数据保存,非必须 - * @param {String} params.ACL 允许用户自定义文件权限,非必须 - * @param {String} params.GrantRead 赋予被授权者读的权限 ,非必须 - * @param {String} params.GrantWrite 赋予被授权者写的权限 ,非必须 - * @param {String} params.GrantFullControl 赋予被授权者读写权限 ,非必须 - * @param {String} params.StorageClass 设置Object的存储级别,枚举值:Standard,Standard_IA,Archive,非必须 - * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ -function multipartInit(params, callback) { - - var self = this; - var headers = params.Headers; - - // 特殊处理 Cache-Control、Content-Type - if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = ''; - if (!headers['Content-Type'] && !headers['content-type']) headers['Content-Type'] = mime.getType(params.Key) || 'application/octet-stream'; - - submitRequest.call(self, { - Action: 'name/cos:InitiateMultipartUpload', - method: 'POST', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - action: 'uploads', - headers: params.Headers, - qs: params.Query, - }, function (err, data) { - if (err) return callback(err); - data = util.clone(data || {}); - if (data && data.InitiateMultipartUploadResult) { - return callback(null, util.extend(data.InitiateMultipartUploadResult, { - statusCode: data.statusCode, - headers: data.headers, - })); - } - callback(null, data); - }); -} - -/** - * 分块上传 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {String} params.Body 上传文件对象或字符串 - * @param {String} params.ContentLength RFC 2616 中定义的 HTTP 请求内容长度(字节),非必须 - * @param {String} params.Expect 当使用 Expect: 100-continue 时,在收到服务端确认后,才会发送请求内容,非必须 - * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须 - * @param {String} params.ContentSha1 RFC 3174 中定义的 160-bit 内容 SHA-1 算法校验值,非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {Object} data.ETag 返回的文件分块 sha1 值 - */ -function multipartUpload(params, callback) { - - var self = this; - util.getFileSize('multipartUpload', params, function () { - util.getBodyMd5(self.options.UploadCheckContentMd5, params.Body, function (md5) { - if (md5) params.Headers['Content-MD5'] = util.binaryBase64(md5); - submitRequest.call(self, { - Action: 'name/cos:UploadPart', - TaskId: params.TaskId, - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - qs: { - partNumber: params['PartNumber'], - uploadId: params['UploadId'], - }, - headers: params.Headers, - onProgress: params.onProgress, - body: params.Body || null - }, function (err, data) { - if (err) return callback(err); - callback(null, { - ETag: util.attr(data.headers, 'etag', {}), - statusCode: data.statusCode, - headers: data.headers, - }); - }); - }); - }); - -} - -/** - * 完成分块上传 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {Array} params.Parts 分块信息列表,必须 - * @param {String} params.Parts[i].PartNumber 块编号,必须 - * @param {String} params.Parts[i].ETag 分块的 sha1 校验值 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {Object} data.CompleteMultipartUpload 完成分块上传后的文件信息,包括Location, Bucket, Key 和 ETag - */ -function multipartComplete(params, callback) { - var self = this; - - var UploadId = params.UploadId; - - var Parts = params['Parts']; - - for (var i = 0, len = Parts.length; i < len; i++) { - if (Parts[i]['ETag'].indexOf('"') === 0) { - continue; - } - Parts[i]['ETag'] = '"' + Parts[i]['ETag'] + '"'; - } - - var xml = util.json2xml({CompleteMultipartUpload: {Part: Parts}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:CompleteMultipartUpload', - method: 'POST', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - qs: { - uploadId: UploadId - }, - body: xml, - headers: headers, - }, function (err, data) { - if (err) return callback(err); - var url = getUrl({ - ForcePathStyle: self.options.ForcePathStyle, - protocol: self.options.Protocol, - domain: self.options.Domain, - bucket: params.Bucket, - region: params.Region, - object: params.Key, - isLocation: true, - }); - var CompleteMultipartUploadResult = data.CompleteMultipartUploadResult || {}; - var result = util.extend(CompleteMultipartUploadResult, { - Location: url, - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); -} - -/** - * 分块上传任务列表查询 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Delimiter 定界符为一个符号,如果有Prefix,则将Prefix到delimiter之间的相同路径归为一类,定义为Common Prefix,然后列出所有Common Prefix。如果没有Prefix,则从路径起点开始,非必须 - * @param {String} params.EncodingType 规定返回值的编码方式,非必须 - * @param {String} params.Prefix 前缀匹配,用来规定返回的文件前缀地址,非必须 - * @param {String} params.MaxUploads 单次返回最大的条目数量,默认1000,非必须 - * @param {String} params.KeyMarker 与upload-id-marker一起使用
当upload-id-marker未被指定时,ObjectName字母顺序大于key-marker的条目将被列出
当upload-id-marker被指定时,ObjectName字母顺序大于key-marker的条目被列出,ObjectName字母顺序等于key-marker同时UploadId大于upload-id-marker的条目将被列出,非必须 - * @param {String} params.UploadIdMarker 与key-marker一起使用
当key-marker未被指定时,upload-id-marker将被忽略
当key-marker被指定时,ObjectName字母顺序大于key-marker的条目被列出,ObjectName字母顺序等于key-marker同时UploadId大于upload-id-marker的条目将被列出,非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {Object} data.ListMultipartUploadsResult 分块上传任务信息 - */ -function multipartList(params, callback) { - var reqParams = {}; - - reqParams['delimiter'] = params['Delimiter']; - reqParams['encoding-type'] = params['EncodingType']; - reqParams['prefix'] = params['Prefix'] || ''; - - reqParams['max-uploads'] = params['MaxUploads']; - - reqParams['key-marker'] = params['KeyMarker']; - reqParams['upload-id-marker'] = params['UploadIdMarker']; - - reqParams = util.clearKey(reqParams); - - submitRequest.call(this, { - Action: 'name/cos:ListMultipartUploads', - ResourceKey: reqParams['prefix'], - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - qs: reqParams, - action: 'uploads', - }, function (err, data) { - if (err) return callback(err); - - if (data && data.ListMultipartUploadsResult) { - var Upload = data.ListMultipartUploadsResult.Upload || []; - - var CommonPrefixes = data.ListMultipartUploadsResult.CommonPrefixes || []; - - CommonPrefixes = util.isArray(CommonPrefixes) ? CommonPrefixes : [CommonPrefixes]; - Upload = util.isArray(Upload) ? Upload : [Upload]; - - data.ListMultipartUploadsResult.Upload = Upload; - data.ListMultipartUploadsResult.CommonPrefixes = CommonPrefixes; - } - var result = util.clone(data.ListMultipartUploadsResult || {}); - util.extend(result, { - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); -} - -/** - * 上传的分块列表查询 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {String} params.UploadId 标示本次分块上传的ID,必须 - * @param {String} params.EncodingType 规定返回值的编码方式,非必须 - * @param {String} params.MaxParts 单次返回最大的条目数量,默认1000,非必须 - * @param {String} params.PartNumberMarker 默认以UTF-8二进制顺序列出条目,所有列出条目从marker开始,非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {Object} data.ListMultipartUploadsResult 分块信息 - */ -function multipartListPart(params, callback) { - var reqParams = {}; - - reqParams['uploadId'] = params['UploadId']; - reqParams['encoding-type'] = params['EncodingType']; - reqParams['max-parts'] = params['MaxParts']; - reqParams['part-number-marker'] = params['PartNumberMarker']; - - submitRequest.call(this, { - Action: 'name/cos:ListParts', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - qs: reqParams, - }, function (err, data) { - if (err) return callback(err); - var ListPartsResult = data.ListPartsResult || {}; - var Part = ListPartsResult.Part || []; - Part = util.isArray(Part) ? Part : [Part]; - - ListPartsResult.Part = Part; - var result = util.clone(ListPartsResult); - util.extend(result, { - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); -} - -/** - * 抛弃分块上传 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {String} params.UploadId 标示本次分块上传的ID,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ -function multipartAbort(params, callback) { - var reqParams = {}; - - reqParams['uploadId'] = params['UploadId']; - submitRequest.call(this, { - Action: 'name/cos:AbortMultipartUpload', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - qs: reqParams, - }, function (err, data) { - if (err) return callback(err); - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - - -/** - * cos 内置请求 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ - function request(params, callback) { - submitRequest.call(this, { - method: params.Method, - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - action: params.Action, - headers: params.Headers, - qs: params.Query, - body: params.Body, - }, function (err, data) { - if (err) return callback(err); - if (data && data.body) { - data.Body = data.body; - delete data.body; - } - callback(err, data); - }); -} - -/** - * 获取签名 - * @param {Object} params 参数对象,必须 - * @param {String} params.Method 请求方法,必须 - * @param {String} params.Key object名称,必须 - * @param {String} params.Expires 名超时时间,单位秒,可选 - * @return {String} data 返回签名字符串 - */ -function getAuth(params) { - var self = this; - return util.getAuth({ - SecretId: params.SecretId || this.options.SecretId || '', - SecretKey: params.SecretKey || this.options.SecretKey || '', - Method: params.Method, - Key: params.Key, - Query: params.Query, - Headers: params.Headers, - Expires: params.Expires, - SystemClockOffset: self.options.SystemClockOffset, - }); -} - -/** - * 获取文件下载链接 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {String} params.Method 请求的方法,可选 - * @param {String} params.Expires 签名超时时间,单位秒,可选 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ -function getObjectUrl(params, callback) { - var self = this; - var url = getUrl({ - ForcePathStyle: self.options.ForcePathStyle, - protocol: params.Protocol || self.options.Protocol, - domain: params.Domain || self.options.Domain, - bucket: params.Bucket, - region: params.Region, - object: params.Key, - }); - - var queryParamsStr = ''; - if(params.Query){ - queryParamsStr += util.obj2str(params.Query); - } - if(params.QueryString){ - queryParamsStr += (queryParamsStr ? '&' : '') + params.QueryString; - } - - var syncUrl = url; - if (params.Sign !== undefined && !params.Sign) { - queryParamsStr && (syncUrl += '?' + queryParamsStr); - callback(null, {Url: syncUrl}); - return syncUrl; - } - var AuthData = getAuthorizationAsync.call(this, { - Action: ((params.Method || '').toUpperCase() === 'PUT' ? 'name/cos:PutObject' : 'name/cos:GetObject'), - Bucket: params.Bucket || '', - Region: params.Region || '', - Method: params.Method || 'get', - Key: params.Key, - Expires: params.Expires, - }, function (err, AuthData) { - if (!callback) return; - if (err) { - callback(err); - return; - } - var signUrl = url; - signUrl += '?' + (AuthData.Authorization.indexOf('q-signature') > -1 ? - AuthData.Authorization : 'sign=' + encodeURIComponent(AuthData.Authorization)); - AuthData.XCosSecurityToken && (signUrl += '&x-cos-security-token=' + AuthData.XCosSecurityToken); - AuthData.ClientIP && (signUrl += '&clientIP=' + AuthData.ClientIP); - AuthData.ClientUA && (signUrl += '&clientUA=' + AuthData.ClientUA); - AuthData.Token && (signUrl += '&token=' + AuthData.Token); - queryParamsStr && (signUrl += '&' + queryParamsStr); - setTimeout(function () { - callback(null, {Url: signUrl}); - }); - }); - - if (AuthData) { - signUrl += '?' + AuthData.Authorization + - (AuthData.XCosSecurityToken ? '&x-cos-security-token=' + AuthData.XCosSecurityToken : ''); - queryParamsStr && (syncUrl += '&' + queryParamsStr); - } else { - queryParamsStr && (syncUrl += '?' + queryParamsStr); - } - return syncUrl; -} - - -/** - * 私有方法 - */ -function decodeAcl(AccessControlPolicy) { - var result = { - GrantFullControl: [], - GrantWrite: [], - GrantRead: [], - GrantReadAcp: [], - GrantWriteAcp: [], - ACL: '', - }; - var GrantMap = { - 'FULL_CONTROL': 'GrantFullControl', - 'WRITE': 'GrantWrite', - 'READ': 'GrantRead', - 'READ_ACP': 'GrantReadAcp', - 'WRITE_ACP': 'GrantWriteAcp', - }; - var AccessControlList = AccessControlPolicy && AccessControlPolicy.AccessControlList || {}; - var Grant = AccessControlList.Grant; - if (Grant) { - Grant = util.isArray(Grant) ? Grant : [Grant]; - } - var PublicAcl = {READ: 0, WRITE: 0, FULL_CONTROL: 0}; - Grant && Grant.length && util.each(Grant, function (item) { - if (item.Grantee.ID === 'qcs::cam::anyone:anyone' || item.Grantee.URI === 'http://cam.qcloud.com/groups/global/AllUsers') { - PublicAcl[item.Permission] = 1; - } else if (item.Grantee.ID !== AccessControlPolicy.Owner.ID) { - result[GrantMap[item.Permission]].push('id="' + item.Grantee.ID + '"'); - } - }); - if (PublicAcl.FULL_CONTROL || (PublicAcl.WRITE && PublicAcl.READ)) { - result.ACL = 'public-read-write'; - } else if (PublicAcl.READ) { - result.ACL = 'public-read'; - } else { - result.ACL = 'private'; - } - util.each(GrantMap, function (item) { - result[item] = uniqGrant(result[item].join(',')); - }); - return result; -} - -// Grant 去重 -function uniqGrant(str) { - var arr = str.split(','); - var exist = {}; - var i, item; - for (i = 0; i < arr.length; ) { - item = arr[i].trim(); - if (exist[item]) { - arr.splice(i, 1); - } else { - exist[item] = true; - arr[i] = item; - i++; - } - } - return arr.join(','); -} - -// 生成操作 url -function getUrl(params) { - var longBucket = params.bucket; - var shortBucket = longBucket.substr(0, longBucket.lastIndexOf('-')); - var appId = longBucket.substr(longBucket.lastIndexOf('-') + 1); - var domain = params.domain; - var region = params.region; - var object = params.object; - var protocol = 'https:'; - if (!domain) { - if (['cn-south', 'cn-south-2', 'cn-north', 'cn-east', 'cn-southwest', 'sg'].indexOf(region) > -1) { - domain = '{Region}.myqcloud.com'; - } else { - domain = 'cos.{Region}.myqcloud.com'; - } - if (!params.ForcePathStyle) { - domain = '{Bucket}.' + domain; - } - } - domain = domain.replace(/\{\{AppId\}\}/ig, appId) - .replace(/\{\{Bucket\}\}/ig, shortBucket) - .replace(/\{\{Region\}\}/ig, region) - .replace(/\{\{.*?\}\}/ig, ''); - domain = domain.replace(/\{AppId\}/ig, appId) - .replace(/\{BucketName\}/ig, shortBucket) - .replace(/\{Bucket\}/ig, longBucket) - .replace(/\{Region\}/ig, region) - .replace(/\{.*?\}/ig, ''); - if (!/^[a-zA-Z]+:\/\//.test(domain)) { - domain = protocol + '//' + domain; - } - - // 去掉域名最后的斜杆 - if (domain.slice(-1) === '/') { - domain = domain.slice(0, -1); - } - var url = domain; - - if (params.ForcePathStyle) { - url += '/' + longBucket; - } - url += '/'; - if (object) { - url += util.camSafeUrlEncode(object).replace(/%2F/g, '/'); - } - - if (params.isLocation) { - url = url.replace(/^https?:\/\//, ''); - } - return url; -} - -// 异步获取签名 -function getAuthorizationAsync(params, callback) { - - var headers = util.clone(params.Headers); - delete headers['Content-Type']; - delete headers['Cache-Control']; - util.each(headers, function (v, k) { - v === '' && delete headers[k]; - }); - - var cb = function (AuthData) { - - // 检查签名格式 - var formatAllow = false; - var auth = AuthData.Authorization; - if (auth) { - if (auth.indexOf(' ') > -1) { - formatAllow = false; - } else if (auth.indexOf('q-sign-algorithm=') > -1 && - auth.indexOf('q-ak=') > -1 && - auth.indexOf('q-sign-time=') > -1 && - auth.indexOf('q-key-time=') > -1 && - auth.indexOf('q-url-param-list=') > -1) { - formatAllow = true; - } else { - try { - auth = base64.atob(auth); - if (auth.indexOf('a=') > -1 && - auth.indexOf('k=') > -1 && - auth.indexOf('t=') > -1 && - auth.indexOf('r=') > -1 && - auth.indexOf('b=') > -1) { - formatAllow = true; - } - } catch (e) {} - } - } - if (formatAllow) { - callback && callback(null, AuthData); - } else { - callback && callback('authorization error'); - } - }; - - var self = this; - var Bucket = params.Bucket || ''; - var Region = params.Region || ''; - - // PathName - var KeyName = params.Action === 'name/cos:PostObject' || !params.Key ? '' : params.Key; - if (self.options.ForcePathStyle && Bucket) { - KeyName = Bucket + '/' + KeyName; - } - var Pathname = '/' + KeyName; - - // Action、ResourceKey - var StsData = {}; - var Scope = params.Scope; - if (!Scope) { - var Action = params.Action || ''; - var ResourceKey = params.ResourceKey || params.Key || ''; - Scope = params.Scope || [{ - action: Action, - bucket: Bucket, - region: Region, - prefix: ResourceKey, - }]; - } - var ScopeKey = util.md5(JSON.stringify(Scope)); - - // STS - self._StsCache = self._StsCache ||[]; - (function () { - var i, AuthData; - for (i = self._StsCache.length - 1; i >= 0; i--) { - AuthData = self._StsCache[i]; - var compareTime = Math.round(util.getSkewTime(self.options.SystemClockOffset) / 1000) + 30; - if (AuthData.StartTime && compareTime < AuthData.StartTime || compareTime >= AuthData.ExpiredTime) { - self._StsCache.splice(i, 1); - continue; - } - if (!AuthData.ScopeLimit || AuthData.ScopeLimit && AuthData.ScopeKey === ScopeKey) { - StsData = AuthData; - break; - } - } - })(); - - var calcAuthByTmpKey = function () { - var KeyTime = StsData.StartTime && StsData.ExpiredTime ? StsData.StartTime + ';' + StsData.ExpiredTime : ''; - var Authorization = util.getAuth({ - SecretId: StsData.TmpSecretId, - SecretKey: StsData.TmpSecretKey, - Method: params.Method, - Pathname: Pathname, - Query: params.Query, - Headers: headers, - Expires: params.Expires, - SystemClockOffset: self.options.SystemClockOffset, - KeyTime: KeyTime - }); - var AuthData = { - Authorization: Authorization, - XCosSecurityToken: StsData.XCosSecurityToken || '', - Token: StsData.Token || '', - ClientIP: StsData.ClientIP || '', - ClientUA: StsData.ClientUA || '', - }; - cb(AuthData); - }; - - // 先判断是否有临时密钥 - if (StsData.ExpiredTime && StsData.ExpiredTime - (util.getSkewTime(self.options.SystemClockOffset) / 1000) > 60) { // 如果缓存的临时密钥有效,并还有超过60秒有效期就直接使用 - calcAuthByTmpKey(); - } else if (self.options.getAuthorization) { // 外部计算签名或获取临时密钥 - self.options.getAuthorization.call(self, { - Bucket: Bucket, - Region: Region, - Method: params.Method, - Key: KeyName, - Pathname: Pathname, - Query: params.Query, - Headers: headers, - Scope: Scope, - SystemClockOffset: self.options.SystemClockOffset, - }, function (AuthData) { - if (typeof AuthData === 'string') { - AuthData = {Authorization: AuthData}; - } - if (AuthData.TmpSecretId && - AuthData.TmpSecretKey && - AuthData.XCosSecurityToken && - AuthData.ExpiredTime) { - StsData = AuthData || {}; - StsData.Scope = Scope; - StsData.ScopeKey = ScopeKey; - self._StsCache.push(StsData); - calcAuthByTmpKey(); - } else { - cb(AuthData); - } - }); - } else if (self.options.getSTS) { // 外部获取临时密钥 - self.options.getSTS.call(self, { - Bucket: Bucket, - Region: Region, - }, function (data) { - StsData = data || {}; - StsData.Scope = Scope; - StsData.ScopeKey = ScopeKey; - StsData.TmpSecretId = StsData.SecretId; - StsData.TmpSecretKey = StsData.SecretKey; - self._StsCache.push(StsData); - calcAuthByTmpKey(); - }); - } else { // 内部计算获取签名 - return (function () { - var Authorization = util.getAuth({ - SecretId: params.SecretId || self.options.SecretId, - SecretKey: params.SecretKey || self.options.SecretKey, - Method: params.Method, - Pathname: Pathname, - Query: params.Query, - Headers: headers, - Expires: params.Expires, - SystemClockOffset: self.options.SystemClockOffset, - }); - var AuthData = { - Authorization: Authorization, - XCosSecurityToken: self.options.XCosSecurityToken, - }; - cb(AuthData); - return AuthData; - })(); - } - return ''; -} - -// 调整时间偏差 -function allowRetry(err) { - var allowRetry = false; - var isTimeError = false; - var serverDate = (err.headers && (err.headers.date || err.headers.Date)) || (err.error && err.error.ServerTime); - try { - var errorCode = err.error.Code; - var errorMessage = err.error.Message; - if (errorCode === 'RequestTimeTooSkewed' || - (errorCode === 'AccessDenied' && errorMessage === 'Request has expired')) { - isTimeError = true; - } - } catch (e) { - } - if (err) { - if (isTimeError && serverDate) { - var serverTime = Date.parse(serverDate); - if (this.options.CorrectClockSkew && Math.abs(util.getSkewTime(this.options.SystemClockOffset) - serverTime) >= 30000) { - console.error('error: Local time is too skewed.'); - this.options.SystemClockOffset = serverTime - Date.now(); - allowRetry = true; - } - } else if (Math.floor(err.statusCode / 100) === 5) { - allowRetry = true; - } - } - return allowRetry; -} - -// 获取签名并发起请求 -function submitRequest(params, callback) { - var self = this; - - // 处理 headers - !params.headers && (params.headers = {}); - - // 处理 query - !params.qs && (params.qs = {}); - params.VersionId && (params.qs.versionId = params.VersionId); - params.qs = util.clearKey(params.qs); - - // 清理 undefined 和 null 字段 - params.headers && (params.headers = util.clearKey(params.headers)); - params.qs && (params.qs = util.clearKey(params.qs)); - - var Query = util.clone(params.qs); - params.action && (Query[params.action] = ''); - - var next = function (tryTimes) { - var oldClockOffset = self.options.SystemClockOffset; - getAuthorizationAsync.call(self, { - Bucket: params.Bucket || '', - Region: params.Region || '', - Method: params.method, - Key: params.Key, - Query: Query, - Headers: params.headers, - Action: params.Action, - ResourceKey: params.ResourceKey, - Scope: params.Scope, - }, function (err, AuthData) { - if (err) { - callback(err); - return; - } - params.AuthData = AuthData; - _submitRequest.call(self, params, function (err, data) { - if (err && tryTimes < 2 && (oldClockOffset !== self.options.SystemClockOffset || allowRetry.call(self, err))) { - if (params.headers) { - delete params.headers.Authorization; - delete params.headers['token']; - delete params.headers['clientIP']; - delete params.headers['clientUA']; - delete params.headers['x-cos-security-token']; - } - next(tryTimes + 1); - } else { - callback(err, data); - } - }); - }); - }; - next(1); - -} - -// 发起请求 -function _submitRequest(params, callback) { - var self = this; - var TaskId = params.TaskId; - if (TaskId && !self._isRunningTask(TaskId)) return; - - var bucket = params.Bucket; - var region = params.Region; - var object = params.Key; - var method = params.method || 'GET'; - var url = params.url; - var body = params.body; - var json = params.json; - var rawBody = params.rawBody; - - // url - if (self.options.UseAccelerate) { - region = 'accelerate'; - } - url = url || getUrl({ - ForcePathStyle: self.options.ForcePathStyle, - protocol: self.options.Protocol, - domain: self.options.Domain, - bucket: bucket, - region: region, - object: object, - }); - if (params.action) { - url = url + '?' + params.action; - } - if (params.qsStr) { - if(url.indexOf('?') > -1){ - url = url + '&' + params.qsStr; - }else{ - url = url + '?' + params.qsStr; - } - } - - var opt = { - method: method, - url: url, - headers: params.headers, - qs: params.qs, - filePath: params.filePath, - body: body, - json: json, - }; - - // 获取签名 - opt.headers.Authorization = params.AuthData.Authorization; - params.AuthData.Token && (opt.headers['token'] = params.AuthData.Token); - params.AuthData.ClientIP && (opt.headers['clientIP'] = params.AuthData.ClientIP); - params.AuthData.ClientUA && (opt.headers['clientUA'] = params.AuthData.ClientUA); - params.AuthData.XCosSecurityToken && (opt.headers['x-cos-security-token'] = params.AuthData.XCosSecurityToken); - - // 清理 undefined 和 null 字段 - opt.headers && (opt.headers = util.clearKey(opt.headers)); - opt = util.clearKey(opt); - - // progress - if (params.onProgress && typeof params.onProgress === 'function') { - opt.onProgress = function (e) { - if (TaskId && !self._isRunningTask(TaskId)) return; - var loaded = e ? e.loaded : 0; - params.onProgress({loaded: loaded, total: e.total}); - }; - } - if (this.options.Timeout) { - opt.timeout = this.options.Timeout; - } - - self.options.ForcePathStyle && (opt.pathStyle = self.options.ForcePathStyle); - self.emit('before-send', opt); - var sender = REQUEST(opt, function (err, response, body) { - if (err === 'abort') return; - - // 返回内容添加 状态码 和 headers - var hasReturned; - var cb = function (err, data) { - TaskId && self.off('inner-kill-task', killTask); - if (hasReturned) return; - hasReturned = true; - var attrs = {}; - response && response.statusCode && (attrs.statusCode = response.statusCode); - response && response.headers && (attrs.headers = response.headers); - - if (err) { - err = util.extend(err || {}, attrs); - callback(err, null); - } else { - data = util.extend(data || {}, attrs); - callback(null, data); - } - sender = null; - }; - - // 请求错误,发生网络错误 - if (err) { - cb({error: err}); - return; - } - - // 不对 body 进行转换,body 直接挂载返回 - var jsonRes; - if (rawBody) { - jsonRes = {}; - jsonRes.body = body; - } else { - try { - jsonRes = body && body.indexOf('<') > -1 && body.indexOf('>') > -1 && util.xml2json(body) || {}; - } catch (e) { - jsonRes = body || {}; - } - } - - // 请求返回码不为 200 - var statusCode = response.statusCode; - var statusSuccess = Math.floor(statusCode / 100) === 2; // 200 202 204 206 - if (!statusSuccess) { - cb({error: jsonRes.Error || jsonRes}); - return; - } - - if (jsonRes.Error) { - cb({error: jsonRes.Error}); - return; - } - cb(null, jsonRes); - }); - - // kill task - var killTask = function (data) { - if (data.TaskId === TaskId) { - sender && sender.abort && sender.abort(); - self.off('inner-kill-task', killTask); - } - }; - TaskId && self.on('inner-kill-task', killTask); - -} - - -var API_MAP = { - // Bucket 相关方法 - getService: getService, // Bucket - putBucket: putBucket, - headBucket: headBucket, // Bucket - getBucket: getBucket, - deleteBucket: deleteBucket, - putBucketAcl: putBucketAcl, // BucketACL - getBucketAcl: getBucketAcl, - putBucketCors: putBucketCors, // BucketCors - getBucketCors: getBucketCors, - deleteBucketCors: deleteBucketCors, - getBucketLocation: getBucketLocation, // BucketLocation - getBucketPolicy: getBucketPolicy, // BucketPolicy - putBucketPolicy: putBucketPolicy, - deleteBucketPolicy: deleteBucketPolicy, - putBucketTagging: putBucketTagging, // BucketTagging - getBucketTagging: getBucketTagging, - deleteBucketTagging: deleteBucketTagging, - putBucketLifecycle: putBucketLifecycle, // BucketLifecycle - getBucketLifecycle: getBucketLifecycle, - deleteBucketLifecycle: deleteBucketLifecycle, - putBucketVersioning: putBucketVersioning, // BucketVersioning - getBucketVersioning: getBucketVersioning, - putBucketReplication: putBucketReplication, // BucketReplication - getBucketReplication: getBucketReplication, - deleteBucketReplication: deleteBucketReplication, - putBucketWebsite: putBucketWebsite, // BucketWebsite - getBucketWebsite: getBucketWebsite, - deleteBucketWebsite: deleteBucketWebsite, - putBucketReferer: putBucketReferer, // BucketReferer - getBucketReferer: getBucketReferer, - putBucketDomain: putBucketDomain, // BucketDomain - getBucketDomain: getBucketDomain, - deleteBucketDomain: deleteBucketDomain, - putBucketOrigin: putBucketOrigin, // BucketOrigin - getBucketOrigin: getBucketOrigin, - deleteBucketOrigin: deleteBucketOrigin, - putBucketLogging: putBucketLogging, // BucketLogging - getBucketLogging: getBucketLogging, - putBucketInventory: putBucketInventory, // BucketInventory - getBucketInventory: getBucketInventory, - listBucketInventory: listBucketInventory, - deleteBucketInventory: deleteBucketInventory, - putBucketAccelerate: putBucketAccelerate, - getBucketAccelerate: getBucketAccelerate, - - // Object 相关方法 - getObject: getObject, - headObject: headObject, - listObjectVersions: listObjectVersions, - putObject: putObject, - postObject: postObject, - deleteObject: deleteObject, - getObjectAcl: getObjectAcl, - putObjectAcl: putObjectAcl, - optionsObject: optionsObject, - putObjectCopy: putObjectCopy, - deleteMultipleObject: deleteMultipleObject, - restoreObject: restoreObject, - putObjectTagging: putObjectTagging, - getObjectTagging: getObjectTagging, - deleteObjectTagging: deleteObjectTagging, - - // 分块上传相关方法 - uploadPartCopy: uploadPartCopy, - multipartInit: multipartInit, - multipartUpload: multipartUpload, - multipartComplete: multipartComplete, - multipartList: multipartList, - multipartListPart: multipartListPart, - multipartAbort: multipartAbort, - - // 工具方法 - request: request, - getObjectUrl: getObjectUrl, - getAuth: getAuth, -}; - -module.exports.init = function (COS, task) { - task.transferToTaskMethod(API_MAP, 'postObject'); - task.transferToTaskMethod(API_MAP, 'putObject'); - util.each(API_MAP, function (fn, apiName) { - COS.prototype[apiName] = util.apiWrapper(apiName, fn); - }); -}; +var session = __webpack_require__(5); +var util = __webpack_require__(0); + +var originApiMap = {}; +var transferToTaskMethod = function (apiMap, apiName) { + originApiMap[apiName] = apiMap[apiName]; + apiMap[apiName] = function (params, callback) { + if (params.SkipTask) { + originApiMap[apiName].call(this, params, callback); + } else { + this._addTask(apiName, params, callback); + } + }; +}; + +var initTask = function (cos) { + + var queue = []; + var tasks = {}; + var uploadingFileCount = 0; + var nextUploadIndex = 0; + + // 接口返回简略的任务信息 + var formatTask = function (task) { + var t = { + id: task.id, + Bucket: task.Bucket, + Region: task.Region, + Key: task.Key, + FilePath: task.FilePath, + state: task.state, + loaded: task.loaded, + size: task.size, + speed: task.speed, + percent: task.percent, + hashPercent: task.hashPercent, + error: task.error, + }; + if (task.FilePath) t.FilePath = task.FilePath; + return t; + }; + + var emitListUpdate = (function () { + var timer; + var emit = function () { + timer = 0; + cos.emit('task-list-update', {list: util.map(queue, formatTask)}); + cos.emit('list-update', {list: util.map(queue, formatTask)}); + }; + return function () { + if (!timer) timer = setTimeout(emit); + } + })(); + + var clearQueue = function () { + if (queue.length <= cos.options.UploadQueueSize) return; + for (var i = 0; + i < nextUploadIndex && // 小于当前操作的 index 才清理 + i < queue.length && // 大于队列才清理 + queue.length > cos.options.UploadQueueSize // 如果还太多,才继续清理 + ;) { + var isActive = queue[i].state === 'waiting' || queue[i].state === 'checking' || queue[i].state === 'uploading'; + if (!queue[i] || !isActive) { + tasks[queue[i].id] && (delete tasks[queue[i].id]); + queue.splice(i, 1); + nextUploadIndex--; + } else { + i++; + } + } + emitListUpdate(); + }; + + var startNextTask = function () { + // 检查是否允许增加执行进程 + if (uploadingFileCount >= cos.options.FileParallelLimit) return; + // 跳过不可执行的任务 + while (queue[nextUploadIndex] && queue[nextUploadIndex].state !== 'waiting') nextUploadIndex++; + // 检查是否已遍历结束 + if (nextUploadIndex >= queue.length) return; + // 上传该遍历到的任务 + var task = queue[nextUploadIndex]; + nextUploadIndex++; + uploadingFileCount++; + task.state = 'checking'; + task.params.onTaskStart && task.params.onTaskStart(formatTask(task)); + !task.params.UploadData && (task.params.UploadData = {}); + var apiParams = util.formatParams(task.api, task.params); + originApiMap[task.api].call(cos, apiParams, function (err, data) { + if (!cos._isRunningTask(task.id)) return; + if (task.state === 'checking' || task.state === 'uploading') { + task.state = err ? 'error' : 'success'; + err && (task.error = err); + uploadingFileCount--; + emitListUpdate(); + startNextTask(); + task.callback && task.callback(err, data); + if (task.state === 'success') { + if (task.params) { + delete task.params.UploadData; + delete task.params.Body; + delete task.params; + } + delete task.callback; + } + } + clearQueue(); + }); + emitListUpdate(); + // 异步执行下一个任务 + setTimeout(startNextTask); + }; + + var killTask = function (id, switchToState) { + var task = tasks[id]; + if (!task) return; + var waiting = task && task.state === 'waiting'; + var running = task && (task.state === 'checking' || task.state === 'uploading'); + if (switchToState === 'canceled' && task.state !== 'canceled' || + switchToState === 'paused' && waiting || + switchToState === 'paused' && running) { + if (switchToState === 'paused' && task.params.Body && typeof task.params.Body.pipe === 'function') { + console.error('stream not support pause'); + return; + } + task.state = switchToState; + cos.emit('inner-kill-task', {TaskId: id, toState: switchToState}); + try { + var UploadId = task && task.params && task.params.UploadData.UploadId + } catch(e) {} + if (switchToState === 'canceled' && UploadId) session.removeUsing(UploadId) + emitListUpdate(); + if (running) { + uploadingFileCount--; + startNextTask(); + } + if (switchToState === 'canceled') { + if (task.params) { + delete task.params.UploadData; + delete task.params.Body; + delete task.params; + } + delete task.callback; + } + } + clearQueue(); + }; + + cos._addTasks = function (taskList) { + util.each(taskList, function (task) { + cos._addTask(task.api, task.params, task.callback, true); + }); + emitListUpdate(); + }; + + cos._addTask = function (api, params, callback, ignoreAddEvent) { + + // 如果小程序版本不支持获取文件分片内容,统一转到 postObject 接口上传 + if (api === 'sliceUploadFile' && !util.canFileSlice()) api = 'postObject'; + + // 复制参数对象 + params = util.formatParams(api, params); + + // 生成 id + var id = util.uuid(); + params.TaskId = id; + params.onTaskReady && params.onTaskReady(id); + + var task = { + // env + params: params, + callback: callback, + api: api, + index: queue.length, + // task + id: id, + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + FilePath: params.FilePath || '', + state: 'waiting', + loaded: 0, + size: 0, + speed: 0, + percent: 0, + hashPercent: 0, + error: null, + }; + var onHashProgress = params.onHashProgress; + params.onHashProgress = function (info) { + if (!cos._isRunningTask(task.id)) return; + task.hashPercent = info.percent; + onHashProgress && onHashProgress(info); + emitListUpdate(); + }; + var onProgress = params.onProgress; + params.onProgress = function (info) { + if (!cos._isRunningTask(task.id)) return; + task.state === 'checking' && (task.state = 'uploading'); + task.loaded = info.loaded; + task.size = info.total; + task.speed = info.speed; + task.percent = info.percent; + onProgress && onProgress(info); + emitListUpdate(); + }; + + // 异步获取 filesize + util.getFileSize(api, params, function (err, size) { + // 开始处理上传 + if (err) { // 如果获取大小出错,不加入队列 + callback(err); + return; + } + // 获取完文件大小再把任务加入队列 + tasks[id] = task; + queue.push(task); + task.size = size; + !ignoreAddEvent && emitListUpdate(); + startNextTask(); + clearQueue(); + }); + return id; + }; + cos._isRunningTask = function (id) { + var task = tasks[id]; + return !!(task && (task.state === 'checking' || task.state === 'uploading')); + }; + cos.getTaskList = function () { + return util.map(queue, formatTask); + }; + cos.cancelTask = function (id) { + killTask(id, 'canceled'); + }; + cos.pauseTask = function (id) { + killTask(id, 'paused'); + }; + cos.restartTask = function (id) { + var task = tasks[id]; + if (task && (task.state === 'paused' || task.state === 'error')) { + task.state = 'waiting'; + emitListUpdate(); + nextUploadIndex = Math.min(nextUploadIndex, task.index); + startNextTask(); + } + }; + cos.isUploadRunning = function () { + return uploadingFileCount || nextUploadIndex < queue.length; + }; + +}; + +module.exports.transferToTaskMethod = transferToTaskMethod; +module.exports.init = initTask; + + +/***/ }), +/* 17 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var REQUEST = __webpack_require__(18); +var base64 = __webpack_require__(3); +var util = __webpack_require__(0); +var mime = __webpack_require__(19); + + +// Bucket 相关 + +/** + * 获取用户的 bucket 列表 + * @param {Object} params 回调函数,必须,下面为参数列表 + * 无特殊参数 + * @param {Function} callback 回调函数,必须 + */ +function getService(params, callback) { + + if (typeof params === 'function') { + callback = params; + params = {}; + } + var protocol = 'https:'; + var domain = this.options.ServiceDomain; + var region = params.Region; + if (domain) { + domain = domain.replace(/\{\{Region\}\}/ig, region || '').replace(/\{\{.*?\}\}/ig, ''); + if (!/^[a-zA-Z]+:\/\//.test(domain)) { + domain = protocol + '//' + domain; + } + if (domain.slice(-1) === '/') { + domain = domain.slice(0, -1); + } + } else if (region) { + domain = protocol + '//cos.' + region + '.myqcloud.com'; + } else { + domain = protocol + '//service.cos.myqcloud.com'; + } + + submitRequest.call(this, { + Action: 'name/cos:GetService', + url: domain, + method: 'GET', + headers: params.Headers, + }, function (err, data) { + if (err) return callback(err); + var buckets = (data && data.ListAllMyBucketsResult && data.ListAllMyBucketsResult.Buckets + && data.ListAllMyBucketsResult.Buckets.Bucket) || []; + buckets = util.isArray(buckets) ? buckets : [buckets]; + var owner = (data && data.ListAllMyBucketsResult && data.ListAllMyBucketsResult.Owner) || {}; + callback(null, { + Buckets: buckets, + Owner: owner, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 创建 Bucket,并初始化访问权限 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.ACL 用户自定义文件权限,可以设置:private,public-read;默认值:private,非必须 + * @param {String} params.GrantRead 赋予被授权者读的权限,格式x-cos-grant-read: uin=" ",uin=" ",非必须 + * @param {String} params.GrantWrite 赋予被授权者写的权限,格式x-cos-grant-write: uin=" ",uin=" ",非必须 + * @param {String} params.GrantFullControl 赋予被授权者读写权限,格式x-cos-grant-full-control: uin=" ",uin=" ",非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {String} data.Location 操作地址 + */ +function putBucket(params, callback) { + + var self = this; + + var xml = ''; + if(params['BucketAZConfig']){ + var CreateBucketConfiguration = { + BucketAZConfig: params.BucketAZConfig + }; + xml = util.json2xml({CreateBucketConfiguration: CreateBucketConfiguration}); + } + + submitRequest.call(this, { + Action: 'name/cos:PutBucket', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + body: xml, + }, function (err, data) { + if (err) return callback(err); + var url = getUrl({ + protocol: self.options.Protocol, + domain: self.options.Domain, + bucket: params.Bucket, + region: params.Region, + isLocation: true, + }); + callback(null, { + Location: url, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 查看是否存在该Bucket,是否有权限访问 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {Boolean} data.BucketExist Bucket是否存在 + * @return {Boolean} data.BucketAuth 是否有 Bucket 的访问权限 + */ +function headBucket(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:HeadBucket', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + method: 'HEAD', + }, function (err, data) { + callback(err, data); + }); +} + +/** + * 获取 Bucket 下的 object 列表 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Prefix 前缀匹配,用来规定返回的文件前缀地址,非必须 + * @param {String} params.Delimiter 定界符为一个符号,如果有Prefix,则将Prefix到delimiter之间的相同路径归为一类,非必须 + * @param {String} params.Marker 默认以UTF-8二进制顺序列出条目,所有列出条目从marker开始,非必须 + * @param {String} params.MaxKeys 单次返回最大的条目数量,默认1000,非必须 + * @param {String} params.EncodingType 规定返回值的编码方式,非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {Object} data.ListBucketResult 返回的 object 列表信息 + */ +function getBucket(params, callback) { + var reqParams = {}; + reqParams['prefix'] = params['Prefix'] || ''; + reqParams['delimiter'] = params['Delimiter']; + reqParams['marker'] = params['Marker']; + reqParams['max-keys'] = params['MaxKeys']; + reqParams['encoding-type'] = params['EncodingType']; + + submitRequest.call(this, { + Action: 'name/cos:GetBucket', + ResourceKey: reqParams['prefix'], + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + qs: reqParams, + }, function (err, data) { + if (err) return callback(err); + var ListBucketResult = data.ListBucketResult || {}; + var Contents = ListBucketResult.Contents || []; + var CommonPrefixes = ListBucketResult.CommonPrefixes || []; + + Contents = util.isArray(Contents) ? Contents : [Contents]; + CommonPrefixes = util.isArray(CommonPrefixes) ? CommonPrefixes : [CommonPrefixes]; + + var result = util.clone(ListBucketResult); + util.extend(result, { + Contents: Contents, + CommonPrefixes: CommonPrefixes, + statusCode: data.statusCode, + headers: data.headers, + }); + + callback(null, result); + }); +} + +/** + * 删除 Bucket + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {String} data.Location 操作地址 + */ +function deleteBucket(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:DeleteBucket', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + method: 'DELETE', + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 设置 Bucket 的 权限列表 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.ACL 用户自定义文件权限,可以设置:private,public-read;默认值:private,非必须 + * @param {String} params.GrantRead 赋予被授权者读的权限,格式x-cos-grant-read: uin=" ",uin=" ",非必须 + * @param {String} params.GrantWrite 赋予被授权者写的权限,格式x-cos-grant-write: uin=" ",uin=" ",非必须 + * @param {String} params.GrantFullControl 赋予被授权者读写权限,格式x-cos-grant-full-control: uin=" ",uin=" ",非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ +function putBucketAcl(params, callback) { + var headers = params.Headers; + + var xml = ''; + if (params['AccessControlPolicy']) { + var AccessControlPolicy = util.clone(params['AccessControlPolicy'] || {}); + var Grants = AccessControlPolicy.Grants || AccessControlPolicy.Grant; + Grants = util.isArray(Grants) ? Grants : [Grants]; + delete AccessControlPolicy.Grant; + delete AccessControlPolicy.Grants; + AccessControlPolicy.AccessControlList = {Grant: Grants}; + xml = util.json2xml({AccessControlPolicy: AccessControlPolicy}); + + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + } + + // Grant Header 去重 + util.each(headers, function (val, key) { + if (key.indexOf('x-cos-grant-') === 0) { + headers[key] = uniqGrant(headers[key]); + } + }); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketACL', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + headers: headers, + action: 'acl', + body: xml, + }, function (err, data) { + if (err) return callback(err); + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的 权限列表 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {Object} data.AccessControlPolicy 访问权限信息 + */ +function getBucketAcl(params, callback) { + + submitRequest.call(this, { + Action: 'name/cos:GetBucketACL', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'acl', + }, function (err, data) { + if (err) return callback(err); + var AccessControlPolicy = data.AccessControlPolicy || {}; + var Owner = AccessControlPolicy.Owner || {}; + var Grant = AccessControlPolicy.AccessControlList.Grant || []; + Grant = util.isArray(Grant) ? Grant : [Grant]; + var result = decodeAcl(AccessControlPolicy); + if (data.headers && data.headers['x-cos-acl']) { + result.ACL = data.headers['x-cos-acl']; + } + result = util.extend(result, { + Owner: Owner, + Grants: Grant, + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }); +} + +/** + * 设置 Bucket 的 跨域设置 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Object} params.CORSConfiguration 相关的跨域设置,必须 + * @param {Array} params.CORSConfiguration.CORSRules 对应的跨域规则 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ +function putBucketCors(params, callback) { + + var CORSConfiguration = params['CORSConfiguration'] || {}; + var CORSRules = CORSConfiguration['CORSRules'] || params['CORSRules'] || []; + CORSRules = util.clone(util.isArray(CORSRules) ? CORSRules : [CORSRules]); + util.each(CORSRules, function (rule) { + util.each(['AllowedOrigin', 'AllowedHeader', 'AllowedMethod', 'ExposeHeader'], function (key) { + var sKey = key + 's'; + var val = rule[sKey] || rule[key] || []; + delete rule[sKey]; + rule[key] = util.isArray(val) ? val : [val]; + }); + }); + + var xml = util.json2xml({CORSConfiguration: {CORSRule: CORSRules}}); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketCORS', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'cors', + headers: headers, + }, function (err, data) { + if (err) return callback(err); + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的 跨域设置 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {Object} data.CORSRules Bucket的跨域设置 + */ +function getBucketCors(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:GetBucketCORS', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'cors', + }, function (err, data) { + if (err) { + if (err.statusCode === 404 && err.error && err.error.Code === 'NoSuchCORSConfiguration') { + var result = { + CORSRules: [], + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); + } + return; + } + var CORSConfiguration = data.CORSConfiguration || {}; + var CORSRules = CORSConfiguration.CORSRules || CORSConfiguration.CORSRule || []; + CORSRules = util.clone(util.isArray(CORSRules) ? CORSRules : [CORSRules]); + + util.each(CORSRules, function (rule) { + util.each(['AllowedOrigin', 'AllowedHeader', 'AllowedMethod', 'ExposeHeader'], function (key) { + var sKey = key + 's'; + var val = rule[sKey] || rule[key] || []; + delete rule[key]; + rule[sKey] = util.isArray(val) ? val : [val]; + }); + }); + + callback(null, { + CORSRules: CORSRules, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 删除 Bucket 的 跨域设置 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ +function deleteBucketCors(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:DeleteBucketCORS', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'cors', + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode || err.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的 地域信息 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据,包含地域信息 LocationConstraint + */ +function getBucketLocation(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:GetBucketLocation', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'location', + }, function (err, data) { + if (err) return callback(err); + callback(null, data); + }); +} + +function putBucketPolicy(params, callback) { + var Policy = params['Policy']; + var PolicyStr = Policy; + try { + if (typeof Policy === 'string') { + Policy = JSON.parse(PolicyStr); + } else { + PolicyStr = JSON.stringify(Policy); + } + } catch (e) { + callback({error: 'Policy format error'}); + } + + var headers = params.Headers; + headers['Content-Type'] = 'application/json'; + headers['Content-MD5'] = util.binaryBase64(util.md5(PolicyStr)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketPolicy', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + action: 'policy', + body: PolicyStr, + headers: headers, + json: true, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的读取权限策略 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function getBucketPolicy(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:GetBucketPolicy', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'policy', + rawBody: true, + }, function (err, data) { + if (err) { + if (err.statusCode && err.statusCode === 403) { + return callback({ErrorStatus: 'Access Denied'}); + } + if (err.statusCode && err.statusCode === 405) { + return callback({ErrorStatus: 'Method Not Allowed'}); + } + if (err.statusCode && err.statusCode === 404) { + return callback({ErrorStatus: 'Policy Not Found'}); + } + return callback(err); + } + var Policy = {}; + try { + Policy = JSON.parse(data.body); + } catch (e) { + } + callback(null, { + Policy: Policy, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 删除 Bucket 的 跨域设置 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ +function deleteBucketPolicy(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:DeleteBucketPolicy', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'policy', + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode || err.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 设置 Bucket 的标签 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Array} params.TagSet 标签设置,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function putBucketTagging(params, callback) { + + var Tagging = params['Tagging'] || {}; + var Tags = Tagging.TagSet || Tagging.Tags || params['Tags'] || []; + Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); + var xml = util.json2xml({Tagging: {TagSet: {Tag: Tags}}}); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketTagging', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'tagging', + headers: headers, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的标签设置 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function getBucketTagging(params, callback) { + + submitRequest.call(this, { + Action: 'name/cos:GetBucketTagging', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'tagging', + }, function (err, data) { + if (err) { + if (err.statusCode === 404 && err.error && (err.error === "Not Found" || err.error.Code === 'NoSuchTagSet')) { + var result = { + Tags: [], + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); + } + return; + } + var Tags = []; + try { + Tags = data.Tagging.TagSet.Tag || []; + } catch (e) { + } + Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); + callback(null, { + Tags: Tags, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 删除 Bucket 的 标签设置 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ +function deleteBucketTagging(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:DeleteBucketTagging', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'tagging', + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +function putBucketLifecycle(params, callback) { + + var LifecycleConfiguration = params['LifecycleConfiguration'] || {}; + var Rules = LifecycleConfiguration.Rules || params.Rules || []; + Rules = util.clone(Rules); + var xml = util.json2xml({LifecycleConfiguration: {Rule: Rules}}); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketLifecycle', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'lifecycle', + headers: headers, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +function getBucketLifecycle(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:GetBucketLifecycle', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'lifecycle', + }, function (err, data) { + if (err) { + if (err.statusCode === 404 && err.error && err.error.Code === 'NoSuchLifecycleConfiguration') { + var result = { + Rules: [], + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); + } + return; + } + var Rules = []; + try { + Rules = data.LifecycleConfiguration.Rule || []; + } catch (e) { + } + Rules = util.clone(util.isArray(Rules) ? Rules : [Rules]); + callback(null, { + Rules: Rules, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +function deleteBucketLifecycle(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:DeleteBucketLifecycle', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'lifecycle', + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +function putBucketVersioning(params, callback) { + + if (!params['VersioningConfiguration']) { + callback({error: 'missing param VersioningConfiguration'}); + return; + } + var VersioningConfiguration = params['VersioningConfiguration'] || {}; + var xml = util.json2xml({VersioningConfiguration: VersioningConfiguration}); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketVersioning', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'versioning', + headers: headers, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +function getBucketVersioning(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:GetBucketVersioning', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'versioning', + }, function (err, data) { + if (!err) { + !data.VersioningConfiguration && (data.VersioningConfiguration = {}); + } + callback(err, data); + }); +} + +function putBucketReplication(params, callback) { + var ReplicationConfiguration = util.clone(params.ReplicationConfiguration); + var xml = util.json2xml({ReplicationConfiguration: ReplicationConfiguration}); + xml = xml.replace(/<(\/?)Rules>/ig, '<$1Rule>'); + xml = xml.replace(/<(\/?)Tags>/ig, '<$1Tag>'); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketReplication', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'replication', + headers: headers, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +function getBucketReplication(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:GetBucketReplication', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'replication', + }, function (err, data) { + if (err) { + if (err.statusCode === 404 && err.error && (err.error === 'Not Found' || err.error.Code === 'ReplicationConfigurationnotFoundError')) { + var result = { + ReplicationConfiguration: {Rules: []}, + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); + } + return; + } + if (!err) { + !data.ReplicationConfiguration && (data.ReplicationConfiguration = {}); + } + if (data.ReplicationConfiguration.Rule) { + data.ReplicationConfiguration.Rules = data.ReplicationConfiguration.Rule; + delete data.ReplicationConfiguration.Rule; + } + callback(err, data); + }); +} + +function deleteBucketReplication(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:DeleteBucketReplication', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'replication', + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 设置 Bucket 静态网站配置信息 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Object} params.WebsiteConfiguration 地域名称,必须 + * @param {Object} WebsiteConfiguration.IndexDocument 索引文档,必须 + * @param {Object} WebsiteConfiguration.ErrorDocument 错误文档,非必须 + * @param {Object} WebsiteConfiguration.RedirectAllRequestsTo 重定向所有请求,非必须 + * @param {Array} params.RoutingRules 重定向规则,非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function putBucketWebsite(params, callback) { + + if (!params['WebsiteConfiguration']) { + callback({ error: 'missing param WebsiteConfiguration' }); + return; + } + + var WebsiteConfiguration = util.clone(params['WebsiteConfiguration'] || {}); + var RoutingRules = WebsiteConfiguration['RoutingRules'] || WebsiteConfiguration['RoutingRule'] || []; + RoutingRules = util.isArray(RoutingRules) ? RoutingRules : [RoutingRules]; + delete WebsiteConfiguration.RoutingRule; + delete WebsiteConfiguration.RoutingRules; + if (RoutingRules.length) WebsiteConfiguration.RoutingRules = { RoutingRule: RoutingRules }; + var xml = util.json2xml({ WebsiteConfiguration: WebsiteConfiguration }); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketWebsite', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'website', + headers: headers, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的静态网站配置信息 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function getBucketWebsite(params, callback) { + + submitRequest.call(this, { + Action: 'name/cos:GetBucketWebsite', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + action: 'website', + }, function (err, data) { + if (err) { + if(err.statusCode === 404 && err.error.Code === 'NoSuchWebsiteConfiguration'){ + var result = { + WebsiteConfiguration: {}, + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); + } + return; + } + + var WebsiteConfiguration = data.WebsiteConfiguration || {}; + if (WebsiteConfiguration['RoutingRules']) { + var RoutingRules = util.clone(WebsiteConfiguration['RoutingRules'].RoutingRule || []); + RoutingRules = util.makeArray(RoutingRules); + WebsiteConfiguration.RoutingRules = RoutingRules; + } + + callback(null, { + WebsiteConfiguration: WebsiteConfiguration, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 删除 Bucket 的静态网站配置 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function deleteBucketWebsite(params, callback) { + + submitRequest.call(this, { + Action: 'name/cos:DeleteBucketWebsite', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'website', + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 设置 Bucket 的防盗链白名单或者黑名单 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Object} params.RefererConfiguration 地域名称,必须 + * @param {String} RefererConfiguration.Status 是否开启防盗链,枚举值:Enabled、Disabled + * @param {String} RefererConfiguration.RefererType 防盗链类型,枚举值:Black-List、White-List,必须 + * @param {Array} RefererConfiguration.DomianList.Domain 生效域名,必须 + * @param {String} RefererConfiguration.EmptyReferConfiguration ,非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function putBucketReferer(params, callback) { + + if (!params['RefererConfiguration']) { + callback({ error: 'missing param RefererConfiguration' }); + return; + } + + var RefererConfiguration = util.clone(params['RefererConfiguration'] || {}); + var DomainList = RefererConfiguration['DomainList'] || {}; + var Domains = DomainList['Domains'] || DomainList['Domain'] || []; + Domains = util.isArray(Domains) ? Domains : [Domains]; + if (Domains.length) RefererConfiguration.DomainList = {Domain: Domains}; + var xml = util.json2xml({ RefererConfiguration: RefererConfiguration }); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketReferer', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'referer', + headers: headers, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的防盗链白名单或者黑名单 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function getBucketReferer(params, callback) { + + submitRequest.call(this, { + Action: 'name/cos:GetBucketReferer', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + action: 'referer', + }, function (err, data) { + if (err) { + if(err.statusCode === 404 && err.error.Code === 'NoSuchRefererConfiguration'){ + var result = { + WebsiteConfiguration: {}, + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); + } + return; + } + + var RefererConfiguration = data.RefererConfiguration || {}; + if (RefererConfiguration['DomainList']) { + var Domains = util.clone(RefererConfiguration['DomainList'].Domain || []); + Domains = util.makeArray(Domains); + RefererConfiguration.DomainList = {Domains: Domains}; + } + + callback(null, { + RefererConfiguration: RefererConfiguration, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 设置 Bucket 自定义域名 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function putBucketDomain(params, callback) { + + var DomainConfiguration = params['DomainConfiguration'] || {}; + var DomainRule = DomainConfiguration.DomainRule || params.DomainRule || []; + DomainRule = util.clone(DomainRule); + var xml = util.json2xml({DomainConfiguration: {DomainRule: DomainRule}}); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketDomain', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'domain', + headers: headers, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的自定义域名 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function getBucketDomain(params, callback) { + + submitRequest.call(this, { + Action: 'name/cos:GetBucketDomain', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'domain', + }, function (err, data) { + if (err) return callback(err); + + var DomainRule = []; + try { + DomainRule = data.DomainConfiguration.DomainRule || []; + } catch (e) { + } + DomainRule = util.clone(util.isArray(DomainRule) ? DomainRule : [DomainRule]); + callback(null, { + DomainRule: DomainRule, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 删除 Bucket 自定义域名 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function deleteBucketDomain(params, callback) { + + submitRequest.call(this, { + Action: 'name/cos:DeleteBucketDomain', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'domain', + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 设置 Bucket 的回源 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function putBucketOrigin(params, callback){ + var OriginConfiguration = params['OriginConfiguration'] || {}; + var OriginRule = OriginConfiguration.OriginRule || params.OriginRule || []; + OriginRule = util.clone(OriginRule); + var xml = util.json2xml({OriginConfiguration: {OriginRule: OriginRule}}); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketOrigin', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'origin', + headers: headers, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的回源 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function getBucketOrigin(params, callback) { + + submitRequest.call(this, { + Action: 'name/cos:GetBucketOrigin', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'origin', + }, function (err, data) { + if (err) return callback(err); + + var OriginRule = []; + try { + OriginRule = data.OriginConfiguration.OriginRule || []; + } catch (e) { + } + OriginRule = util.clone(util.isArray(OriginRule) ? OriginRule : [OriginRule]); + callback(null, { + OriginRule: OriginRule, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 删除 Bucket 的回源 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function deleteBucketOrigin(params, callback) { + + submitRequest.call(this, { + Action: 'name/cos:DeleteBucketOrigin', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'origin', + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 设置 Bucket 的日志记录 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {(Object|String)} params.BucketLoggingStatus 说明日志记录配置的状态,如果无子节点信息则意为关闭日志记录,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function putBucketLogging(params, callback) { + var xml = util.json2xml({ + BucketLoggingStatus: params['BucketLoggingStatus'] || '' + }); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketLogging', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'logging', + headers: headers, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的日志记录 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function getBucketLogging(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:GetBucketLogging', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'logging', + }, function (err, data) { + if (err) return callback(err); + delete data.BucketLoggingStatus._xmlns; + callback(null, { + BucketLoggingStatus: data.BucketLoggingStatus, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 创建/编辑 Bucket 的清单任务 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Id 清单任务的名称,必须 + * @param {Object} params.InventoryConfiguration 包含清单的配置参数,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function putBucketInventory(params, callback) { + var InventoryConfiguration = util.clone(params['InventoryConfiguration']); + + if (InventoryConfiguration.OptionalFields) { + var Field = InventoryConfiguration.OptionalFields || []; + InventoryConfiguration.OptionalFields = { + Field: Field + }; + } + + if (InventoryConfiguration.Destination + && InventoryConfiguration.Destination.COSBucketDestination + && InventoryConfiguration.Destination.COSBucketDestination.Encryption + ) { + var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption; + if (Object.keys(Encryption).indexOf('SSECOS') > -1) { + Encryption['SSE-COS'] = Encryption['SSECOS']; + delete Encryption['SSECOS']; + } + } + + var xml = util.json2xml({ + InventoryConfiguration: InventoryConfiguration + }); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketInventory', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'inventory', + qs: { + id: params['Id'] + }, + headers: headers, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的清单任务信息 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Id 清单任务的名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function getBucketInventory(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:GetBucketInventory', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'inventory', + qs: { + id: params['Id'] + } + }, function (err, data) { + if (err) return callback(err); + + var InventoryConfiguration = data['InventoryConfiguration']; + if (InventoryConfiguration && InventoryConfiguration.OptionalFields && InventoryConfiguration.OptionalFields.Field) { + var Field = InventoryConfiguration.OptionalFields.Field; + if (!util.isArray(Field)) { + Field = [Field]; + } + InventoryConfiguration.OptionalFields = Field; + } + if (InventoryConfiguration.Destination + && InventoryConfiguration.Destination.COSBucketDestination + && InventoryConfiguration.Destination.COSBucketDestination.Encryption + ) { + var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption; + if (Object.keys(Encryption).indexOf('SSE-COS') > -1) { + Encryption['SSECOS'] = Encryption['SSE-COS']; + delete Encryption['SSE-COS']; + } + } + + callback(null, { + InventoryConfiguration: InventoryConfiguration, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的清单任务信息 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.ContinuationToken 当 COS 响应体中 IsTruncated 为 true,且 NextContinuationToken 节点中存在参数值时,您可以将这个参数作为 continuation-token 参数值,以获取下一页的清单任务信息,非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function listBucketInventory(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:ListBucketInventory', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'inventory', + qs: { + 'continuation-token': params['ContinuationToken'] + } + }, function (err, data) { + if (err) return callback(err); + var ListInventoryConfigurationResult = data['ListInventoryConfigurationResult']; + var InventoryConfigurations = ListInventoryConfigurationResult.InventoryConfiguration || []; + InventoryConfigurations = util.isArray(InventoryConfigurations) ? InventoryConfigurations : [InventoryConfigurations]; + delete ListInventoryConfigurationResult['InventoryConfiguration']; + util.each(InventoryConfigurations, function (InventoryConfiguration) { + if (InventoryConfiguration && InventoryConfiguration.OptionalFields && InventoryConfiguration.OptionalFields.Field) { + var Field = InventoryConfiguration.OptionalFields.Field; + if (!util.isArray(Field)) { + Field = [Field]; + } + InventoryConfiguration.OptionalFields = Field; + } + + if (InventoryConfiguration.Destination + && InventoryConfiguration.Destination.COSBucketDestination + && InventoryConfiguration.Destination.COSBucketDestination.Encryption + ) { + var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption; + if (Object.keys(Encryption).indexOf('SSE-COS') > -1) { + Encryption['SSECOS'] = Encryption['SSE-COS']; + delete Encryption['SSE-COS']; + } + } + }); + ListInventoryConfigurationResult.InventoryConfigurations = InventoryConfigurations; + util.extend(ListInventoryConfigurationResult, { + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, ListInventoryConfigurationResult); + }); +} + +/** + * 删除 Bucket 的清单任务 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Id 清单任务的名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function deleteBucketInventory(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:DeleteBucketInventory', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'inventory', + qs: { + id: params['Id'] + } + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/* 全球加速 */ +function putBucketAccelerate(params, callback) { + + if (!params['AccelerateConfiguration']) { + callback({error: 'missing param AccelerateConfiguration'}); + return; + } + + var configuration = { AccelerateConfiguration: params.AccelerateConfiguration || {} }; + + var xml = util.json2xml(configuration); + + var headers = {}; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Interface: 'putBucketAccelerate', + Action: 'name/cos:PutBucketAccelerate', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'accelerate', + headers: headers, + }, function (err, data) { + if (err) return callback(err); + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +function getBucketAccelerate(params, callback) { + submitRequest.call(this, { + Interface: 'getBucketAccelerate', + Action: 'name/cos:GetBucketAccelerate', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + action: 'accelerate', + }, function (err, data) { + if (!err) { + !data.AccelerateConfiguration && (data.AccelerateConfiguration = {}); + } + callback(err, data); + }); +} + +// Object 相关 + +/** + * 取回对应Object的元数据,Head的权限与Get的权限一致 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key 文件名称,必须 + * @param {String} params.IfModifiedSince 当Object在指定时间后被修改,则返回对应Object元信息,否则返回304,非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 为指定 object 的元数据,如果设置了 IfModifiedSince ,且文件未修改,则返回一个对象,NotModified 属性为 true + * @return {Boolean} data.NotModified 是否在 IfModifiedSince 时间点之后未修改该 object,则为 true + */ +function headObject(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:HeadObject', + method: 'HEAD', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + VersionId: params.VersionId, + headers: params.Headers, + }, function (err, data) { + if (err) { + var statusCode = err.statusCode; + if (params.Headers['If-Modified-Since'] && statusCode && statusCode === 304) { + return callback(null, { + NotModified: true, + statusCode: statusCode, + }); + } + return callback(err); + } + data.ETag = util.attr(data.headers, 'etag', ''); + callback(null, data); + }); +} + + +function listObjectVersions(params, callback) { + var reqParams = {}; + reqParams['prefix'] = params['Prefix'] || ''; + reqParams['delimiter'] = params['Delimiter']; + reqParams['key-marker'] = params['KeyMarker']; + reqParams['version-id-marker'] = params['VersionIdMarker']; + reqParams['max-keys'] = params['MaxKeys']; + reqParams['encoding-type'] = params['EncodingType']; + + submitRequest.call(this, { + Action: 'name/cos:GetBucketObjectVersions', + ResourceKey: reqParams['prefix'], + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + qs: reqParams, + action: 'versions', + }, function (err, data) { + if (err) return callback(err); + var ListVersionsResult = data.ListVersionsResult || {}; + var DeleteMarkers = ListVersionsResult.DeleteMarker || []; + DeleteMarkers = util.isArray(DeleteMarkers) ? DeleteMarkers : [DeleteMarkers]; + var Versions = ListVersionsResult.Version || []; + Versions = util.isArray(Versions) ? Versions : [Versions]; + + var result = util.clone(ListVersionsResult); + delete result.DeleteMarker; + delete result.Version; + util.extend(result, { + DeleteMarkers: DeleteMarkers, + Versions: Versions, + statusCode: data.statusCode, + headers: data.headers, + }); + + callback(null, result); + }); +} + +/** + * 下载 object + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key 文件名称,必须 + * @param {WriteStream} params.Output 文件写入流,非必须 + * @param {String} params.IfModifiedSince 当Object在指定时间后被修改,则返回对应Object元信息,否则返回304,非必须 + * @param {String} params.IfUnmodifiedSince 如果文件修改时间早于或等于指定时间,才返回文件内容。否则返回 412 (precondition failed),非必须 + * @param {String} params.IfMatch 当 ETag 与指定的内容一致,才返回文件。否则返回 412 (precondition failed),非必须 + * @param {String} params.IfNoneMatch 当 ETag 与指定的内容不一致,才返回文件。否则返回304 (not modified),非必须 + * @param {String} params.ResponseContentType 设置返回头部中的 Content-Type 参数,非必须 + * @param {String} params.ResponseContentLanguage 设置返回头部中的 Content-Language 参数,非必须 + * @param {String} params.ResponseExpires 设置返回头部中的 Content-Expires 参数,非必须 + * @param {String} params.ResponseCacheControl 设置返回头部中的 Cache-Control 参数,非必须 + * @param {String} params.ResponseContentDisposition 设置返回头部中的 Content-Disposition 参数,非必须 + * @param {String} params.ResponseContentEncoding 设置返回头部中的 Content-Encoding 参数,非必须 + * @param {Function} callback 回调函数,必须 + * @param {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @param {Object} data 为对应的 object 数据,包括 body 和 headers + */ +function getObject(params, callback) { + var reqParams = params.Query || {}; + var reqParamsStr = params.QueryString || ''; + + reqParams['response-content-type'] = params['ResponseContentType']; + reqParams['response-content-language'] = params['ResponseContentLanguage']; + reqParams['response-expires'] = params['ResponseExpires']; + reqParams['response-cache-control'] = params['ResponseCacheControl']; + reqParams['response-content-disposition'] = params['ResponseContentDisposition']; + reqParams['response-content-encoding'] = params['ResponseContentEncoding']; + + // 如果用户自己传入了 output + submitRequest.call(this, { + Action: 'name/cos:GetObject', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + VersionId: params.VersionId, + headers: params.Headers, + qs: reqParams, + qsStr: reqParamsStr, + rawBody: true, + }, function (err, data) { + if (err) { + var statusCode = err.statusCode; + if (params.Headers['If-Modified-Since'] && statusCode && statusCode === 304) { + return callback(null, { + NotModified: true + }); + } + return callback(err); + } + callback(null, { + Body: data.body, + ETag: util.attr(data.headers, 'etag', ''), + statusCode: data.statusCode, + headers: data.headers, + }); + }); + +} + +/** + * 上传 object + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key 文件名称,必须 + * @param {String} params.Body 上传文件的内容,只支持字符串 + * @param {String} params.CacheControl RFC 2616 中定义的缓存策略,将作为 Object 元数据保存,非必须 + * @param {String} params.ContentDisposition RFC 2616 中定义的文件名称,将作为 Object 元数据保存,非必须 + * @param {String} params.ContentEncoding RFC 2616 中定义的编码格式,将作为 Object 元数据保存,非必须 + * @param {String} params.ContentLength RFC 2616 中定义的 HTTP 请求内容长度(字节),必须 + * @param {String} params.ContentType RFC 2616 中定义的内容类型(MIME),将作为 Object 元数据保存,非必须 + * @param {String} params.Expect 当使用 Expect: 100-continue 时,在收到服务端确认后,才会发送请求内容,非必须 + * @param {String} params.Expires RFC 2616 中定义的过期时间,将作为 Object 元数据保存,非必须 + * @param {String} params.ContentSha1 RFC 3174 中定义的 160-bit 内容 SHA-1 算法校验,非必须 + * @param {String} params.ACL 允许用户自定义文件权限,有效值:private | public-read,非必须 + * @param {String} params.GrantRead 赋予被授权者读的权限,格式 x-cos-grant-read: uin=" ",uin=" ",非必须 + * @param {String} params.GrantWrite 赋予被授权者写的权限,格式 x-cos-grant-write: uin=" ",uin=" ",非必须 + * @param {String} params.GrantFullControl 赋予被授权者读写权限,格式 x-cos-grant-full-control: uin=" ",uin=" ",非必须 + * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须 + * @param {Function} params.onProgress 上传进度回调函数 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 为对应的 object 数据 + * @return {String} data.ETag 为对应上传文件的 ETag 值 + */ +function putObject(params, callback) { + var self = this; + var FileSize = params.ContentLength; + var onProgress = util.throttleOnProgress.call(self, FileSize, params.onProgress); + + // 特殊处理 Cache-Control、Content-Type,避免代理更改这两个字段导致写入到 Object 属性里 + var headers = params.Headers; + if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = ''; + if (!headers['Content-Type'] && !headers['content-type']) headers['Content-Type'] = mime.getType(params.Key) || 'application/octet-stream'; + + util.getBodyMd5(self.options.UploadCheckContentMd5, params.Body, function (md5) { + if (md5) headers['Content-MD5'] = util.binaryBase64(md5); + if (params.ContentLength !== undefined) headers['Content-Length'] = params.ContentLength; + onProgress(null, true); // 任务状态开始 uploading + submitRequest.call(self, { + Action: 'name/cos:PutObject', + TaskId: params.TaskId, + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + qs: params.Query, + body: params.Body, + onProgress: onProgress, + }, function (err, data) { + if (err) { + onProgress(null, true); + return callback(err); + } + onProgress({loaded: FileSize, total: FileSize}, true); + var url = getUrl({ + ForcePathStyle: self.options.ForcePathStyle, + protocol: self.options.Protocol, + domain: self.options.Domain, + bucket: params.Bucket, + region: !self.options.UseAccelerate ? params.Region : 'accelerate', + object: params.Key, + }); + url = url.substr(url.indexOf('://') + 3); + data.Location = url; + data.ETag = util.attr(data.headers, 'etag', ''); + callback(null, data); + }); + }); +} + +/** + * 上传 object + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key 文件名称,必须 + * @param {FilePath} params.FilePath 要上传的文件路径 + * @param {Function} params.onProgress 上传进度回调函数 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 为对应的 object 数据 + * @return {String} data.ETag 为对应上传文件的 ETag 值 + */ +function postObject(params, callback) { + var self = this; + var headers = {}; + var filePath = params.FilePath; + if (!filePath) { + callback({error: 'missing param FilePath'}); + return; + } + + headers['Cache-Control'] = params['CacheControl']; + headers['Content-Disposition'] = params['ContentDisposition']; + headers['Content-Encoding'] = params['ContentEncoding']; + headers['Content-MD5'] = params['ContentMD5']; + headers['Content-Length'] = params['ContentLength']; + headers['Content-Type'] = params['ContentType']; + headers['Expect'] = params['Expect']; + headers['Expires'] = params['Expires']; + headers['x-cos-acl'] = params['ACL']; + headers['x-cos-grant-read'] = params['GrantRead']; + headers['x-cos-grant-write'] = params['GrantWrite']; + headers['x-cos-grant-full-control'] = params['GrantFullControl']; + headers['x-cos-storage-class'] = params['StorageClass']; + + // 删除 Content-Length 避免签名错误 + delete headers['Content-Length']; + delete headers['content-length']; + + for (var key in params) { + if (key.indexOf('x-cos-meta-') > -1) { + headers[key] = params[key]; + } + } + + var onProgress = util.throttleOnProgress.call(self, headers['Content-Length'], params.onProgress); + + submitRequest.call(this, { + Action: 'name/cos:PostObject', + method: 'POST', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: headers, + qs: params.Query, + filePath: filePath, + onProgress: onProgress, + }, function (err, data) { + onProgress(null, true); + if (err) return callback(err); + if (data && data.headers) { + var headers = data.headers; + var ETag = headers.etag || headers.Etag || headers.ETag || ''; + var filename = filePath.substr(filePath.lastIndexOf('/') + 1); + var url = getUrl({ + ForcePathStyle: self.options.ForcePathStyle, + protocol: self.options.Protocol, + domain: self.options.Domain, + bucket: params.Bucket, + region: params.Region, + object: params.Key.replace(/\$\{filename\}/g, filename), + isLocation: true, + }); + + return callback(null, { + Location: url, + statusCode: data.statusCode, + headers: headers, + ETag: ETag, + }); + } + callback(null, data); + }); +} + +/** + * 删除 object + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {Function} callback 回调函数,必须 + * @param {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @param {Object} data 删除操作成功之后返回的数据 + */ +function deleteObject(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:DeleteObject', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + VersionId: params.VersionId, + }, function (err, data) { + if (err) { + var statusCode = err.statusCode; + if (statusCode && statusCode === 204) { + return callback(null, {statusCode: statusCode}); + } else if (statusCode && statusCode === 404) { + return callback(null, {BucketNotFound: true, statusCode: statusCode,}); + } else { + return callback(err); + } + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 object 的 权限列表 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {Object} data.AccessControlPolicy 权限列表 + */ +function getObjectAcl(params, callback) { + + submitRequest.call(this, { + Action: 'name/cos:GetObjectACL', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + action: 'acl', + }, function (err, data) { + if (err) return callback(err); + var AccessControlPolicy = data.AccessControlPolicy || {}; + var Owner = AccessControlPolicy.Owner || {}; + var Grant = AccessControlPolicy.AccessControlList && AccessControlPolicy.AccessControlList.Grant || []; + Grant = util.isArray(Grant) ? Grant : [Grant]; + var result = decodeAcl(AccessControlPolicy); + if (data.headers && data.headers['x-cos-acl']) { + result.ACL = data.headers['x-cos-acl']; + } + result = util.extend(result, { + Owner: Owner, + Grants: Grant, + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }); +} + +/** + * 设置 object 的 权限列表 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ +function putObjectAcl(params, callback) { + var headers = params.Headers; + + var xml = ''; + if (params['AccessControlPolicy']) { + var AccessControlPolicy = util.clone(params['AccessControlPolicy'] || {}); + var Grants = AccessControlPolicy.Grants || AccessControlPolicy.Grant; + Grants = util.isArray(Grants) ? Grants : [Grants]; + delete AccessControlPolicy.Grant; + delete AccessControlPolicy.Grants; + AccessControlPolicy.AccessControlList = {Grant: Grants}; + xml = util.json2xml({AccessControlPolicy: AccessControlPolicy}); + + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + } + + // Grant Header 去重 + util.each(headers, function (val, key) { + if (key.indexOf('x-cos-grant-') === 0) { + headers[key] = uniqGrant(headers[key]); + } + }); + + submitRequest.call(this, { + Action: 'name/cos:PutObjectACL', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + action: 'acl', + headers: headers, + body: xml, + }, function (err, data) { + if (err) return callback(err); + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * Options Object请求实现跨域访问的预请求。即发出一个 OPTIONS 请求给服务器以确认是否可以进行跨域操作。 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ +function optionsObject(params, callback) { + + var headers = params.Headers; + headers['Origin'] = params['Origin']; + headers['Access-Control-Request-Method'] = params['AccessControlRequestMethod']; + headers['Access-Control-Request-Headers'] = params['AccessControlRequestHeaders']; + + submitRequest.call(this, { + Action: 'name/cos:OptionsObject', + method: 'OPTIONS', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: headers, + }, function (err, data) { + if (err) { + if (err.statusCode && err.statusCode === 403) { + return callback(null, { + OptionsForbidden: true, + statusCode: err.statusCode + }); + } + return callback(err); + } + + var headers = data.headers || {}; + callback(null, { + AccessControlAllowOrigin: headers['access-control-allow-origin'], + AccessControlAllowMethods: headers['access-control-allow-methods'], + AccessControlAllowHeaders: headers['access-control-allow-headers'], + AccessControlExposeHeaders: headers['access-control-expose-headers'], + AccessControlMaxAge: headers['access-control-max-age'], + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * @param {Object} 参数列表 + * @param {String} Bucket Bucket 名称 + * @param {String} Region 地域名称 + * @param {String} Key 文件名称 + * @param {String} CopySource 源文件URL绝对路径,可以通过versionid子资源指定历史版本 + * @param {String} ACL 允许用户自定义文件权限。有效值:private,public-read默认值:private。 + * @param {String} GrantRead 赋予被授权者读的权限,格式 x-cos-grant-read: uin=" ",uin=" ",当需要给子账户授权时,uin="RootAcountID/SubAccountID",当需要给根账户授权时,uin="RootAcountID"。 + * @param {String} GrantWrite 赋予被授权者写的权限,格式 x-cos-grant-write: uin=" ",uin=" ",当需要给子账户授权时,uin="RootAcountID/SubAccountID",当需要给根账户授权时,uin="RootAcountID"。 + * @param {String} GrantFullControl 赋予被授权者读写权限,格式 x-cos-grant-full-control: uin=" ",uin=" ",当需要给子账户授权时,uin="RootAcountID/SubAccountID",当需要给根账户授权时,uin="RootAcountID"。 + * @param {String} MetadataDirective 是否拷贝元数据,枚举值:Copy, Replaced,默认值Copy。假如标记为Copy,忽略Header中的用户元数据信息直接复制;假如标记为Replaced,按Header信息修改元数据。当目标路径和原路径一致,即用户试图修改元数据时,必须为Replaced + * @param {String} CopySourceIfModifiedSince 当Object在指定时间后被修改,则执行操作,否则返回412。可与x-cos-copy-source-If-None-Match一起使用,与其他条件联合使用返回冲突。 + * @param {String} CopySourceIfUnmodifiedSince 当Object在指定时间后未被修改,则执行操作,否则返回412。可与x-cos-copy-source-If-Match一起使用,与其他条件联合使用返回冲突。 + * @param {String} CopySourceIfMatch 当Object的ETag和给定一致时,则执行操作,否则返回412。可与x-cos-copy-source-If-Unmodified-Since一起使用,与其他条件联合使用返回冲突。 + * @param {String} CopySourceIfNoneMatch 当Object的ETag和给定不一致时,则执行操作,否则返回412。可与x-cos-copy-source-If-Modified-Since一起使用,与其他条件联合使用返回冲突。 + * @param {String} StorageClass 存储级别,枚举值:存储级别,枚举值:Standard, Standard_IA,Archive;默认值:Standard + * @param {String} CacheControl 指定所有缓存机制在整个请求/响应链中必须服从的指令。 + * @param {String} ContentDisposition MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件 + * @param {String} ContentEncoding HTTP 中用来对「采用何种编码格式传输正文」进行协定的一对头部字段 + * @param {String} ContentLength 设置响应消息的实体内容的大小,单位为字节 + * @param {String} ContentType RFC 2616 中定义的 HTTP 请求内容类型(MIME),例如text/plain + * @param {String} Expect 请求的特定的服务器行为 + * @param {String} Expires 响应过期的日期和时间 + * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须 + * @param {String} ContentLanguage 指定内容语言 + * @param {String} x-cos-meta-* 允许用户自定义的头部信息,将作为 Object 元数据返回。大小限制2K。 + */ +function putObjectCopy(params, callback) { + + // 特殊处理 Cache-Control + var headers = params.Headers; + if (!headers['Cache-Control'] && !!headers['cache-control']) headers['Cache-Control'] = ''; + + var CopySource = params.CopySource || ''; + var m = CopySource.match(/^([^.]+-\d+)\.cos(v6)?\.([^.]+)\.[^/]+\/(.+)$/); + if (!m) { + callback({error: 'CopySource format error'}); + return; + } + + var SourceBucket = m[1]; + var SourceRegion = m[3]; + var SourceKey = decodeURIComponent(m[4]); + + submitRequest.call(this, { + Scope: [{ + action: 'name/cos:GetObject', + bucket: SourceBucket, + region: SourceRegion, + prefix: SourceKey, + }, { + action: 'name/cos:PutObject', + bucket: params.Bucket, + region: params.Region, + prefix: params.Key, + }], + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + VersionId: params.VersionId, + headers: params.Headers, + }, function (err, data) { + if (err) return callback(err); + var result = util.clone(data.CopyObjectResult || {}); + util.extend(result, { + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }); +} + +function uploadPartCopy(params, callback) { + + var CopySource = params.CopySource || ''; + var m = CopySource.match(/^([^.]+-\d+)\.cos(v6)?\.([^.]+)\.[^/]+\/(.+)$/); + if (!m) { + callback({error: 'CopySource format error'}); + return; + } + + var SourceBucket = m[1]; + var SourceRegion = m[3]; + var SourceKey = decodeURIComponent(m[4]); + + submitRequest.call(this, { + Scope: [{ + action: 'name/cos:GetObject', + bucket: SourceBucket, + region: SourceRegion, + prefix: SourceKey, + }, { + action: 'name/cos:PutObject', + bucket: params.Bucket, + region: params.Region, + prefix: params.Key, + }], + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + VersionId: params.VersionId, + qs: { + partNumber: params['PartNumber'], + uploadId: params['UploadId'], + }, + headers: params.Headers, + }, function (err, data) { + if (err) return callback(err); + var result = util.clone(data.CopyPartResult || {}); + util.extend(result, { + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }); +} + +function deleteMultipleObject(params, callback) { + var Objects = params.Objects || []; + var Quiet = params.Quiet; + Objects = util.isArray(Objects) ? Objects : [Objects]; + + var xml = util.json2xml({Delete: {Object: Objects, Quiet: Quiet || false}}); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + var Scope = util.map(Objects, function (v) { + return { + action: 'name/cos:DeleteObject', + bucket: params.Bucket, + region: params.Region, + prefix: v.Key, + }; + }); + + submitRequest.call(this, { + Scope: Scope, + method: 'POST', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'delete', + headers: headers, + }, function (err, data) { + if (err) return callback(err); + var DeleteResult = data.DeleteResult || {}; + var Deleted = DeleteResult.Deleted || []; + var Errors = DeleteResult.Error || []; + + Deleted = util.isArray(Deleted) ? Deleted : [Deleted]; + Errors = util.isArray(Errors) ? Errors : [Errors]; + + var result = util.clone(DeleteResult); + util.extend(result, { + Error: Errors, + Deleted: Deleted, + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }); +} + +function restoreObject(params, callback) { + var headers = params.Headers; + if (!params['RestoreRequest']) { + callback({error: 'missing param RestoreRequest'}); + return; + } + + var RestoreRequest = params.RestoreRequest || {}; + var xml = util.json2xml({RestoreRequest: RestoreRequest}); + + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:RestoreObject', + method: 'POST', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + VersionId: params.VersionId, + body: xml, + action: 'restore', + headers: headers, + }, function (err, data) { + callback(err, data); + }); +} + +/** + * 设置 Object 的标签 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Object名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Array} params.TagSet 标签设置,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/42998 + * @return {Object} data 返回数据 + */ +function putObjectTagging(params, callback) { + + var Tagging = params['Tagging'] || {}; + var Tags = Tagging.TagSet || Tagging.Tags || params['Tags'] || []; + Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); + var xml = util.json2xml({Tagging: {TagSet: {Tag: Tags}}}); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Interface: 'putObjectTagging', + Action: 'name/cos:PutObjectTagging', + method: 'PUT', + Bucket: params.Bucket, + Key: params.Key, + Region: params.Region, + body: xml, + action: 'tagging', + headers: headers, + VersionId: params.VersionId, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Object 的标签设置 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/42998 + * @return {Object} data 返回数据 + */ +function getObjectTagging(params, callback) { + + submitRequest.call(this, { + Interface: 'getObjectTagging', + Action: 'name/cos:GetObjectTagging', + method: 'GET', + Key: params.Key, + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'tagging', + VersionId: params.VersionId, + }, function (err, data) { + if (err) { + if (err.statusCode === 404 && err.error && (err.error === "Not Found" || err.error.Code === 'NoSuchTagSet')) { + var result = { + Tags: [], + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); + } + return; + } + var Tags = []; + try { + Tags = data.Tagging.TagSet.Tag || []; + } catch (e) { + } + Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); + callback(null, { + Tags: Tags, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 删除 Object 的 标签设置 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Object名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/42998 + * @return {Object} data 返回的数据 + */ +function deleteObjectTagging(params, callback) { + submitRequest.call(this, { + Interface: 'deleteObjectTagging', + Action: 'name/cos:DeleteObjectTagging', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + action: 'tagging', + VersionId: params.VersionId, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + + +// 分块上传 + + +/** + * 初始化分块上传 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {String} params.UploadId object名称,必须 + * @param {String} params.CacheControl RFC 2616 中定义的缓存策略,将作为 Object 元数据保存,非必须 + * @param {String} params.ContentDisposition RFC 2616 中定义的文件名称,将作为 Object 元数据保存 ,非必须 + * @param {String} params.ContentEncoding RFC 2616 中定义的编码格式,将作为 Object 元数据保存,非必须 + * @param {String} params.ContentType RFC 2616 中定义的内容类型(MIME),将作为 Object 元数据保存,非必须 + * @param {String} params.Expires RFC 2616 中定义的过期时间,将作为 Object 元数据保存,非必须 + * @param {String} params.ACL 允许用户自定义文件权限,非必须 + * @param {String} params.GrantRead 赋予被授权者读的权限 ,非必须 + * @param {String} params.GrantWrite 赋予被授权者写的权限 ,非必须 + * @param {String} params.GrantFullControl 赋予被授权者读写权限 ,非必须 + * @param {String} params.StorageClass 设置Object的存储级别,枚举值:Standard,Standard_IA,Archive,非必须 + * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ +function multipartInit(params, callback) { + + var self = this; + var headers = params.Headers; + + // 特殊处理 Cache-Control、Content-Type + if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = ''; + if (!headers['Content-Type'] && !headers['content-type']) headers['Content-Type'] = mime.getType(params.Key) || 'application/octet-stream'; + + submitRequest.call(self, { + Action: 'name/cos:InitiateMultipartUpload', + method: 'POST', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + action: 'uploads', + headers: params.Headers, + qs: params.Query, + }, function (err, data) { + if (err) return callback(err); + data = util.clone(data || {}); + if (data && data.InitiateMultipartUploadResult) { + return callback(null, util.extend(data.InitiateMultipartUploadResult, { + statusCode: data.statusCode, + headers: data.headers, + })); + } + callback(null, data); + }); +} + +/** + * 分块上传 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {String} params.Body 上传文件对象或字符串 + * @param {String} params.ContentLength RFC 2616 中定义的 HTTP 请求内容长度(字节),非必须 + * @param {String} params.Expect 当使用 Expect: 100-continue 时,在收到服务端确认后,才会发送请求内容,非必须 + * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须 + * @param {String} params.ContentSha1 RFC 3174 中定义的 160-bit 内容 SHA-1 算法校验值,非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {Object} data.ETag 返回的文件分块 sha1 值 + */ +function multipartUpload(params, callback) { + + var self = this; + util.getFileSize('multipartUpload', params, function () { + util.getBodyMd5(self.options.UploadCheckContentMd5, params.Body, function (md5) { + if (md5) params.Headers['Content-MD5'] = util.binaryBase64(md5); + submitRequest.call(self, { + Action: 'name/cos:UploadPart', + TaskId: params.TaskId, + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + qs: { + partNumber: params['PartNumber'], + uploadId: params['UploadId'], + }, + headers: params.Headers, + onProgress: params.onProgress, + body: params.Body || null + }, function (err, data) { + if (err) return callback(err); + callback(null, { + ETag: util.attr(data.headers, 'etag', {}), + statusCode: data.statusCode, + headers: data.headers, + }); + }); + }); + }); + +} + +/** + * 完成分块上传 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {Array} params.Parts 分块信息列表,必须 + * @param {String} params.Parts[i].PartNumber 块编号,必须 + * @param {String} params.Parts[i].ETag 分块的 sha1 校验值 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {Object} data.CompleteMultipartUpload 完成分块上传后的文件信息,包括Location, Bucket, Key 和 ETag + */ +function multipartComplete(params, callback) { + var self = this; + + var UploadId = params.UploadId; + + var Parts = params['Parts']; + + for (var i = 0, len = Parts.length; i < len; i++) { + if (Parts[i]['ETag'].indexOf('"') === 0) { + continue; + } + Parts[i]['ETag'] = '"' + Parts[i]['ETag'] + '"'; + } + + var xml = util.json2xml({CompleteMultipartUpload: {Part: Parts}}); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:CompleteMultipartUpload', + method: 'POST', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + qs: { + uploadId: UploadId + }, + body: xml, + headers: headers, + }, function (err, data) { + if (err) return callback(err); + var url = getUrl({ + ForcePathStyle: self.options.ForcePathStyle, + protocol: self.options.Protocol, + domain: self.options.Domain, + bucket: params.Bucket, + region: params.Region, + object: params.Key, + isLocation: true, + }); + var CompleteMultipartUploadResult = data.CompleteMultipartUploadResult || {}; + var result = util.extend(CompleteMultipartUploadResult, { + Location: url, + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }); +} + +/** + * 分块上传任务列表查询 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Delimiter 定界符为一个符号,如果有Prefix,则将Prefix到delimiter之间的相同路径归为一类,定义为Common Prefix,然后列出所有Common Prefix。如果没有Prefix,则从路径起点开始,非必须 + * @param {String} params.EncodingType 规定返回值的编码方式,非必须 + * @param {String} params.Prefix 前缀匹配,用来规定返回的文件前缀地址,非必须 + * @param {String} params.MaxUploads 单次返回最大的条目数量,默认1000,非必须 + * @param {String} params.KeyMarker 与upload-id-marker一起使用
当upload-id-marker未被指定时,ObjectName字母顺序大于key-marker的条目将被列出
当upload-id-marker被指定时,ObjectName字母顺序大于key-marker的条目被列出,ObjectName字母顺序等于key-marker同时UploadId大于upload-id-marker的条目将被列出,非必须 + * @param {String} params.UploadIdMarker 与key-marker一起使用
当key-marker未被指定时,upload-id-marker将被忽略
当key-marker被指定时,ObjectName字母顺序大于key-marker的条目被列出,ObjectName字母顺序等于key-marker同时UploadId大于upload-id-marker的条目将被列出,非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {Object} data.ListMultipartUploadsResult 分块上传任务信息 + */ +function multipartList(params, callback) { + var reqParams = {}; + + reqParams['delimiter'] = params['Delimiter']; + reqParams['encoding-type'] = params['EncodingType']; + reqParams['prefix'] = params['Prefix'] || ''; + + reqParams['max-uploads'] = params['MaxUploads']; + + reqParams['key-marker'] = params['KeyMarker']; + reqParams['upload-id-marker'] = params['UploadIdMarker']; + + reqParams = util.clearKey(reqParams); + + submitRequest.call(this, { + Action: 'name/cos:ListMultipartUploads', + ResourceKey: reqParams['prefix'], + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + qs: reqParams, + action: 'uploads', + }, function (err, data) { + if (err) return callback(err); + + if (data && data.ListMultipartUploadsResult) { + var Upload = data.ListMultipartUploadsResult.Upload || []; + + var CommonPrefixes = data.ListMultipartUploadsResult.CommonPrefixes || []; + + CommonPrefixes = util.isArray(CommonPrefixes) ? CommonPrefixes : [CommonPrefixes]; + Upload = util.isArray(Upload) ? Upload : [Upload]; + + data.ListMultipartUploadsResult.Upload = Upload; + data.ListMultipartUploadsResult.CommonPrefixes = CommonPrefixes; + } + var result = util.clone(data.ListMultipartUploadsResult || {}); + util.extend(result, { + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }); +} + +/** + * 上传的分块列表查询 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {String} params.UploadId 标示本次分块上传的ID,必须 + * @param {String} params.EncodingType 规定返回值的编码方式,非必须 + * @param {String} params.MaxParts 单次返回最大的条目数量,默认1000,非必须 + * @param {String} params.PartNumberMarker 默认以UTF-8二进制顺序列出条目,所有列出条目从marker开始,非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {Object} data.ListMultipartUploadsResult 分块信息 + */ +function multipartListPart(params, callback) { + var reqParams = {}; + + reqParams['uploadId'] = params['UploadId']; + reqParams['encoding-type'] = params['EncodingType']; + reqParams['max-parts'] = params['MaxParts']; + reqParams['part-number-marker'] = params['PartNumberMarker']; + + submitRequest.call(this, { + Action: 'name/cos:ListParts', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + qs: reqParams, + }, function (err, data) { + if (err) return callback(err); + var ListPartsResult = data.ListPartsResult || {}; + var Part = ListPartsResult.Part || []; + Part = util.isArray(Part) ? Part : [Part]; + + ListPartsResult.Part = Part; + var result = util.clone(ListPartsResult); + util.extend(result, { + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }); +} + +/** + * 抛弃分块上传 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {String} params.UploadId 标示本次分块上传的ID,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ +function multipartAbort(params, callback) { + var reqParams = {}; + + reqParams['uploadId'] = params['UploadId']; + submitRequest.call(this, { + Action: 'name/cos:AbortMultipartUpload', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + qs: reqParams, + }, function (err, data) { + if (err) return callback(err); + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + + +/** + * cos 内置请求 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ + function request(params, callback) { + submitRequest.call(this, { + method: params.Method, + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + action: params.Action, + headers: params.Headers, + qs: params.Query, + body: params.Body, + }, function (err, data) { + if (err) return callback(err); + if (data && data.body) { + data.Body = data.body; + delete data.body; + } + callback(err, data); + }); +} + +/** + * 获取签名 + * @param {Object} params 参数对象,必须 + * @param {String} params.Method 请求方法,必须 + * @param {String} params.Key object名称,必须 + * @param {String} params.Expires 名超时时间,单位秒,可选 + * @return {String} data 返回签名字符串 + */ +function getAuth(params) { + var self = this; + return util.getAuth({ + SecretId: params.SecretId || this.options.SecretId || '', + SecretKey: params.SecretKey || this.options.SecretKey || '', + Method: params.Method, + Key: params.Key, + Query: params.Query, + Headers: params.Headers, + Expires: params.Expires, + SystemClockOffset: self.options.SystemClockOffset, + }); +} + +/** + * 获取文件下载链接 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {String} params.Method 请求的方法,可选 + * @param {String} params.Expires 签名超时时间,单位秒,可选 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ +function getObjectUrl(params, callback) { + var self = this; + var url = getUrl({ + ForcePathStyle: self.options.ForcePathStyle, + protocol: params.Protocol || self.options.Protocol, + domain: params.Domain || self.options.Domain, + bucket: params.Bucket, + region: params.Region, + object: params.Key, + }); + + var queryParamsStr = ''; + if(params.Query){ + queryParamsStr += util.obj2str(params.Query); + } + if(params.QueryString){ + queryParamsStr += (queryParamsStr ? '&' : '') + params.QueryString; + } + + var syncUrl = url; + if (params.Sign !== undefined && !params.Sign) { + queryParamsStr && (syncUrl += '?' + queryParamsStr); + callback(null, {Url: syncUrl}); + return syncUrl; + } + var AuthData = getAuthorizationAsync.call(this, { + Action: ((params.Method || '').toUpperCase() === 'PUT' ? 'name/cos:PutObject' : 'name/cos:GetObject'), + Bucket: params.Bucket || '', + Region: params.Region || '', + Method: params.Method || 'get', + Key: params.Key, + Expires: params.Expires, + Headers: params.Headers, + Query: params.Query + }, function (err, AuthData) { + if (!callback) return; + if (err) { + callback(err); + return; + } + var signUrl = url; + signUrl += '?' + (AuthData.Authorization.indexOf('q-signature') > -1 ? + AuthData.Authorization : 'sign=' + encodeURIComponent(AuthData.Authorization)); + AuthData.XCosSecurityToken && (signUrl += '&x-cos-security-token=' + AuthData.XCosSecurityToken); + AuthData.ClientIP && (signUrl += '&clientIP=' + AuthData.ClientIP); + AuthData.ClientUA && (signUrl += '&clientUA=' + AuthData.ClientUA); + AuthData.Token && (signUrl += '&token=' + AuthData.Token); + queryParamsStr && (signUrl += '&' + queryParamsStr); + setTimeout(function () { + callback(null, {Url: signUrl}); + }); + }); + + if (AuthData) { + syncUrl += '?' + AuthData.Authorization + + (AuthData.XCosSecurityToken ? '&x-cos-security-token=' + AuthData.XCosSecurityToken : ''); + queryParamsStr && (syncUrl += '&' + queryParamsStr); + } else { + queryParamsStr && (syncUrl += '?' + queryParamsStr); + } + return syncUrl; +} + + +/** + * 私有方法 + */ +function decodeAcl(AccessControlPolicy) { + var result = { + GrantFullControl: [], + GrantWrite: [], + GrantRead: [], + GrantReadAcp: [], + GrantWriteAcp: [], + ACL: '', + }; + var GrantMap = { + 'FULL_CONTROL': 'GrantFullControl', + 'WRITE': 'GrantWrite', + 'READ': 'GrantRead', + 'READ_ACP': 'GrantReadAcp', + 'WRITE_ACP': 'GrantWriteAcp', + }; + var AccessControlList = AccessControlPolicy && AccessControlPolicy.AccessControlList || {}; + var Grant = AccessControlList.Grant; + if (Grant) { + Grant = util.isArray(Grant) ? Grant : [Grant]; + } + var PublicAcl = {READ: 0, WRITE: 0, FULL_CONTROL: 0}; + Grant && Grant.length && util.each(Grant, function (item) { + if (item.Grantee.ID === 'qcs::cam::anyone:anyone' || item.Grantee.URI === 'http://cam.qcloud.com/groups/global/AllUsers') { + PublicAcl[item.Permission] = 1; + } else if (item.Grantee.ID !== AccessControlPolicy.Owner.ID) { + result[GrantMap[item.Permission]].push('id="' + item.Grantee.ID + '"'); + } + }); + if (PublicAcl.FULL_CONTROL || (PublicAcl.WRITE && PublicAcl.READ)) { + result.ACL = 'public-read-write'; + } else if (PublicAcl.READ) { + result.ACL = 'public-read'; + } else { + result.ACL = 'private'; + } + util.each(GrantMap, function (item) { + result[item] = uniqGrant(result[item].join(',')); + }); + return result; +} + +// Grant 去重 +function uniqGrant(str) { + var arr = str.split(','); + var exist = {}; + var i, item; + for (i = 0; i < arr.length; ) { + item = arr[i].trim(); + if (exist[item]) { + arr.splice(i, 1); + } else { + exist[item] = true; + arr[i] = item; + i++; + } + } + return arr.join(','); +} + +// 生成操作 url +function getUrl(params) { + var longBucket = params.bucket; + var shortBucket = longBucket.substr(0, longBucket.lastIndexOf('-')); + var appId = longBucket.substr(longBucket.lastIndexOf('-') + 1); + var domain = params.domain; + var region = params.region; + var object = params.object; + var protocol = 'https:'; + if (!domain) { + if (['cn-south', 'cn-south-2', 'cn-north', 'cn-east', 'cn-southwest', 'sg'].indexOf(region) > -1) { + domain = '{Region}.myqcloud.com'; + } else { + domain = 'cos.{Region}.myqcloud.com'; + } + if (!params.ForcePathStyle) { + domain = '{Bucket}.' + domain; + } + } + domain = domain.replace(/\{\{AppId\}\}/ig, appId) + .replace(/\{\{Bucket\}\}/ig, shortBucket) + .replace(/\{\{Region\}\}/ig, region) + .replace(/\{\{.*?\}\}/ig, ''); + domain = domain.replace(/\{AppId\}/ig, appId) + .replace(/\{BucketName\}/ig, shortBucket) + .replace(/\{Bucket\}/ig, longBucket) + .replace(/\{Region\}/ig, region) + .replace(/\{.*?\}/ig, ''); + if (!/^[a-zA-Z]+:\/\//.test(domain)) { + domain = protocol + '//' + domain; + } + + // 去掉域名最后的斜杆 + if (domain.slice(-1) === '/') { + domain = domain.slice(0, -1); + } + var url = domain; + + if (params.ForcePathStyle) { + url += '/' + longBucket; + } + url += '/'; + if (object) { + url += util.camSafeUrlEncode(object).replace(/%2F/g, '/'); + } + + if (params.isLocation) { + url = url.replace(/^https?:\/\//, ''); + } + return url; +} + +// 异步获取签名 +function getAuthorizationAsync(params, callback) { + + var headers = util.clone(params.Headers); + delete headers['Content-Type']; + delete headers['Cache-Control']; + util.each(headers, function (v, k) { + v === '' && delete headers[k]; + }); + + var cb = function (AuthData) { + + // 检查签名格式 + var formatAllow = false; + var auth = AuthData.Authorization; + if (auth) { + if (auth.indexOf(' ') > -1) { + formatAllow = false; + } else if (auth.indexOf('q-sign-algorithm=') > -1 && + auth.indexOf('q-ak=') > -1 && + auth.indexOf('q-sign-time=') > -1 && + auth.indexOf('q-key-time=') > -1 && + auth.indexOf('q-url-param-list=') > -1) { + formatAllow = true; + } else { + try { + auth = base64.atob(auth); + if (auth.indexOf('a=') > -1 && + auth.indexOf('k=') > -1 && + auth.indexOf('t=') > -1 && + auth.indexOf('r=') > -1 && + auth.indexOf('b=') > -1) { + formatAllow = true; + } + } catch (e) {} + } + } + if (formatAllow) { + callback && callback(null, AuthData); + } else { + callback && callback('authorization error'); + } + }; + + var self = this; + var Bucket = params.Bucket || ''; + var Region = params.Region || ''; + + // PathName + var KeyName = params.Action === 'name/cos:PostObject' || !params.Key ? '' : params.Key; + if (self.options.ForcePathStyle && Bucket) { + KeyName = Bucket + '/' + KeyName; + } + var Pathname = '/' + KeyName; + + // Action、ResourceKey + var StsData = {}; + var Scope = params.Scope; + if (!Scope) { + var Action = params.Action || ''; + var ResourceKey = params.ResourceKey || params.Key || ''; + Scope = params.Scope || [{ + action: Action, + bucket: Bucket, + region: Region, + prefix: ResourceKey, + }]; + } + var ScopeKey = util.md5(JSON.stringify(Scope)); + + // STS + self._StsCache = self._StsCache ||[]; + (function () { + var i, AuthData; + for (i = self._StsCache.length - 1; i >= 0; i--) { + AuthData = self._StsCache[i]; + var compareTime = Math.round(util.getSkewTime(self.options.SystemClockOffset) / 1000) + 30; + if (AuthData.StartTime && compareTime < AuthData.StartTime || compareTime >= AuthData.ExpiredTime) { + self._StsCache.splice(i, 1); + continue; + } + if (!AuthData.ScopeLimit || AuthData.ScopeLimit && AuthData.ScopeKey === ScopeKey) { + StsData = AuthData; + break; + } + } + })(); + + var calcAuthByTmpKey = function () { + var KeyTime = StsData.StartTime && StsData.ExpiredTime ? StsData.StartTime + ';' + StsData.ExpiredTime : ''; + var Authorization = util.getAuth({ + SecretId: StsData.TmpSecretId, + SecretKey: StsData.TmpSecretKey, + Method: params.Method, + Pathname: Pathname, + Query: params.Query, + Headers: headers, + Expires: params.Expires, + SystemClockOffset: self.options.SystemClockOffset, + KeyTime: KeyTime + }); + var AuthData = { + Authorization: Authorization, + XCosSecurityToken: StsData.XCosSecurityToken || '', + Token: StsData.Token || '', + ClientIP: StsData.ClientIP || '', + ClientUA: StsData.ClientUA || '', + }; + cb(AuthData); + }; + + // 先判断是否有临时密钥 + if (StsData.ExpiredTime && StsData.ExpiredTime - (util.getSkewTime(self.options.SystemClockOffset) / 1000) > 60) { // 如果缓存的临时密钥有效,并还有超过60秒有效期就直接使用 + calcAuthByTmpKey(); + } else if (self.options.getAuthorization) { // 外部计算签名或获取临时密钥 + self.options.getAuthorization.call(self, { + Bucket: Bucket, + Region: Region, + Method: params.Method, + Key: KeyName, + Pathname: Pathname, + Query: params.Query, + Headers: headers, + Scope: Scope, + SystemClockOffset: self.options.SystemClockOffset, + }, function (AuthData) { + if (typeof AuthData === 'string') { + AuthData = {Authorization: AuthData}; + } + if (AuthData.TmpSecretId && + AuthData.TmpSecretKey && + AuthData.XCosSecurityToken && + AuthData.ExpiredTime) { + StsData = AuthData || {}; + StsData.Scope = Scope; + StsData.ScopeKey = ScopeKey; + self._StsCache.push(StsData); + calcAuthByTmpKey(); + } else { + cb(AuthData); + } + }); + } else if (self.options.getSTS) { // 外部获取临时密钥 + self.options.getSTS.call(self, { + Bucket: Bucket, + Region: Region, + }, function (data) { + StsData = data || {}; + StsData.Scope = Scope; + StsData.ScopeKey = ScopeKey; + StsData.TmpSecretId = StsData.SecretId; + StsData.TmpSecretKey = StsData.SecretKey; + self._StsCache.push(StsData); + calcAuthByTmpKey(); + }); + } else { // 内部计算获取签名 + return (function () { + var Authorization = util.getAuth({ + SecretId: params.SecretId || self.options.SecretId, + SecretKey: params.SecretKey || self.options.SecretKey, + Method: params.Method, + Pathname: Pathname, + Query: params.Query, + Headers: headers, + Expires: params.Expires, + SystemClockOffset: self.options.SystemClockOffset, + }); + var AuthData = { + Authorization: Authorization, + XCosSecurityToken: self.options.XCosSecurityToken, + }; + cb(AuthData); + return AuthData; + })(); + } + return ''; +} + +// 调整时间偏差 +function allowRetry(err) { + var allowRetry = false; + var isTimeError = false; + var serverDate = (err.headers && (err.headers.date || err.headers.Date)) || (err.error && err.error.ServerTime); + try { + var errorCode = err.error.Code; + var errorMessage = err.error.Message; + if (errorCode === 'RequestTimeTooSkewed' || + (errorCode === 'AccessDenied' && errorMessage === 'Request has expired')) { + isTimeError = true; + } + } catch (e) { + } + if (err) { + if (isTimeError && serverDate) { + var serverTime = Date.parse(serverDate); + if (this.options.CorrectClockSkew && Math.abs(util.getSkewTime(this.options.SystemClockOffset) - serverTime) >= 30000) { + console.error('error: Local time is too skewed.'); + this.options.SystemClockOffset = serverTime - Date.now(); + allowRetry = true; + } + } else if (Math.floor(err.statusCode / 100) === 5) { + allowRetry = true; + } + } + return allowRetry; +} + +// 获取签名并发起请求 +function submitRequest(params, callback) { + var self = this; + + // 处理 headers + !params.headers && (params.headers = {}); + + // 处理 query + !params.qs && (params.qs = {}); + params.VersionId && (params.qs.versionId = params.VersionId); + params.qs = util.clearKey(params.qs); + + // 清理 undefined 和 null 字段 + params.headers && (params.headers = util.clearKey(params.headers)); + params.qs && (params.qs = util.clearKey(params.qs)); + + var Query = util.clone(params.qs); + params.action && (Query[params.action] = ''); + + var next = function (tryTimes) { + var oldClockOffset = self.options.SystemClockOffset; + getAuthorizationAsync.call(self, { + Bucket: params.Bucket || '', + Region: params.Region || '', + Method: params.method, + Key: params.Key, + Query: Query, + Headers: params.headers, + Action: params.Action, + ResourceKey: params.ResourceKey, + Scope: params.Scope, + }, function (err, AuthData) { + if (err) { + callback(err); + return; + } + params.AuthData = AuthData; + _submitRequest.call(self, params, function (err, data) { + if (err && tryTimes < 2 && (oldClockOffset !== self.options.SystemClockOffset || allowRetry.call(self, err))) { + if (params.headers) { + delete params.headers.Authorization; + delete params.headers['token']; + delete params.headers['clientIP']; + delete params.headers['clientUA']; + delete params.headers['x-cos-security-token']; + } + next(tryTimes + 1); + } else { + callback(err, data); + } + }); + }); + }; + next(1); + +} + +// 发起请求 +function _submitRequest(params, callback) { + var self = this; + var TaskId = params.TaskId; + if (TaskId && !self._isRunningTask(TaskId)) return; + + var bucket = params.Bucket; + var region = params.Region; + var object = params.Key; + var method = params.method || 'GET'; + var url = params.url; + var body = params.body; + var json = params.json; + var rawBody = params.rawBody; + + // url + if (self.options.UseAccelerate) { + region = 'accelerate'; + } + url = url || getUrl({ + ForcePathStyle: self.options.ForcePathStyle, + protocol: self.options.Protocol, + domain: self.options.Domain, + bucket: bucket, + region: region, + object: object, + }); + if (params.action) { + url = url + '?' + params.action; + } + if (params.qsStr) { + if(url.indexOf('?') > -1){ + url = url + '&' + params.qsStr; + }else{ + url = url + '?' + params.qsStr; + } + } + + var opt = { + method: method, + url: url, + headers: params.headers, + qs: params.qs, + filePath: params.filePath, + body: body, + json: json, + }; + + // 获取签名 + opt.headers.Authorization = params.AuthData.Authorization; + params.AuthData.Token && (opt.headers['token'] = params.AuthData.Token); + params.AuthData.ClientIP && (opt.headers['clientIP'] = params.AuthData.ClientIP); + params.AuthData.ClientUA && (opt.headers['clientUA'] = params.AuthData.ClientUA); + params.AuthData.XCosSecurityToken && (opt.headers['x-cos-security-token'] = params.AuthData.XCosSecurityToken); + + // 清理 undefined 和 null 字段 + opt.headers && (opt.headers = util.clearKey(opt.headers)); + opt = util.clearKey(opt); + + // progress + if (params.onProgress && typeof params.onProgress === 'function') { + opt.onProgress = function (e) { + if (TaskId && !self._isRunningTask(TaskId)) return; + var loaded = e ? e.loaded : 0; + params.onProgress({loaded: loaded, total: e.total}); + }; + } + if (this.options.Timeout) { + opt.timeout = this.options.Timeout; + } + + self.options.ForcePathStyle && (opt.pathStyle = self.options.ForcePathStyle); + self.emit('before-send', opt); + var sender = REQUEST(opt, function (err, response, body) { + if (err === 'abort') return; + + // 返回内容添加 状态码 和 headers + var hasReturned; + var cb = function (err, data) { + TaskId && self.off('inner-kill-task', killTask); + if (hasReturned) return; + hasReturned = true; + var attrs = {}; + response && response.statusCode && (attrs.statusCode = response.statusCode); + response && response.headers && (attrs.headers = response.headers); + + if (err) { + err = util.extend(err || {}, attrs); + callback(err, null); + } else { + data = util.extend(data || {}, attrs); + callback(null, data); + } + sender = null; + }; + + // 请求错误,发生网络错误 + if (err) { + cb({error: err}); + return; + } + + // 不对 body 进行转换,body 直接挂载返回 + var jsonRes; + if (rawBody) { + jsonRes = {}; + jsonRes.body = body; + } else { + try { + jsonRes = body && body.indexOf('<') > -1 && body.indexOf('>') > -1 && util.xml2json(body) || {}; + } catch (e) { + jsonRes = body || {}; + } + } + + // 请求返回码不为 200 + var statusCode = response.statusCode; + var statusSuccess = Math.floor(statusCode / 100) === 2; // 200 202 204 206 + if (!statusSuccess) { + cb({error: jsonRes.Error || jsonRes}); + return; + } + + if (jsonRes.Error) { + cb({error: jsonRes.Error}); + return; + } + cb(null, jsonRes); + }); + + // kill task + var killTask = function (data) { + if (data.TaskId === TaskId) { + sender && sender.abort && sender.abort(); + self.off('inner-kill-task', killTask); + } + }; + TaskId && self.on('inner-kill-task', killTask); + +} + + +var API_MAP = { + // Bucket 相关方法 + getService: getService, // Bucket + putBucket: putBucket, + headBucket: headBucket, // Bucket + getBucket: getBucket, + deleteBucket: deleteBucket, + putBucketAcl: putBucketAcl, // BucketACL + getBucketAcl: getBucketAcl, + putBucketCors: putBucketCors, // BucketCors + getBucketCors: getBucketCors, + deleteBucketCors: deleteBucketCors, + getBucketLocation: getBucketLocation, // BucketLocation + getBucketPolicy: getBucketPolicy, // BucketPolicy + putBucketPolicy: putBucketPolicy, + deleteBucketPolicy: deleteBucketPolicy, + putBucketTagging: putBucketTagging, // BucketTagging + getBucketTagging: getBucketTagging, + deleteBucketTagging: deleteBucketTagging, + putBucketLifecycle: putBucketLifecycle, // BucketLifecycle + getBucketLifecycle: getBucketLifecycle, + deleteBucketLifecycle: deleteBucketLifecycle, + putBucketVersioning: putBucketVersioning, // BucketVersioning + getBucketVersioning: getBucketVersioning, + putBucketReplication: putBucketReplication, // BucketReplication + getBucketReplication: getBucketReplication, + deleteBucketReplication: deleteBucketReplication, + putBucketWebsite: putBucketWebsite, // BucketWebsite + getBucketWebsite: getBucketWebsite, + deleteBucketWebsite: deleteBucketWebsite, + putBucketReferer: putBucketReferer, // BucketReferer + getBucketReferer: getBucketReferer, + putBucketDomain: putBucketDomain, // BucketDomain + getBucketDomain: getBucketDomain, + deleteBucketDomain: deleteBucketDomain, + putBucketOrigin: putBucketOrigin, // BucketOrigin + getBucketOrigin: getBucketOrigin, + deleteBucketOrigin: deleteBucketOrigin, + putBucketLogging: putBucketLogging, // BucketLogging + getBucketLogging: getBucketLogging, + putBucketInventory: putBucketInventory, // BucketInventory + getBucketInventory: getBucketInventory, + listBucketInventory: listBucketInventory, + deleteBucketInventory: deleteBucketInventory, + putBucketAccelerate: putBucketAccelerate, + getBucketAccelerate: getBucketAccelerate, + + // Object 相关方法 + getObject: getObject, + headObject: headObject, + listObjectVersions: listObjectVersions, + putObject: putObject, + postObject: postObject, + deleteObject: deleteObject, + getObjectAcl: getObjectAcl, + putObjectAcl: putObjectAcl, + optionsObject: optionsObject, + putObjectCopy: putObjectCopy, + deleteMultipleObject: deleteMultipleObject, + restoreObject: restoreObject, + putObjectTagging: putObjectTagging, + getObjectTagging: getObjectTagging, + deleteObjectTagging: deleteObjectTagging, + + // 分块上传相关方法 + uploadPartCopy: uploadPartCopy, + multipartInit: multipartInit, + multipartUpload: multipartUpload, + multipartComplete: multipartComplete, + multipartList: multipartList, + multipartListPart: multipartListPart, + multipartAbort: multipartAbort, + + // 工具方法 + request: request, + getObjectUrl: getObjectUrl, + getAuth: getAuth, +}; + +module.exports.init = function (COS, task) { + task.transferToTaskMethod(API_MAP, 'postObject'); + task.transferToTaskMethod(API_MAP, 'putObject'); + util.each(API_MAP, function (fn, apiName) { + COS.prototype[apiName] = util.apiWrapper(apiName, fn); + }); +}; /***/ }), /* 18 */ /***/ (function(module, exports) { -var obj2str = function (obj) { - var i, key, val; - var list = []; - var keyList = Object.keys(obj); - for (i = 0; i < keyList.length; i++) { - key = keyList[i]; - val = obj[key] || ''; - list.push(key + '=' + encodeURIComponent(val)); - } - return list.join('&'); -}; - -var request = function (params, callback) { - var filePath = params.filePath; - var headers = params.headers || {}; - var url = params.url; - var method = params.method; - var onProgress = params.onProgress; - var requestTask; - - var cb = function (err, response) { - var H = response.header - var headers = {}; - if (H) for (var key in H) { - if (H.hasOwnProperty(key)) headers[key.toLowerCase()] = H[key]; - } - callback(err, {statusCode: response.statusCode, headers: headers}, response.data); - }; - - if (filePath) { - var fileKey; - var m = url.match(/^(https?:\/\/[^/]+\/)([^/]*\/?)(.*)$/); - if (params.pathStyle) { - fileKey = decodeURIComponent(m[3] || ''); - url = m[1] + m[2]; - } else { - fileKey = decodeURIComponent(m[2] + m[3] || ''); - url = m[1]; - } - - // 整理 postObject 参数 - var formData = { - 'key': fileKey, - 'success_action_status': 200, - 'Signature': headers.Authorization, - }; - var headerKeys = [ - 'Cache-Control', - 'Content-Type', - 'Content-Disposition', - 'Content-Encoding', - 'Expires', - 'x-cos-storage-class', - 'x-cos-security-token', - ]; - for (var i in params.headers) { - if (params.headers.hasOwnProperty(i) && (i.indexOf('x-cos-meta-') > -1 || headerKeys.indexOf(i) > -1)) { - formData[i] = params.headers[i]; - } - } - headers['x-cos-acl'] && (formData.acl = headers['x-cos-acl']); - !formData['Content-Type'] && (formData['Content-Type'] = ''); - - requestTask = wx.uploadFile({ - url: url, - method: method, - name: 'file', - header: headers, - filePath: filePath, - formData: formData, - timeout: params.timeout, - success: function (response) { - cb(null, response); - }, - fail: function (response) { - cb(response.errMsg, response); - } - }); - requestTask.onProgressUpdate(function (res) { - onProgress && onProgress({ - loaded: res.totalBytesSent, - total: res.totalBytesExpectedToSend, - progress: res.progress / 100 - }); - }); - } else { - var qsStr = params.qs && obj2str(params.qs) || ''; - if (qsStr) { - url += (url.indexOf('?') > -1 ? '&' : '?') + qsStr; - } - headers['Content-Length'] && (delete headers['Content-Length']); - requestTask = wx.request({ - url: url, - method: method, - header: headers, - dataType: 'text', - data: params.body, - timeout: params.timeout, - success: function (response) { - cb(null, response); - }, - fail: function (response) { - cb(response.errMsg, response); - } - }); - } - - return requestTask; -}; - -module.exports = request; +var obj2str = function (obj) { + var i, key, val; + var list = []; + var keyList = Object.keys(obj); + for (i = 0; i < keyList.length; i++) { + key = keyList[i]; + val = obj[key] || ''; + list.push(key + '=' + encodeURIComponent(val)); + } + return list.join('&'); +}; + +var request = function (params, callback) { + var filePath = params.filePath; + var headers = params.headers || {}; + var url = params.url; + var method = params.method; + var onProgress = params.onProgress; + var requestTask; + + var cb = function (err, response) { + var H = response.header + var headers = {}; + if (H) for (var key in H) { + if (H.hasOwnProperty(key)) headers[key.toLowerCase()] = H[key]; + } + callback(err, {statusCode: response.statusCode, headers: headers}, response.data); + }; + + if (filePath) { + var fileKey; + var m = url.match(/^(https?:\/\/[^/]+\/)([^/]*\/?)(.*)$/); + if (params.pathStyle) { + fileKey = decodeURIComponent(m[3] || ''); + url = m[1] + m[2]; + } else { + fileKey = decodeURIComponent(m[2] + m[3] || ''); + url = m[1]; + } + + // 整理 postObject 参数 + var formData = { + 'key': fileKey, + 'success_action_status': 200, + 'Signature': headers.Authorization, + }; + var headerKeys = [ + 'Cache-Control', + 'Content-Type', + 'Content-Disposition', + 'Content-Encoding', + 'Expires', + 'x-cos-storage-class', + 'x-cos-security-token', + ]; + for (var i in params.headers) { + if (params.headers.hasOwnProperty(i) && (i.indexOf('x-cos-meta-') > -1 || headerKeys.indexOf(i) > -1)) { + formData[i] = params.headers[i]; + } + } + headers['x-cos-acl'] && (formData.acl = headers['x-cos-acl']); + !formData['Content-Type'] && (formData['Content-Type'] = ''); + + requestTask = wx.uploadFile({ + url: url, + method: method, + name: 'file', + header: headers, + filePath: filePath, + formData: formData, + timeout: params.timeout, + success: function (response) { + cb(null, response); + }, + fail: function (response) { + cb(response.errMsg, response); + } + }); + requestTask.onProgressUpdate(function (res) { + onProgress && onProgress({ + loaded: res.totalBytesSent, + total: res.totalBytesExpectedToSend, + progress: res.progress / 100 + }); + }); + } else { + var qsStr = params.qs && obj2str(params.qs) || ''; + if (qsStr) { + url += (url.indexOf('?') > -1 ? '&' : '?') + qsStr; + } + headers['Content-Length'] && (delete headers['Content-Length']); + requestTask = wx.request({ + url: url, + method: method, + header: headers, + dataType: 'text', + data: params.body, + timeout: params.timeout, + success: function (response) { + cb(null, response); + }, + fail: function (response) { + cb(response.errMsg, response); + } + }); + } + + return requestTask; +}; + +module.exports = request; + + +/***/ }), +/* 19 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +let Mime = __webpack_require__(20); +module.exports = new Mime(__webpack_require__(21), __webpack_require__(22)); + + +/***/ }), +/* 20 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/** + * @param typeMap [Object] Map of MIME type -> Array[extensions] + * @param ... + */ +function Mime() { + this._types = Object.create(null); + this._extensions = Object.create(null); + + for (let i = 0; i < arguments.length; i++) { + this.define(arguments[i]); + } + + this.define = this.define.bind(this); + this.getType = this.getType.bind(this); + this.getExtension = this.getExtension.bind(this); +} + +/** + * Define mimetype -> extension mappings. Each key is a mime-type that maps + * to an array of extensions associated with the type. The first extension is + * used as the default extension for the type. + * + * e.g. mime.define({'audio/ogg', ['oga', 'ogg', 'spx']}); + * + * If a type declares an extension that has already been defined, an error will + * be thrown. To suppress this error and force the extension to be associated + * with the new type, pass `force`=true. Alternatively, you may prefix the + * extension with "*" to map the type to extension, without mapping the + * extension to the type. + * + * e.g. mime.define({'audio/wav', ['wav']}, {'audio/x-wav', ['*wav']}); + * + * + * @param map (Object) type definitions + * @param force (Boolean) if true, force overriding of existing definitions + */ +Mime.prototype.define = function(typeMap, force) { + for (let type in typeMap) { + let extensions = typeMap[type].map(function(t) { + return t.toLowerCase(); + }); + type = type.toLowerCase(); + + for (let i = 0; i < extensions.length; i++) { + const ext = extensions[i]; + + // '*' prefix = not the preferred type for this extension. So fixup the + // extension, and skip it. + if (ext[0] === '*') { + continue; + } + + if (!force && (ext in this._types)) { + throw new Error( + 'Attempt to change mapping for "' + ext + + '" extension from "' + this._types[ext] + '" to "' + type + + '". Pass `force=true` to allow this, otherwise remove "' + ext + + '" from the list of extensions for "' + type + '".' + ); + } + + this._types[ext] = type; + } + + // Use first extension as default + if (force || !this._extensions[type]) { + const ext = extensions[0]; + this._extensions[type] = (ext[0] !== '*') ? ext : ext.substr(1); + } + } +}; + +/** + * Lookup a mime type based on extension + */ +Mime.prototype.getType = function(path) { + path = String(path); + let last = path.replace(/^.*[/\\]/, '').toLowerCase(); + let ext = last.replace(/^.*\./, '').toLowerCase(); + + let hasPath = last.length < path.length; + let hasDot = ext.length < last.length - 1; + + return (hasDot || !hasPath) && this._types[ext] || null; +}; + +/** + * Return file extension associated with a mime type + */ +Mime.prototype.getExtension = function(type) { + type = /^\s*([^;\s]*)/.test(type) && RegExp.$1; + return type && this._extensions[type.toLowerCase()] || null; +}; + +module.exports = Mime; + + +/***/ }), +/* 21 */ +/***/ (function(module, exports) { + +module.exports = {"application/andrew-inset":["ez"],"application/applixware":["aw"],"application/atom+xml":["atom"],"application/atomcat+xml":["atomcat"],"application/atomdeleted+xml":["atomdeleted"],"application/atomsvc+xml":["atomsvc"],"application/atsc-dwd+xml":["dwd"],"application/atsc-held+xml":["held"],"application/atsc-rsat+xml":["rsat"],"application/bdoc":["bdoc"],"application/calendar+xml":["xcs"],"application/ccxml+xml":["ccxml"],"application/cdfx+xml":["cdfx"],"application/cdmi-capability":["cdmia"],"application/cdmi-container":["cdmic"],"application/cdmi-domain":["cdmid"],"application/cdmi-object":["cdmio"],"application/cdmi-queue":["cdmiq"],"application/cu-seeme":["cu"],"application/dash+xml":["mpd"],"application/davmount+xml":["davmount"],"application/docbook+xml":["dbk"],"application/dssc+der":["dssc"],"application/dssc+xml":["xdssc"],"application/ecmascript":["ecma","es"],"application/emma+xml":["emma"],"application/emotionml+xml":["emotionml"],"application/epub+zip":["epub"],"application/exi":["exi"],"application/fdt+xml":["fdt"],"application/font-tdpfr":["pfr"],"application/geo+json":["geojson"],"application/gml+xml":["gml"],"application/gpx+xml":["gpx"],"application/gxf":["gxf"],"application/gzip":["gz"],"application/hjson":["hjson"],"application/hyperstudio":["stk"],"application/inkml+xml":["ink","inkml"],"application/ipfix":["ipfix"],"application/its+xml":["its"],"application/java-archive":["jar","war","ear"],"application/java-serialized-object":["ser"],"application/java-vm":["class"],"application/javascript":["js","mjs"],"application/json":["json","map"],"application/json5":["json5"],"application/jsonml+json":["jsonml"],"application/ld+json":["jsonld"],"application/lgr+xml":["lgr"],"application/lost+xml":["lostxml"],"application/mac-binhex40":["hqx"],"application/mac-compactpro":["cpt"],"application/mads+xml":["mads"],"application/manifest+json":["webmanifest"],"application/marc":["mrc"],"application/marcxml+xml":["mrcx"],"application/mathematica":["ma","nb","mb"],"application/mathml+xml":["mathml"],"application/mbox":["mbox"],"application/mediaservercontrol+xml":["mscml"],"application/metalink+xml":["metalink"],"application/metalink4+xml":["meta4"],"application/mets+xml":["mets"],"application/mmt-aei+xml":["maei"],"application/mmt-usd+xml":["musd"],"application/mods+xml":["mods"],"application/mp21":["m21","mp21"],"application/mp4":["mp4s","m4p"],"application/mrb-consumer+xml":["*xdf"],"application/mrb-publish+xml":["*xdf"],"application/msword":["doc","dot"],"application/mxf":["mxf"],"application/n-quads":["nq"],"application/n-triples":["nt"],"application/node":["cjs"],"application/octet-stream":["bin","dms","lrf","mar","so","dist","distz","pkg","bpk","dump","elc","deploy","exe","dll","deb","dmg","iso","img","msi","msp","msm","buffer"],"application/oda":["oda"],"application/oebps-package+xml":["opf"],"application/ogg":["ogx"],"application/omdoc+xml":["omdoc"],"application/onenote":["onetoc","onetoc2","onetmp","onepkg"],"application/oxps":["oxps"],"application/p2p-overlay+xml":["relo"],"application/patch-ops-error+xml":["*xer"],"application/pdf":["pdf"],"application/pgp-encrypted":["pgp"],"application/pgp-signature":["asc","sig"],"application/pics-rules":["prf"],"application/pkcs10":["p10"],"application/pkcs7-mime":["p7m","p7c"],"application/pkcs7-signature":["p7s"],"application/pkcs8":["p8"],"application/pkix-attr-cert":["ac"],"application/pkix-cert":["cer"],"application/pkix-crl":["crl"],"application/pkix-pkipath":["pkipath"],"application/pkixcmp":["pki"],"application/pls+xml":["pls"],"application/postscript":["ai","eps","ps"],"application/provenance+xml":["provx"],"application/pskc+xml":["pskcxml"],"application/raml+yaml":["raml"],"application/rdf+xml":["rdf","owl"],"application/reginfo+xml":["rif"],"application/relax-ng-compact-syntax":["rnc"],"application/resource-lists+xml":["rl"],"application/resource-lists-diff+xml":["rld"],"application/rls-services+xml":["rs"],"application/route-apd+xml":["rapd"],"application/route-s-tsid+xml":["sls"],"application/route-usd+xml":["rusd"],"application/rpki-ghostbusters":["gbr"],"application/rpki-manifest":["mft"],"application/rpki-roa":["roa"],"application/rsd+xml":["rsd"],"application/rss+xml":["rss"],"application/rtf":["rtf"],"application/sbml+xml":["sbml"],"application/scvp-cv-request":["scq"],"application/scvp-cv-response":["scs"],"application/scvp-vp-request":["spq"],"application/scvp-vp-response":["spp"],"application/sdp":["sdp"],"application/senml+xml":["senmlx"],"application/sensml+xml":["sensmlx"],"application/set-payment-initiation":["setpay"],"application/set-registration-initiation":["setreg"],"application/shf+xml":["shf"],"application/sieve":["siv","sieve"],"application/smil+xml":["smi","smil"],"application/sparql-query":["rq"],"application/sparql-results+xml":["srx"],"application/srgs":["gram"],"application/srgs+xml":["grxml"],"application/sru+xml":["sru"],"application/ssdl+xml":["ssdl"],"application/ssml+xml":["ssml"],"application/swid+xml":["swidtag"],"application/tei+xml":["tei","teicorpus"],"application/thraud+xml":["tfi"],"application/timestamped-data":["tsd"],"application/toml":["toml"],"application/ttml+xml":["ttml"],"application/ubjson":["ubj"],"application/urc-ressheet+xml":["rsheet"],"application/urc-targetdesc+xml":["td"],"application/voicexml+xml":["vxml"],"application/wasm":["wasm"],"application/widget":["wgt"],"application/winhlp":["hlp"],"application/wsdl+xml":["wsdl"],"application/wspolicy+xml":["wspolicy"],"application/xaml+xml":["xaml"],"application/xcap-att+xml":["xav"],"application/xcap-caps+xml":["xca"],"application/xcap-diff+xml":["xdf"],"application/xcap-el+xml":["xel"],"application/xcap-error+xml":["xer"],"application/xcap-ns+xml":["xns"],"application/xenc+xml":["xenc"],"application/xhtml+xml":["xhtml","xht"],"application/xliff+xml":["xlf"],"application/xml":["xml","xsl","xsd","rng"],"application/xml-dtd":["dtd"],"application/xop+xml":["xop"],"application/xproc+xml":["xpl"],"application/xslt+xml":["*xsl","xslt"],"application/xspf+xml":["xspf"],"application/xv+xml":["mxml","xhvml","xvml","xvm"],"application/yang":["yang"],"application/yin+xml":["yin"],"application/zip":["zip"],"audio/3gpp":["*3gpp"],"audio/adpcm":["adp"],"audio/amr":["amr"],"audio/basic":["au","snd"],"audio/midi":["mid","midi","kar","rmi"],"audio/mobile-xmf":["mxmf"],"audio/mp3":["*mp3"],"audio/mp4":["m4a","mp4a"],"audio/mpeg":["mpga","mp2","mp2a","mp3","m2a","m3a"],"audio/ogg":["oga","ogg","spx","opus"],"audio/s3m":["s3m"],"audio/silk":["sil"],"audio/wav":["wav"],"audio/wave":["*wav"],"audio/webm":["weba"],"audio/xm":["xm"],"font/collection":["ttc"],"font/otf":["otf"],"font/ttf":["ttf"],"font/woff":["woff"],"font/woff2":["woff2"],"image/aces":["exr"],"image/apng":["apng"],"image/avif":["avif"],"image/bmp":["bmp"],"image/cgm":["cgm"],"image/dicom-rle":["drle"],"image/emf":["emf"],"image/fits":["fits"],"image/g3fax":["g3"],"image/gif":["gif"],"image/heic":["heic"],"image/heic-sequence":["heics"],"image/heif":["heif"],"image/heif-sequence":["heifs"],"image/hej2k":["hej2"],"image/hsj2":["hsj2"],"image/ief":["ief"],"image/jls":["jls"],"image/jp2":["jp2","jpg2"],"image/jpeg":["jpeg","jpg","jpe"],"image/jph":["jph"],"image/jphc":["jhc"],"image/jpm":["jpm"],"image/jpx":["jpx","jpf"],"image/jxr":["jxr"],"image/jxra":["jxra"],"image/jxrs":["jxrs"],"image/jxs":["jxs"],"image/jxsc":["jxsc"],"image/jxsi":["jxsi"],"image/jxss":["jxss"],"image/ktx":["ktx"],"image/ktx2":["ktx2"],"image/png":["png"],"image/sgi":["sgi"],"image/svg+xml":["svg","svgz"],"image/t38":["t38"],"image/tiff":["tif","tiff"],"image/tiff-fx":["tfx"],"image/webp":["webp"],"image/wmf":["wmf"],"message/disposition-notification":["disposition-notification"],"message/global":["u8msg"],"message/global-delivery-status":["u8dsn"],"message/global-disposition-notification":["u8mdn"],"message/global-headers":["u8hdr"],"message/rfc822":["eml","mime"],"model/3mf":["3mf"],"model/gltf+json":["gltf"],"model/gltf-binary":["glb"],"model/iges":["igs","iges"],"model/mesh":["msh","mesh","silo"],"model/mtl":["mtl"],"model/obj":["obj"],"model/stl":["stl"],"model/vrml":["wrl","vrml"],"model/x3d+binary":["*x3db","x3dbz"],"model/x3d+fastinfoset":["x3db"],"model/x3d+vrml":["*x3dv","x3dvz"],"model/x3d+xml":["x3d","x3dz"],"model/x3d-vrml":["x3dv"],"text/cache-manifest":["appcache","manifest"],"text/calendar":["ics","ifb"],"text/coffeescript":["coffee","litcoffee"],"text/css":["css"],"text/csv":["csv"],"text/html":["html","htm","shtml"],"text/jade":["jade"],"text/jsx":["jsx"],"text/less":["less"],"text/markdown":["markdown","md"],"text/mathml":["mml"],"text/mdx":["mdx"],"text/n3":["n3"],"text/plain":["txt","text","conf","def","list","log","in","ini"],"text/richtext":["rtx"],"text/rtf":["*rtf"],"text/sgml":["sgml","sgm"],"text/shex":["shex"],"text/slim":["slim","slm"],"text/spdx":["spdx"],"text/stylus":["stylus","styl"],"text/tab-separated-values":["tsv"],"text/troff":["t","tr","roff","man","me","ms"],"text/turtle":["ttl"],"text/uri-list":["uri","uris","urls"],"text/vcard":["vcard"],"text/vtt":["vtt"],"text/xml":["*xml"],"text/yaml":["yaml","yml"],"video/3gpp":["3gp","3gpp"],"video/3gpp2":["3g2"],"video/h261":["h261"],"video/h263":["h263"],"video/h264":["h264"],"video/iso.segment":["m4s"],"video/jpeg":["jpgv"],"video/jpm":["*jpm","jpgm"],"video/mj2":["mj2","mjp2"],"video/mp2t":["ts"],"video/mp4":["mp4","mp4v","mpg4"],"video/mpeg":["mpeg","mpg","mpe","m1v","m2v"],"video/ogg":["ogv"],"video/quicktime":["qt","mov"],"video/webm":["webm"]}; + +/***/ }), +/* 22 */ +/***/ (function(module, exports) { + +module.exports = {"application/prs.cww":["cww"],"application/vnd.1000minds.decision-model+xml":["1km"],"application/vnd.3gpp.pic-bw-large":["plb"],"application/vnd.3gpp.pic-bw-small":["psb"],"application/vnd.3gpp.pic-bw-var":["pvb"],"application/vnd.3gpp2.tcap":["tcap"],"application/vnd.3m.post-it-notes":["pwn"],"application/vnd.accpac.simply.aso":["aso"],"application/vnd.accpac.simply.imp":["imp"],"application/vnd.acucobol":["acu"],"application/vnd.acucorp":["atc","acutc"],"application/vnd.adobe.air-application-installer-package+zip":["air"],"application/vnd.adobe.formscentral.fcdt":["fcdt"],"application/vnd.adobe.fxp":["fxp","fxpl"],"application/vnd.adobe.xdp+xml":["xdp"],"application/vnd.adobe.xfdf":["xfdf"],"application/vnd.ahead.space":["ahead"],"application/vnd.airzip.filesecure.azf":["azf"],"application/vnd.airzip.filesecure.azs":["azs"],"application/vnd.amazon.ebook":["azw"],"application/vnd.americandynamics.acc":["acc"],"application/vnd.amiga.ami":["ami"],"application/vnd.android.package-archive":["apk"],"application/vnd.anser-web-certificate-issue-initiation":["cii"],"application/vnd.anser-web-funds-transfer-initiation":["fti"],"application/vnd.antix.game-component":["atx"],"application/vnd.apple.installer+xml":["mpkg"],"application/vnd.apple.keynote":["key"],"application/vnd.apple.mpegurl":["m3u8"],"application/vnd.apple.numbers":["numbers"],"application/vnd.apple.pages":["pages"],"application/vnd.apple.pkpass":["pkpass"],"application/vnd.aristanetworks.swi":["swi"],"application/vnd.astraea-software.iota":["iota"],"application/vnd.audiograph":["aep"],"application/vnd.balsamiq.bmml+xml":["bmml"],"application/vnd.blueice.multipass":["mpm"],"application/vnd.bmi":["bmi"],"application/vnd.businessobjects":["rep"],"application/vnd.chemdraw+xml":["cdxml"],"application/vnd.chipnuts.karaoke-mmd":["mmd"],"application/vnd.cinderella":["cdy"],"application/vnd.citationstyles.style+xml":["csl"],"application/vnd.claymore":["cla"],"application/vnd.cloanto.rp9":["rp9"],"application/vnd.clonk.c4group":["c4g","c4d","c4f","c4p","c4u"],"application/vnd.cluetrust.cartomobile-config":["c11amc"],"application/vnd.cluetrust.cartomobile-config-pkg":["c11amz"],"application/vnd.commonspace":["csp"],"application/vnd.contact.cmsg":["cdbcmsg"],"application/vnd.cosmocaller":["cmc"],"application/vnd.crick.clicker":["clkx"],"application/vnd.crick.clicker.keyboard":["clkk"],"application/vnd.crick.clicker.palette":["clkp"],"application/vnd.crick.clicker.template":["clkt"],"application/vnd.crick.clicker.wordbank":["clkw"],"application/vnd.criticaltools.wbs+xml":["wbs"],"application/vnd.ctc-posml":["pml"],"application/vnd.cups-ppd":["ppd"],"application/vnd.curl.car":["car"],"application/vnd.curl.pcurl":["pcurl"],"application/vnd.dart":["dart"],"application/vnd.data-vision.rdz":["rdz"],"application/vnd.dbf":["dbf"],"application/vnd.dece.data":["uvf","uvvf","uvd","uvvd"],"application/vnd.dece.ttml+xml":["uvt","uvvt"],"application/vnd.dece.unspecified":["uvx","uvvx"],"application/vnd.dece.zip":["uvz","uvvz"],"application/vnd.denovo.fcselayout-link":["fe_launch"],"application/vnd.dna":["dna"],"application/vnd.dolby.mlp":["mlp"],"application/vnd.dpgraph":["dpg"],"application/vnd.dreamfactory":["dfac"],"application/vnd.ds-keypoint":["kpxx"],"application/vnd.dvb.ait":["ait"],"application/vnd.dvb.service":["svc"],"application/vnd.dynageo":["geo"],"application/vnd.ecowin.chart":["mag"],"application/vnd.enliven":["nml"],"application/vnd.epson.esf":["esf"],"application/vnd.epson.msf":["msf"],"application/vnd.epson.quickanime":["qam"],"application/vnd.epson.salt":["slt"],"application/vnd.epson.ssf":["ssf"],"application/vnd.eszigno3+xml":["es3","et3"],"application/vnd.ezpix-album":["ez2"],"application/vnd.ezpix-package":["ez3"],"application/vnd.fdf":["fdf"],"application/vnd.fdsn.mseed":["mseed"],"application/vnd.fdsn.seed":["seed","dataless"],"application/vnd.flographit":["gph"],"application/vnd.fluxtime.clip":["ftc"],"application/vnd.framemaker":["fm","frame","maker","book"],"application/vnd.frogans.fnc":["fnc"],"application/vnd.frogans.ltf":["ltf"],"application/vnd.fsc.weblaunch":["fsc"],"application/vnd.fujitsu.oasys":["oas"],"application/vnd.fujitsu.oasys2":["oa2"],"application/vnd.fujitsu.oasys3":["oa3"],"application/vnd.fujitsu.oasysgp":["fg5"],"application/vnd.fujitsu.oasysprs":["bh2"],"application/vnd.fujixerox.ddd":["ddd"],"application/vnd.fujixerox.docuworks":["xdw"],"application/vnd.fujixerox.docuworks.binder":["xbd"],"application/vnd.fuzzysheet":["fzs"],"application/vnd.genomatix.tuxedo":["txd"],"application/vnd.geogebra.file":["ggb"],"application/vnd.geogebra.tool":["ggt"],"application/vnd.geometry-explorer":["gex","gre"],"application/vnd.geonext":["gxt"],"application/vnd.geoplan":["g2w"],"application/vnd.geospace":["g3w"],"application/vnd.gmx":["gmx"],"application/vnd.google-apps.document":["gdoc"],"application/vnd.google-apps.presentation":["gslides"],"application/vnd.google-apps.spreadsheet":["gsheet"],"application/vnd.google-earth.kml+xml":["kml"],"application/vnd.google-earth.kmz":["kmz"],"application/vnd.grafeq":["gqf","gqs"],"application/vnd.groove-account":["gac"],"application/vnd.groove-help":["ghf"],"application/vnd.groove-identity-message":["gim"],"application/vnd.groove-injector":["grv"],"application/vnd.groove-tool-message":["gtm"],"application/vnd.groove-tool-template":["tpl"],"application/vnd.groove-vcard":["vcg"],"application/vnd.hal+xml":["hal"],"application/vnd.handheld-entertainment+xml":["zmm"],"application/vnd.hbci":["hbci"],"application/vnd.hhe.lesson-player":["les"],"application/vnd.hp-hpgl":["hpgl"],"application/vnd.hp-hpid":["hpid"],"application/vnd.hp-hps":["hps"],"application/vnd.hp-jlyt":["jlt"],"application/vnd.hp-pcl":["pcl"],"application/vnd.hp-pclxl":["pclxl"],"application/vnd.hydrostatix.sof-data":["sfd-hdstx"],"application/vnd.ibm.minipay":["mpy"],"application/vnd.ibm.modcap":["afp","listafp","list3820"],"application/vnd.ibm.rights-management":["irm"],"application/vnd.ibm.secure-container":["sc"],"application/vnd.iccprofile":["icc","icm"],"application/vnd.igloader":["igl"],"application/vnd.immervision-ivp":["ivp"],"application/vnd.immervision-ivu":["ivu"],"application/vnd.insors.igm":["igm"],"application/vnd.intercon.formnet":["xpw","xpx"],"application/vnd.intergeo":["i2g"],"application/vnd.intu.qbo":["qbo"],"application/vnd.intu.qfx":["qfx"],"application/vnd.ipunplugged.rcprofile":["rcprofile"],"application/vnd.irepository.package+xml":["irp"],"application/vnd.is-xpr":["xpr"],"application/vnd.isac.fcs":["fcs"],"application/vnd.jam":["jam"],"application/vnd.jcp.javame.midlet-rms":["rms"],"application/vnd.jisp":["jisp"],"application/vnd.joost.joda-archive":["joda"],"application/vnd.kahootz":["ktz","ktr"],"application/vnd.kde.karbon":["karbon"],"application/vnd.kde.kchart":["chrt"],"application/vnd.kde.kformula":["kfo"],"application/vnd.kde.kivio":["flw"],"application/vnd.kde.kontour":["kon"],"application/vnd.kde.kpresenter":["kpr","kpt"],"application/vnd.kde.kspread":["ksp"],"application/vnd.kde.kword":["kwd","kwt"],"application/vnd.kenameaapp":["htke"],"application/vnd.kidspiration":["kia"],"application/vnd.kinar":["kne","knp"],"application/vnd.koan":["skp","skd","skt","skm"],"application/vnd.kodak-descriptor":["sse"],"application/vnd.las.las+xml":["lasxml"],"application/vnd.llamagraphics.life-balance.desktop":["lbd"],"application/vnd.llamagraphics.life-balance.exchange+xml":["lbe"],"application/vnd.lotus-1-2-3":["123"],"application/vnd.lotus-approach":["apr"],"application/vnd.lotus-freelance":["pre"],"application/vnd.lotus-notes":["nsf"],"application/vnd.lotus-organizer":["org"],"application/vnd.lotus-screencam":["scm"],"application/vnd.lotus-wordpro":["lwp"],"application/vnd.macports.portpkg":["portpkg"],"application/vnd.mcd":["mcd"],"application/vnd.medcalcdata":["mc1"],"application/vnd.mediastation.cdkey":["cdkey"],"application/vnd.mfer":["mwf"],"application/vnd.mfmp":["mfm"],"application/vnd.micrografx.flo":["flo"],"application/vnd.micrografx.igx":["igx"],"application/vnd.mif":["mif"],"application/vnd.mobius.daf":["daf"],"application/vnd.mobius.dis":["dis"],"application/vnd.mobius.mbk":["mbk"],"application/vnd.mobius.mqy":["mqy"],"application/vnd.mobius.msl":["msl"],"application/vnd.mobius.plc":["plc"],"application/vnd.mobius.txf":["txf"],"application/vnd.mophun.application":["mpn"],"application/vnd.mophun.certificate":["mpc"],"application/vnd.mozilla.xul+xml":["xul"],"application/vnd.ms-artgalry":["cil"],"application/vnd.ms-cab-compressed":["cab"],"application/vnd.ms-excel":["xls","xlm","xla","xlc","xlt","xlw"],"application/vnd.ms-excel.addin.macroenabled.12":["xlam"],"application/vnd.ms-excel.sheet.binary.macroenabled.12":["xlsb"],"application/vnd.ms-excel.sheet.macroenabled.12":["xlsm"],"application/vnd.ms-excel.template.macroenabled.12":["xltm"],"application/vnd.ms-fontobject":["eot"],"application/vnd.ms-htmlhelp":["chm"],"application/vnd.ms-ims":["ims"],"application/vnd.ms-lrm":["lrm"],"application/vnd.ms-officetheme":["thmx"],"application/vnd.ms-outlook":["msg"],"application/vnd.ms-pki.seccat":["cat"],"application/vnd.ms-pki.stl":["*stl"],"application/vnd.ms-powerpoint":["ppt","pps","pot"],"application/vnd.ms-powerpoint.addin.macroenabled.12":["ppam"],"application/vnd.ms-powerpoint.presentation.macroenabled.12":["pptm"],"application/vnd.ms-powerpoint.slide.macroenabled.12":["sldm"],"application/vnd.ms-powerpoint.slideshow.macroenabled.12":["ppsm"],"application/vnd.ms-powerpoint.template.macroenabled.12":["potm"],"application/vnd.ms-project":["mpp","mpt"],"application/vnd.ms-word.document.macroenabled.12":["docm"],"application/vnd.ms-word.template.macroenabled.12":["dotm"],"application/vnd.ms-works":["wps","wks","wcm","wdb"],"application/vnd.ms-wpl":["wpl"],"application/vnd.ms-xpsdocument":["xps"],"application/vnd.mseq":["mseq"],"application/vnd.musician":["mus"],"application/vnd.muvee.style":["msty"],"application/vnd.mynfc":["taglet"],"application/vnd.neurolanguage.nlu":["nlu"],"application/vnd.nitf":["ntf","nitf"],"application/vnd.noblenet-directory":["nnd"],"application/vnd.noblenet-sealer":["nns"],"application/vnd.noblenet-web":["nnw"],"application/vnd.nokia.n-gage.ac+xml":["*ac"],"application/vnd.nokia.n-gage.data":["ngdat"],"application/vnd.nokia.n-gage.symbian.install":["n-gage"],"application/vnd.nokia.radio-preset":["rpst"],"application/vnd.nokia.radio-presets":["rpss"],"application/vnd.novadigm.edm":["edm"],"application/vnd.novadigm.edx":["edx"],"application/vnd.novadigm.ext":["ext"],"application/vnd.oasis.opendocument.chart":["odc"],"application/vnd.oasis.opendocument.chart-template":["otc"],"application/vnd.oasis.opendocument.database":["odb"],"application/vnd.oasis.opendocument.formula":["odf"],"application/vnd.oasis.opendocument.formula-template":["odft"],"application/vnd.oasis.opendocument.graphics":["odg"],"application/vnd.oasis.opendocument.graphics-template":["otg"],"application/vnd.oasis.opendocument.image":["odi"],"application/vnd.oasis.opendocument.image-template":["oti"],"application/vnd.oasis.opendocument.presentation":["odp"],"application/vnd.oasis.opendocument.presentation-template":["otp"],"application/vnd.oasis.opendocument.spreadsheet":["ods"],"application/vnd.oasis.opendocument.spreadsheet-template":["ots"],"application/vnd.oasis.opendocument.text":["odt"],"application/vnd.oasis.opendocument.text-master":["odm"],"application/vnd.oasis.opendocument.text-template":["ott"],"application/vnd.oasis.opendocument.text-web":["oth"],"application/vnd.olpc-sugar":["xo"],"application/vnd.oma.dd2+xml":["dd2"],"application/vnd.openblox.game+xml":["obgx"],"application/vnd.openofficeorg.extension":["oxt"],"application/vnd.openstreetmap.data+xml":["osm"],"application/vnd.openxmlformats-officedocument.presentationml.presentation":["pptx"],"application/vnd.openxmlformats-officedocument.presentationml.slide":["sldx"],"application/vnd.openxmlformats-officedocument.presentationml.slideshow":["ppsx"],"application/vnd.openxmlformats-officedocument.presentationml.template":["potx"],"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":["xlsx"],"application/vnd.openxmlformats-officedocument.spreadsheetml.template":["xltx"],"application/vnd.openxmlformats-officedocument.wordprocessingml.document":["docx"],"application/vnd.openxmlformats-officedocument.wordprocessingml.template":["dotx"],"application/vnd.osgeo.mapguide.package":["mgp"],"application/vnd.osgi.dp":["dp"],"application/vnd.osgi.subsystem":["esa"],"application/vnd.palm":["pdb","pqa","oprc"],"application/vnd.pawaafile":["paw"],"application/vnd.pg.format":["str"],"application/vnd.pg.osasli":["ei6"],"application/vnd.picsel":["efif"],"application/vnd.pmi.widget":["wg"],"application/vnd.pocketlearn":["plf"],"application/vnd.powerbuilder6":["pbd"],"application/vnd.previewsystems.box":["box"],"application/vnd.proteus.magazine":["mgz"],"application/vnd.publishare-delta-tree":["qps"],"application/vnd.pvi.ptid1":["ptid"],"application/vnd.quark.quarkxpress":["qxd","qxt","qwd","qwt","qxl","qxb"],"application/vnd.rar":["rar"],"application/vnd.realvnc.bed":["bed"],"application/vnd.recordare.musicxml":["mxl"],"application/vnd.recordare.musicxml+xml":["musicxml"],"application/vnd.rig.cryptonote":["cryptonote"],"application/vnd.rim.cod":["cod"],"application/vnd.rn-realmedia":["rm"],"application/vnd.rn-realmedia-vbr":["rmvb"],"application/vnd.route66.link66+xml":["link66"],"application/vnd.sailingtracker.track":["st"],"application/vnd.seemail":["see"],"application/vnd.sema":["sema"],"application/vnd.semd":["semd"],"application/vnd.semf":["semf"],"application/vnd.shana.informed.formdata":["ifm"],"application/vnd.shana.informed.formtemplate":["itp"],"application/vnd.shana.informed.interchange":["iif"],"application/vnd.shana.informed.package":["ipk"],"application/vnd.simtech-mindmapper":["twd","twds"],"application/vnd.smaf":["mmf"],"application/vnd.smart.teacher":["teacher"],"application/vnd.software602.filler.form+xml":["fo"],"application/vnd.solent.sdkm+xml":["sdkm","sdkd"],"application/vnd.spotfire.dxp":["dxp"],"application/vnd.spotfire.sfs":["sfs"],"application/vnd.stardivision.calc":["sdc"],"application/vnd.stardivision.draw":["sda"],"application/vnd.stardivision.impress":["sdd"],"application/vnd.stardivision.math":["smf"],"application/vnd.stardivision.writer":["sdw","vor"],"application/vnd.stardivision.writer-global":["sgl"],"application/vnd.stepmania.package":["smzip"],"application/vnd.stepmania.stepchart":["sm"],"application/vnd.sun.wadl+xml":["wadl"],"application/vnd.sun.xml.calc":["sxc"],"application/vnd.sun.xml.calc.template":["stc"],"application/vnd.sun.xml.draw":["sxd"],"application/vnd.sun.xml.draw.template":["std"],"application/vnd.sun.xml.impress":["sxi"],"application/vnd.sun.xml.impress.template":["sti"],"application/vnd.sun.xml.math":["sxm"],"application/vnd.sun.xml.writer":["sxw"],"application/vnd.sun.xml.writer.global":["sxg"],"application/vnd.sun.xml.writer.template":["stw"],"application/vnd.sus-calendar":["sus","susp"],"application/vnd.svd":["svd"],"application/vnd.symbian.install":["sis","sisx"],"application/vnd.syncml+xml":["xsm"],"application/vnd.syncml.dm+wbxml":["bdm"],"application/vnd.syncml.dm+xml":["xdm"],"application/vnd.syncml.dmddf+xml":["ddf"],"application/vnd.tao.intent-module-archive":["tao"],"application/vnd.tcpdump.pcap":["pcap","cap","dmp"],"application/vnd.tmobile-livetv":["tmo"],"application/vnd.trid.tpt":["tpt"],"application/vnd.triscape.mxs":["mxs"],"application/vnd.trueapp":["tra"],"application/vnd.ufdl":["ufd","ufdl"],"application/vnd.uiq.theme":["utz"],"application/vnd.umajin":["umj"],"application/vnd.unity":["unityweb"],"application/vnd.uoml+xml":["uoml"],"application/vnd.vcx":["vcx"],"application/vnd.visio":["vsd","vst","vss","vsw"],"application/vnd.visionary":["vis"],"application/vnd.vsf":["vsf"],"application/vnd.wap.wbxml":["wbxml"],"application/vnd.wap.wmlc":["wmlc"],"application/vnd.wap.wmlscriptc":["wmlsc"],"application/vnd.webturbo":["wtb"],"application/vnd.wolfram.player":["nbp"],"application/vnd.wordperfect":["wpd"],"application/vnd.wqd":["wqd"],"application/vnd.wt.stf":["stf"],"application/vnd.xara":["xar"],"application/vnd.xfdl":["xfdl"],"application/vnd.yamaha.hv-dic":["hvd"],"application/vnd.yamaha.hv-script":["hvs"],"application/vnd.yamaha.hv-voice":["hvp"],"application/vnd.yamaha.openscoreformat":["osf"],"application/vnd.yamaha.openscoreformat.osfpvg+xml":["osfpvg"],"application/vnd.yamaha.smaf-audio":["saf"],"application/vnd.yamaha.smaf-phrase":["spf"],"application/vnd.yellowriver-custom-menu":["cmp"],"application/vnd.zul":["zir","zirz"],"application/vnd.zzazz.deck+xml":["zaz"],"application/x-7z-compressed":["7z"],"application/x-abiword":["abw"],"application/x-ace-compressed":["ace"],"application/x-apple-diskimage":["*dmg"],"application/x-arj":["arj"],"application/x-authorware-bin":["aab","x32","u32","vox"],"application/x-authorware-map":["aam"],"application/x-authorware-seg":["aas"],"application/x-bcpio":["bcpio"],"application/x-bdoc":["*bdoc"],"application/x-bittorrent":["torrent"],"application/x-blorb":["blb","blorb"],"application/x-bzip":["bz"],"application/x-bzip2":["bz2","boz"],"application/x-cbr":["cbr","cba","cbt","cbz","cb7"],"application/x-cdlink":["vcd"],"application/x-cfs-compressed":["cfs"],"application/x-chat":["chat"],"application/x-chess-pgn":["pgn"],"application/x-chrome-extension":["crx"],"application/x-cocoa":["cco"],"application/x-conference":["nsc"],"application/x-cpio":["cpio"],"application/x-csh":["csh"],"application/x-debian-package":["*deb","udeb"],"application/x-dgc-compressed":["dgc"],"application/x-director":["dir","dcr","dxr","cst","cct","cxt","w3d","fgd","swa"],"application/x-doom":["wad"],"application/x-dtbncx+xml":["ncx"],"application/x-dtbook+xml":["dtb"],"application/x-dtbresource+xml":["res"],"application/x-dvi":["dvi"],"application/x-envoy":["evy"],"application/x-eva":["eva"],"application/x-font-bdf":["bdf"],"application/x-font-ghostscript":["gsf"],"application/x-font-linux-psf":["psf"],"application/x-font-pcf":["pcf"],"application/x-font-snf":["snf"],"application/x-font-type1":["pfa","pfb","pfm","afm"],"application/x-freearc":["arc"],"application/x-futuresplash":["spl"],"application/x-gca-compressed":["gca"],"application/x-glulx":["ulx"],"application/x-gnumeric":["gnumeric"],"application/x-gramps-xml":["gramps"],"application/x-gtar":["gtar"],"application/x-hdf":["hdf"],"application/x-httpd-php":["php"],"application/x-install-instructions":["install"],"application/x-iso9660-image":["*iso"],"application/x-java-archive-diff":["jardiff"],"application/x-java-jnlp-file":["jnlp"],"application/x-keepass2":["kdbx"],"application/x-latex":["latex"],"application/x-lua-bytecode":["luac"],"application/x-lzh-compressed":["lzh","lha"],"application/x-makeself":["run"],"application/x-mie":["mie"],"application/x-mobipocket-ebook":["prc","mobi"],"application/x-ms-application":["application"],"application/x-ms-shortcut":["lnk"],"application/x-ms-wmd":["wmd"],"application/x-ms-wmz":["wmz"],"application/x-ms-xbap":["xbap"],"application/x-msaccess":["mdb"],"application/x-msbinder":["obd"],"application/x-mscardfile":["crd"],"application/x-msclip":["clp"],"application/x-msdos-program":["*exe"],"application/x-msdownload":["*exe","*dll","com","bat","*msi"],"application/x-msmediaview":["mvb","m13","m14"],"application/x-msmetafile":["*wmf","*wmz","*emf","emz"],"application/x-msmoney":["mny"],"application/x-mspublisher":["pub"],"application/x-msschedule":["scd"],"application/x-msterminal":["trm"],"application/x-mswrite":["wri"],"application/x-netcdf":["nc","cdf"],"application/x-ns-proxy-autoconfig":["pac"],"application/x-nzb":["nzb"],"application/x-perl":["pl","pm"],"application/x-pilot":["*prc","*pdb"],"application/x-pkcs12":["p12","pfx"],"application/x-pkcs7-certificates":["p7b","spc"],"application/x-pkcs7-certreqresp":["p7r"],"application/x-rar-compressed":["*rar"],"application/x-redhat-package-manager":["rpm"],"application/x-research-info-systems":["ris"],"application/x-sea":["sea"],"application/x-sh":["sh"],"application/x-shar":["shar"],"application/x-shockwave-flash":["swf"],"application/x-silverlight-app":["xap"],"application/x-sql":["sql"],"application/x-stuffit":["sit"],"application/x-stuffitx":["sitx"],"application/x-subrip":["srt"],"application/x-sv4cpio":["sv4cpio"],"application/x-sv4crc":["sv4crc"],"application/x-t3vm-image":["t3"],"application/x-tads":["gam"],"application/x-tar":["tar"],"application/x-tcl":["tcl","tk"],"application/x-tex":["tex"],"application/x-tex-tfm":["tfm"],"application/x-texinfo":["texinfo","texi"],"application/x-tgif":["*obj"],"application/x-ustar":["ustar"],"application/x-virtualbox-hdd":["hdd"],"application/x-virtualbox-ova":["ova"],"application/x-virtualbox-ovf":["ovf"],"application/x-virtualbox-vbox":["vbox"],"application/x-virtualbox-vbox-extpack":["vbox-extpack"],"application/x-virtualbox-vdi":["vdi"],"application/x-virtualbox-vhd":["vhd"],"application/x-virtualbox-vmdk":["vmdk"],"application/x-wais-source":["src"],"application/x-web-app-manifest+json":["webapp"],"application/x-x509-ca-cert":["der","crt","pem"],"application/x-xfig":["fig"],"application/x-xliff+xml":["*xlf"],"application/x-xpinstall":["xpi"],"application/x-xz":["xz"],"application/x-zmachine":["z1","z2","z3","z4","z5","z6","z7","z8"],"audio/vnd.dece.audio":["uva","uvva"],"audio/vnd.digital-winds":["eol"],"audio/vnd.dra":["dra"],"audio/vnd.dts":["dts"],"audio/vnd.dts.hd":["dtshd"],"audio/vnd.lucent.voice":["lvp"],"audio/vnd.ms-playready.media.pya":["pya"],"audio/vnd.nuera.ecelp4800":["ecelp4800"],"audio/vnd.nuera.ecelp7470":["ecelp7470"],"audio/vnd.nuera.ecelp9600":["ecelp9600"],"audio/vnd.rip":["rip"],"audio/x-aac":["aac"],"audio/x-aiff":["aif","aiff","aifc"],"audio/x-caf":["caf"],"audio/x-flac":["flac"],"audio/x-m4a":["*m4a"],"audio/x-matroska":["mka"],"audio/x-mpegurl":["m3u"],"audio/x-ms-wax":["wax"],"audio/x-ms-wma":["wma"],"audio/x-pn-realaudio":["ram","ra"],"audio/x-pn-realaudio-plugin":["rmp"],"audio/x-realaudio":["*ra"],"audio/x-wav":["*wav"],"chemical/x-cdx":["cdx"],"chemical/x-cif":["cif"],"chemical/x-cmdf":["cmdf"],"chemical/x-cml":["cml"],"chemical/x-csml":["csml"],"chemical/x-xyz":["xyz"],"image/prs.btif":["btif"],"image/prs.pti":["pti"],"image/vnd.adobe.photoshop":["psd"],"image/vnd.airzip.accelerator.azv":["azv"],"image/vnd.dece.graphic":["uvi","uvvi","uvg","uvvg"],"image/vnd.djvu":["djvu","djv"],"image/vnd.dvb.subtitle":["*sub"],"image/vnd.dwg":["dwg"],"image/vnd.dxf":["dxf"],"image/vnd.fastbidsheet":["fbs"],"image/vnd.fpx":["fpx"],"image/vnd.fst":["fst"],"image/vnd.fujixerox.edmics-mmr":["mmr"],"image/vnd.fujixerox.edmics-rlc":["rlc"],"image/vnd.microsoft.icon":["ico"],"image/vnd.ms-dds":["dds"],"image/vnd.ms-modi":["mdi"],"image/vnd.ms-photo":["wdp"],"image/vnd.net-fpx":["npx"],"image/vnd.pco.b16":["b16"],"image/vnd.tencent.tap":["tap"],"image/vnd.valve.source.texture":["vtf"],"image/vnd.wap.wbmp":["wbmp"],"image/vnd.xiff":["xif"],"image/vnd.zbrush.pcx":["pcx"],"image/x-3ds":["3ds"],"image/x-cmu-raster":["ras"],"image/x-cmx":["cmx"],"image/x-freehand":["fh","fhc","fh4","fh5","fh7"],"image/x-icon":["*ico"],"image/x-jng":["jng"],"image/x-mrsid-image":["sid"],"image/x-ms-bmp":["*bmp"],"image/x-pcx":["*pcx"],"image/x-pict":["pic","pct"],"image/x-portable-anymap":["pnm"],"image/x-portable-bitmap":["pbm"],"image/x-portable-graymap":["pgm"],"image/x-portable-pixmap":["ppm"],"image/x-rgb":["rgb"],"image/x-tga":["tga"],"image/x-xbitmap":["xbm"],"image/x-xpixmap":["xpm"],"image/x-xwindowdump":["xwd"],"message/vnd.wfa.wsc":["wsc"],"model/vnd.collada+xml":["dae"],"model/vnd.dwf":["dwf"],"model/vnd.gdl":["gdl"],"model/vnd.gtw":["gtw"],"model/vnd.mts":["mts"],"model/vnd.opengex":["ogex"],"model/vnd.parasolid.transmit.binary":["x_b"],"model/vnd.parasolid.transmit.text":["x_t"],"model/vnd.usdz+zip":["usdz"],"model/vnd.valve.source.compiled-map":["bsp"],"model/vnd.vtu":["vtu"],"text/prs.lines.tag":["dsc"],"text/vnd.curl":["curl"],"text/vnd.curl.dcurl":["dcurl"],"text/vnd.curl.mcurl":["mcurl"],"text/vnd.curl.scurl":["scurl"],"text/vnd.dvb.subtitle":["sub"],"text/vnd.fly":["fly"],"text/vnd.fmi.flexstor":["flx"],"text/vnd.graphviz":["gv"],"text/vnd.in3d.3dml":["3dml"],"text/vnd.in3d.spot":["spot"],"text/vnd.sun.j2me.app-descriptor":["jad"],"text/vnd.wap.wml":["wml"],"text/vnd.wap.wmlscript":["wmls"],"text/x-asm":["s","asm"],"text/x-c":["c","cc","cxx","cpp","h","hh","dic"],"text/x-component":["htc"],"text/x-fortran":["f","for","f77","f90"],"text/x-handlebars-template":["hbs"],"text/x-java-source":["java"],"text/x-lua":["lua"],"text/x-markdown":["mkd"],"text/x-nfo":["nfo"],"text/x-opml":["opml"],"text/x-org":["*org"],"text/x-pascal":["p","pas"],"text/x-processing":["pde"],"text/x-sass":["sass"],"text/x-scss":["scss"],"text/x-setext":["etx"],"text/x-sfv":["sfv"],"text/x-suse-ymp":["ymp"],"text/x-uuencode":["uu"],"text/x-vcalendar":["vcs"],"text/x-vcard":["vcf"],"video/vnd.dece.hd":["uvh","uvvh"],"video/vnd.dece.mobile":["uvm","uvvm"],"video/vnd.dece.pd":["uvp","uvvp"],"video/vnd.dece.sd":["uvs","uvvs"],"video/vnd.dece.video":["uvv","uvvv"],"video/vnd.dvb.file":["dvb"],"video/vnd.fvt":["fvt"],"video/vnd.mpegurl":["mxu","m4u"],"video/vnd.ms-playready.media.pyv":["pyv"],"video/vnd.uvvu.mp4":["uvu","uvvu"],"video/vnd.vivo":["viv"],"video/x-f4v":["f4v"],"video/x-fli":["fli"],"video/x-flv":["flv"],"video/x-m4v":["m4v"],"video/x-matroska":["mkv","mk3d","mks"],"video/x-mng":["mng"],"video/x-ms-asf":["asf","asx"],"video/x-ms-vob":["vob"],"video/x-ms-wm":["wm"],"video/x-ms-wmv":["wmv"],"video/x-ms-wmx":["wmx"],"video/x-ms-wvx":["wvx"],"video/x-msvideo":["avi"],"video/x-sgi-movie":["movie"],"video/x-smv":["smv"],"x-conference/x-cooltalk":["ice"]}; + +/***/ }), +/* 23 */ +/***/ (function(module, exports, __webpack_require__) { + +var session = __webpack_require__(5); +var Async = __webpack_require__(24); +var EventProxy = __webpack_require__(4).EventProxy; +var util = __webpack_require__(0); + +// 文件分块上传全过程,暴露的分块上传接口 +function sliceUploadFile(params, callback) { + var self = this; + + // 如果小程序版本不支持获取文件分片内容,统一转到 postObject 接口上传 + if (!util.canFileSlice()) { + params.SkipTask = true; + self.postObject(params, callback); + return; + } + + var ep = new EventProxy(); + var TaskId = params.TaskId; + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var FilePath = params.FilePath; + var ChunkSize = params.ChunkSize || params.SliceSize || self.options.ChunkSize; + var AsyncLimit = params.AsyncLimit; + var StorageClass = params.StorageClass; + var ServerSideEncryption = params.ServerSideEncryption; + var FileSize; + + var onProgress; + var onHashProgress = params.onHashProgress; + + // 上传过程中出现错误,返回错误 + ep.on('error', function (err) { + if (!self._isRunningTask(TaskId)) return; + var _err = { + UploadId: params.UploadData.UploadId || '', + err: err, + }; + return callback(_err); + }); + + // 上传分块完成,开始 uploadSliceComplete 操作 + ep.on('upload_complete', function (UploadCompleteData) { + var _UploadCompleteData = util.extend({ + UploadId: params.UploadData.UploadId || '' + }, UploadCompleteData); + callback(null, _UploadCompleteData); + }); + + // 上传分块完成,开始 uploadSliceComplete 操作 + ep.on('upload_slice_complete', function (UploadData) { + uploadSliceComplete.call(self, { + Bucket: Bucket, + Region: Region, + Key: Key, + UploadId: UploadData.UploadId, + SliceList: UploadData.SliceList, + }, function (err, data) { + if (!self._isRunningTask(TaskId)) return; + session.removeUsing(UploadData.UploadId); + if (err) { + onProgress(null, true); + return ep.emit('error', err); + } + session.removeUploadId(UploadData.UploadId); + onProgress({loaded: FileSize, total: FileSize}, true); + ep.emit('upload_complete', data); + }); + }); + + // 获取 UploadId 完成,开始上传每个分片 + ep.on('get_upload_data_finish', function (UploadData) { + + // 处理 UploadId 缓存 + var uuid = session.getFileId(params.FileStat, params.ChunkSize, Bucket, Key); + uuid && session.saveUploadId(uuid, UploadData.UploadId, self.options.UploadIdCacheLimit); // 缓存 UploadId + session.setUsing(UploadData.UploadId); // 标记 UploadId 为正在使用 + + // 获取 UploadId + onProgress(null, true); // 任务状态开始 uploading + uploadSliceList.call(self, { + TaskId: TaskId, + Bucket: Bucket, + Region: Region, + Key: Key, + FilePath: FilePath, + FileSize: FileSize, + SliceSize: ChunkSize, + AsyncLimit: AsyncLimit, + ServerSideEncryption: ServerSideEncryption, + UploadData: UploadData, + onProgress: onProgress + }, function (err, data) { + if (!self._isRunningTask(TaskId)) return; + if (err) { + onProgress(null, true); + return ep.emit('error', err); + } + ep.emit('upload_slice_complete', data); + }); + }); + + // 开始获取文件 UploadId,里面会视情况计算 ETag,并比对,保证文件一致性,也优化上传 + ep.on('get_file_size_finish', function () { + + onProgress = util.throttleOnProgress.call(self, FileSize, params.onProgress); + + if (params.UploadData.UploadId) { + ep.emit('get_upload_data_finish', params.UploadData); + } else { + var _params = util.extend({ + TaskId: TaskId, + Bucket: Bucket, + Region: Region, + Key: Key, + Headers: params.Headers, + StorageClass: StorageClass, + FilePath: FilePath, + FileSize: FileSize, + SliceSize: ChunkSize, + onHashProgress: onHashProgress, + }, params); + getUploadIdAndPartList.call(self, _params, function (err, UploadData) { + if (!self._isRunningTask(TaskId)) return; + if (err) return ep.emit('error', err); + params.UploadData.UploadId = UploadData.UploadId; + params.UploadData.PartList = UploadData.PartList; + ep.emit('get_upload_data_finish', params.UploadData); + }); + } + }); + + // 获取上传文件大小 + FileSize = params.ContentLength; + delete params.ContentLength; + !params.Headers && (params.Headers = {}); + util.each(params.Headers, function (item, key) { + if (key.toLowerCase() === 'content-length') { + delete params.Headers[key]; + } + }); + + // 控制分片大小 + (function () { + var SIZE = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 1024 * 2, 1024 * 4, 1024 * 5]; + var AutoChunkSize = 1024 * 1024; + for (var i = 0; i < SIZE.length; i++) { + AutoChunkSize = SIZE[i] * 1024 * 1024; + if (FileSize / AutoChunkSize <= self.options.MaxPartNumber) break; + } + params.ChunkSize = params.SliceSize = ChunkSize = Math.max(ChunkSize, AutoChunkSize); + })(); + + // 开始上传 + if (FileSize === 0) { + params.Body = ''; + params.ContentLength = 0; + params.SkipTask = true; + self.putObject(params, function (err, data) { + if (err) { + return callback(err); + } + callback(null, data); + }); + } else { + ep.emit('get_file_size_finish'); + } + +} + +// 获取上传任务的 UploadId +function getUploadIdAndPartList(params, callback) { + var TaskId = params.TaskId; + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var StorageClass = params.StorageClass; + var self = this; + + // 计算 ETag + var ETagMap = {}; + var FileSize = params.FileSize; + var SliceSize = params.SliceSize; + var SliceCount = Math.ceil(FileSize / SliceSize); + var FinishSliceCount = 0; + var FinishSize = 0; + var onHashProgress = util.throttleOnProgress.call(self, FileSize, params.onHashProgress); + var getChunkETag = function (PartNumber, callback) { + var start = SliceSize * (PartNumber - 1); + var end = Math.min(start + SliceSize, FileSize); + var ChunkSize = end - start; + + if (ETagMap[PartNumber]) { + callback(null, { + PartNumber: PartNumber, + ETag: ETagMap[PartNumber], + Size: ChunkSize + }); + } else { + util.fileSlice(params.FilePath, start, end, function (chunkItem) { + try { + var md5 = util.getFileMd5(chunkItem); + } catch (err) { + return callback(err); + } + var ETag = '"' + md5 + '"'; + ETagMap[PartNumber] = ETag; + FinishSliceCount += 1; + FinishSize += ChunkSize; + callback(null, { + PartNumber: PartNumber, + ETag: ETag, + Size: ChunkSize + }); + onHashProgress({loaded: FinishSize, total: FileSize}); + }); + } + }; + + // 通过和文件的 md5 对比,判断 UploadId 是否可用 + var isAvailableUploadList = function (PartList, callback) { + var PartCount = PartList.length; + // 如果没有分片,通过 + if (PartCount === 0) { + return callback(null, true); + } + // 检查分片数量 + if (PartCount > SliceCount) { + return callback(null, false); + } + // 检查分片大小 + if (PartCount > 1) { + var PartSliceSize = Math.max(PartList[0].Size, PartList[1].Size); + if (PartSliceSize !== SliceSize) { + return callback(null, false); + } + } + // 逐个分片计算并检查 ETag 是否一致 + var next = function (index) { + if (index < PartCount) { + var Part = PartList[index]; + getChunkETag(Part.PartNumber, function (err, chunk) { + if (chunk && chunk.ETag === Part.ETag && chunk.Size === Part.Size) { + next(index + 1); + } else { + callback(null, false); + } + }); + } else { + callback(null, true); + } + }; + next(0); + }; + + var ep = new EventProxy(); + ep.on('error', function (errData) { + if (!self._isRunningTask(TaskId)) return; + return callback(errData); + }); + + // 存在 UploadId + ep.on('upload_id_available', function (UploadData) { + // 转换成 map + var map = {}; + var list = []; + util.each(UploadData.PartList, function (item) { + map[item.PartNumber] = item; + }); + for (var PartNumber = 1; PartNumber <= SliceCount; PartNumber++) { + var item = map[PartNumber]; + if (item) { + item.PartNumber = PartNumber; + item.Uploaded = true; + } else { + item = { + PartNumber: PartNumber, + ETag: null, + Uploaded: false + }; + } + list.push(item); + } + UploadData.PartList = list; + callback(null, UploadData); + }); + + // 不存在 UploadId, 初始化生成 UploadId + ep.on('no_available_upload_id', function () { + if (!self._isRunningTask(TaskId)) return; + var _params = util.extend({ + Bucket: Bucket, + Region: Region, + Key: Key, + Headers: util.clone(params.Headers), + Query: util.clone(params.Query), + StorageClass: StorageClass, + }, params); + self.multipartInit(_params, function (err, data) { + if (!self._isRunningTask(TaskId)) return; + if (err) return ep.emit('error', err); + var UploadId = data.UploadId; + if (!UploadId) { + return callback({Message: 'no upload id'}); + } + ep.emit('upload_id_available', {UploadId: UploadId, PartList: []}); + }); + }); + + // 如果已存在 UploadId,找一个可以用的 UploadId + ep.on('has_and_check_upload_id', function (UploadIdList) { + // 串行地,找一个内容一致的 UploadId + UploadIdList = UploadIdList.reverse(); + Async.eachLimit(UploadIdList, 1, function (UploadId, asyncCallback) { + if (!self._isRunningTask(TaskId)) return; + // 如果正在上传,跳过 + if (session.using[UploadId]) { + asyncCallback(); // 检查下一个 UploadId + return; + } + // 判断 UploadId 是否可用 + wholeMultipartListPart.call(self, { + Bucket: Bucket, + Region: Region, + Key: Key, + UploadId: UploadId, + }, function (err, PartListData) { + if (!self._isRunningTask(TaskId)) return; + if (err) { + session.removeUsing(UploadId); + return ep.emit('error', err); + } + var PartList = PartListData.PartList; + PartList.forEach(function (item) { + item.PartNumber *= 1; + item.Size *= 1; + item.ETag = item.ETag || ''; + }); + isAvailableUploadList(PartList, function (err, isAvailable) { + if (!self._isRunningTask(TaskId)) return; + if (err) return ep.emit('error', err); + if (isAvailable) { + asyncCallback({ + UploadId: UploadId, + PartList: PartList + }); // 马上结束 + } else { + asyncCallback(); // 检查下一个 UploadId + } + }); + }); + }, function (AvailableUploadData) { + if (!self._isRunningTask(TaskId)) return; + onHashProgress(null, true); + if (AvailableUploadData && AvailableUploadData.UploadId) { + ep.emit('upload_id_available', AvailableUploadData); + } else { + ep.emit('no_available_upload_id'); + } + }); + }); + + // 在本地缓存找可用的 UploadId + ep.on('seek_local_avail_upload_id', function (RemoteUploadIdList) { + // 在本地找可用的 UploadId + var uuid = session.getFileId(params.FileStat, params.ChunkSize, Bucket, Key); + var LocalUploadIdList = session.getUploadIdList(uuid); + if (!uuid || !LocalUploadIdList) { + ep.emit('has_and_check_upload_id', RemoteUploadIdList); + return; + } + var next = function (index) { + // 如果本地找不到可用 UploadId,再一个个遍历校验远端 + if (index >= LocalUploadIdList.length) { + ep.emit('has_and_check_upload_id', RemoteUploadIdList); + return; + } + var UploadId = LocalUploadIdList[index]; + // 如果不在远端 UploadId 列表里,跳过并删除 + if (!util.isInArray(RemoteUploadIdList, UploadId)) { + session.removeUploadId(UploadId); + next(index + 1); + return; + } + // 如果正在上传,跳过 + if (session.using[UploadId]) { + next(index + 1); + return; + } + // 判断 UploadId 是否存在线上 + wholeMultipartListPart.call(self, { + Bucket: Bucket, + Region: Region, + Key: Key, + UploadId: UploadId, + }, function (err, PartListData) { + if (!self._isRunningTask(TaskId)) return; + if (err) { + // 如果 UploadId 获取会出错,跳过并删除 + session.removeUploadId(UploadId); + next(index + 1); + } else { + // 找到可用 UploadId + ep.emit('upload_id_available', { + UploadId: UploadId, + PartList: PartListData.PartList, + }); + } + }); + }; + next(0); + }); + + // 获取线上 UploadId 列表 + ep.on('get_remote_upload_id_list', function () { + // 获取符合条件的 UploadId 列表,因为同一个文件可以有多个上传任务。 + wholeMultipartList.call(self, { + Bucket: Bucket, + Region: Region, + Key: Key, + }, function (err, data) { + if (!self._isRunningTask(TaskId)) return; + if (err) { + return ep.emit('error', err); + } + // 整理远端 UploadId 列表 + var RemoteUploadIdList = util.filter(data.UploadList, function (item) { + return item.Key === Key && (!StorageClass || item.StorageClass.toUpperCase() === StorageClass.toUpperCase()); + }).reverse().map(function (item) { + return item.UploadId || item.UploadID; + }); + if (RemoteUploadIdList.length) { + ep.emit('seek_local_avail_upload_id', RemoteUploadIdList); + } else { + // 远端没有 UploadId,清理缓存的 UploadId + var uuid = session.getFileId(params.FileStat, params.ChunkSize, Bucket, Key), LocalUploadIdList; + if (uuid && (LocalUploadIdList = session.getUploadIdList(uuid))) { + util.each(LocalUploadIdList, function (UploadId) { + session.removeUploadId(UploadId); + }); + } + ep.emit('no_available_upload_id'); + } + }); + }); + + // 开始找可用 UploadId + ep.emit('get_remote_upload_id_list'); + +} + +// 获取符合条件的全部上传任务 (条件包括 Bucket, Region, Prefix) +function wholeMultipartList(params, callback) { + var self = this; + var UploadList = []; + var sendParams = { + Bucket: params.Bucket, + Region: params.Region, + Prefix: params.Key + }; + var next = function () { + self.multipartList(sendParams, function (err, data) { + if (err) return callback(err); + UploadList.push.apply(UploadList, data.Upload || []); + if (data.IsTruncated === 'true') { // 列表不完整 + sendParams.KeyMarker = data.NextKeyMarker; + sendParams.UploadIdMarker = data.NextUploadIdMarker; + next(); + } else { + callback(null, {UploadList: UploadList}); + } + }); + }; + next(); +} + +// 获取指定上传任务的分块列表 +function wholeMultipartListPart(params, callback) { + var self = this; + var PartList = []; + var sendParams = { + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + UploadId: params.UploadId + }; + var next = function () { + self.multipartListPart(sendParams, function (err, data) { + if (err) return callback(err); + PartList.push.apply(PartList, data.Part || []); + if (data.IsTruncated === 'true') { // 列表不完整 + sendParams.PartNumberMarker = data.NextPartNumberMarker; + next(); + } else { + callback(null, {PartList: PartList}); + } + }); + }; + next(); +} + +// 上传文件分块,包括 +/* + UploadId (上传任务编号) + AsyncLimit (并发量), + SliceList (上传的分块数组), + FilePath (本地文件的位置), + SliceSize (文件分块大小) + FileSize (文件大小) + onProgress (上传成功之后的回调函数) + */ +function uploadSliceList(params, cb) { + var self = this; + var TaskId = params.TaskId; + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var UploadData = params.UploadData; + var FileSize = params.FileSize; + var SliceSize = params.SliceSize; + var ChunkParallel = Math.min(params.AsyncLimit || self.options.ChunkParallelLimit || 1, 256); + var FilePath = params.FilePath; + var SliceCount = Math.ceil(FileSize / SliceSize); + var FinishSize = 0; + var ServerSideEncryption = params.ServerSideEncryption; + var needUploadSlices = util.filter(UploadData.PartList, function (SliceItem) { + if (SliceItem['Uploaded']) { + FinishSize += SliceItem['PartNumber'] >= SliceCount ? (FileSize % SliceSize || SliceSize) : SliceSize; + } + return !SliceItem['Uploaded']; + }); + var onProgress = params.onProgress; + + Async.eachLimit(needUploadSlices, ChunkParallel, function (SliceItem, asyncCallback) { + if (!self._isRunningTask(TaskId)) return; + var PartNumber = SliceItem['PartNumber']; + var currentSize = Math.min(FileSize, SliceItem['PartNumber'] * SliceSize) - (SliceItem['PartNumber'] - 1) * SliceSize; + var preAddSize = 0; + uploadSliceItem.call(self, { + TaskId: TaskId, + Bucket: Bucket, + Region: Region, + Key: Key, + SliceSize: SliceSize, + FileSize: FileSize, + PartNumber: PartNumber, + ServerSideEncryption: ServerSideEncryption, + FilePath: FilePath, + UploadData: UploadData, + onProgress: function (data) { + FinishSize += data.loaded - preAddSize; + preAddSize = data.loaded; + onProgress({loaded: FinishSize, total: FileSize}); + }, + }, function (err, data) { + if (!self._isRunningTask(TaskId)) return; + if (err) { + FinishSize -= preAddSize; + } else { + FinishSize += currentSize - preAddSize; + SliceItem.ETag = data.ETag; + } + onProgress({loaded: FinishSize, total: FileSize}); + asyncCallback(err || null, data); + }); + }, function (err) { + if (!self._isRunningTask(TaskId)) return; + if (err) return cb(err); + cb(null, { + UploadId: UploadData.UploadId, + SliceList: UploadData.PartList + }); + }); +} + +// 上传指定分片 +function uploadSliceItem(params, callback) { + var self = this; + var TaskId = params.TaskId; + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var FileSize = params.FileSize; + var FilePath = params.FilePath; + var PartNumber = params.PartNumber * 1; + var SliceSize = params.SliceSize; + var ServerSideEncryption = params.ServerSideEncryption; + var UploadData = params.UploadData; + var ChunkRetryTimes = self.options.ChunkRetryTimes + 1; + + var start = SliceSize * (PartNumber - 1); + + var ContentLength = SliceSize; + + var end = start + SliceSize; + + if (end > FileSize) { + end = FileSize; + ContentLength = end - start; + } + + util.fileSlice(FilePath, start, end, function (Body) { + var md5 = util.getFileMd5(Body); + var contentMd5 = md5 ? util.binaryBase64(md5) : null; + var PartItem = UploadData.PartList[PartNumber - 1]; + Async.retry(ChunkRetryTimes, function (tryCallback) { + if (!self._isRunningTask(TaskId)) return; + self.multipartUpload({ + TaskId: TaskId, + Bucket: Bucket, + Region: Region, + Key: Key, + ContentLength: ContentLength, + PartNumber: PartNumber, + UploadId: UploadData.UploadId, + ServerSideEncryption: ServerSideEncryption, + Body: Body, + onProgress: params.onProgress, + ContentMD5: contentMd5, + }, function (err, data) { + if (!self._isRunningTask(TaskId)) return; + if (err) { + return tryCallback(err); + } else { + PartItem.Uploaded = true; + return tryCallback(null, data); + } + }); + }, function (err, data) { + if (!self._isRunningTask(TaskId)) return; + return callback(err, data); + }); + }); +} + + +// 完成分块上传 +function uploadSliceComplete(params, callback) { + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var UploadId = params.UploadId; + var SliceList = params.SliceList; + var self = this; + var ChunkRetryTimes = this.options.ChunkRetryTimes + 1; + var Parts = SliceList.map(function (item) { + return { + PartNumber: item.PartNumber, + ETag: item.ETag + }; + }); + // 完成上传的请求也做重试 + Async.retry(ChunkRetryTimes, function (tryCallback) { + self.multipartComplete({ + Bucket: Bucket, + Region: Region, + Key: Key, + UploadId: UploadId, + Parts: Parts + }, tryCallback); + }, function (err, data) { + callback(err, data); + }); +} + +// 抛弃分块上传任务 +/* + AsyncLimit (抛弃上传任务的并发量), + UploadId (上传任务的编号,当 Level 为 task 时候需要) + Level (抛弃分块上传任务的级别,task : 抛弃指定的上传任务,file : 抛弃指定的文件对应的上传任务,其他值 :抛弃指定Bucket 的全部上传任务) + */ +function abortUploadTask(params, callback) { + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var UploadId = params.UploadId; + var Level = params.Level || 'task'; + var AsyncLimit = params.AsyncLimit; + var self = this; + + var ep = new EventProxy(); + + ep.on('error', function (errData) { + return callback(errData); + }); + + // 已经获取到需要抛弃的任务列表 + ep.on('get_abort_array', function (AbortArray) { + abortUploadTaskArray.call(self, { + Bucket: Bucket, + Region: Region, + Key: Key, + Headers: params.Headers, + AsyncLimit: AsyncLimit, + AbortArray: AbortArray + }, function (err, data) { + if (err) { + return callback(err); + } + callback(null, data); + }); + }); + + if (Level === 'bucket') { + // Bucket 级别的任务抛弃,抛弃该 Bucket 下的全部上传任务 + wholeMultipartList.call(self, { + Bucket: Bucket, + Region: Region + }, function (err, data) { + if (err) { + return callback(err); + } + ep.emit('get_abort_array', data.UploadList || []); + }); + } else if (Level === 'file') { + // 文件级别的任务抛弃,抛弃该文件的全部上传任务 + if (!Key) return callback({error: 'abort_upload_task_no_key'}); + wholeMultipartList.call(self, { + Bucket: Bucket, + Region: Region, + Key: Key + }, function (err, data) { + if (err) { + return callback(err); + } + ep.emit('get_abort_array', data.UploadList || []); + }); + } else if (Level === 'task') { + // 单个任务级别的任务抛弃,抛弃指定 UploadId 的上传任务 + if (!UploadId) return callback({error: 'abort_upload_task_no_id'}); + if (!Key) return callback({error: 'abort_upload_task_no_key'}); + ep.emit('get_abort_array', [{ + Key: Key, + UploadId: UploadId + }]); + } else { + return callback({error: 'abort_unknown_level'}); + } +} +// 批量抛弃分块上传任务 +function abortUploadTaskArray(params, callback) { + + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var AbortArray = params.AbortArray; + var AsyncLimit = params.AsyncLimit || 1; + var self = this; + + var index = 0; + var resultList = new Array(AbortArray.length); + Async.eachLimit(AbortArray, AsyncLimit, function (AbortItem, callback) { + var eachIndex = index; + if (Key && Key !== AbortItem.Key) { + resultList[eachIndex] = {error: {KeyNotMatch: true}}; + callback(null); + return; + } + var UploadId = AbortItem.UploadId || AbortItem.UploadID; + + self.multipartAbort({ + Bucket: Bucket, + Region: Region, + Key: AbortItem.Key, + Headers: params.Headers, + UploadId: UploadId + }, function (err) { + var task = { + Bucket: Bucket, + Region: Region, + Key: AbortItem.Key, + UploadId: UploadId + }; + resultList[eachIndex] = {error: err, task: task}; + callback(null); + }); + index++; + + }, function (err) { + if (err) { + return callback(err); + } -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { + var successList = []; + var errorList = []; + + for (var i = 0, len = resultList.length; i < len; i++) { + var item = resultList[i]; + if (item['task']) { + if (item['error']) { + errorList.push(item['task']); + } else { + successList.push(item['task']); + } + } + } -"use strict"; + return callback(null, { + successList: successList, + errorList: errorList + }); + }); +} +// 高级上传 +function uploadFile(params, callback) { + var self = this; -var Mime = __webpack_require__(20); -module.exports = new Mime(__webpack_require__(21), __webpack_require__(22)); + // 判断多大的文件使用分片上传 + var SliceSize = params.SliceSize === undefined ? self.options.SliceSize : params.SliceSize; + var taskList = []; -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { + var FileSize = params.FileSize; + var fileInfo = {TaskId: ''}; -"use strict"; + // 整理 option,用于返回给回调 + util.each(params, function (v, k) { + if (typeof v !== 'object' && typeof v !== 'function') { + fileInfo[k] = v; + } + }); + + // 处理文件 TaskReady + var _onTaskReady = params.onTaskReady; + params.onTaskReady = function (tid) { + fileInfo.TaskId = tid; + _onTaskReady && _onTaskReady(tid); + }; + + // 处理文件完成 + var _onFileFinish = params.onFileFinish; + var onFileFinish = function (err, data) { + _onFileFinish && _onFileFinish(err, data, fileInfo); + callback && callback(err, data); + }; + + // 添加上传任务 + var api = FileSize > SliceSize ? 'sliceUploadFile' : 'postObject'; + taskList.push({ + api: api, + params: params, + callback: onFileFinish, + }); + self._addTasks(taskList); +} +// 批量上传文件 +function uploadFiles(params, callback) { + var self = this; + + // 判断多大的文件使用分片上传 + var SliceSize = params.SliceSize === undefined ? self.options.SliceSize : params.SliceSize; + + // 汇总返回进度 + var TotalSize = 0; + var TotalFinish = 0; + var onTotalProgress = util.throttleOnProgress.call(self, TotalFinish, params.onProgress); + + // 汇总返回回调 + var unFinishCount = params.files.length; + var _onTotalFileFinish = params.onFileFinish; + var resultList = Array(unFinishCount); + var onTotalFileFinish = function (err, data, options) { + onTotalProgress(null, true); + _onTotalFileFinish && _onTotalFileFinish(err, data, options); + resultList[options.Index] = { + options: options, + error: err, + data: data + }; + if (--unFinishCount <= 0 && callback) { + callback(null, { + files: resultList, + }); + } + }; -/** - * @param typeMap [Object] Map of MIME type -> Array[extensions] - * @param ... - */ -function Mime() { - this._types = Object.create(null); - this._extensions = Object.create(null); + // 开始处理每个文件 + var taskList = []; + util.each(params.files, function (fileParams, index) { + var FileSize = fileParams.FileSize; + var fileInfo = {Index: index, TaskId: ''}; - for (var i = 0; i < arguments.length; i++) { - this.define(arguments[i]); - } + // 更新文件总大小 + TotalSize += FileSize; - this.define = this.define.bind(this); - this.getType = this.getType.bind(this); - this.getExtension = this.getExtension.bind(this); + // 整理 option,用于返回给回调 + util.each(fileParams, function (v, k) { + if (typeof v !== 'object' && typeof v !== 'function') { + fileInfo[k] = v; + } + }); + + // 处理单个文件 TaskReady + var _onTaskReady = fileParams.onTaskReady; + fileParams.onTaskReady = function (tid) { + fileInfo.TaskId = tid; + _onTaskReady && _onTaskReady(tid); + }; + + // 处理单个文件进度 + var PreAddSize = 0; + var _onProgress = fileParams.onProgress; + fileParams.onProgress = function (info) { + TotalFinish = TotalFinish - PreAddSize + info.loaded; + PreAddSize = info.loaded; + _onProgress && _onProgress(info); + onTotalProgress({loaded: TotalFinish, total: TotalSize}); + }; + + // 处理单个文件完成 + var _onFileFinish = fileParams.onFileFinish; + var onFileFinish = function (err, data) { + _onFileFinish && _onFileFinish(err, data); + onTotalFileFinish && onTotalFileFinish(err, data, fileInfo); + }; + + // 添加上传任务 + var api = FileSize > SliceSize ? 'sliceUploadFile' : 'postObject'; + taskList.push({ + api: api, + params: fileParams, + callback: onFileFinish, + }); + }); + self._addTasks(taskList); } -/** - * Define mimetype -> extension mappings. Each key is a mime-type that maps - * to an array of extensions associated with the type. The first extension is - * used as the default extension for the type. - * - * e.g. mime.define({'audio/ogg', ['oga', 'ogg', 'spx']}); - * - * If a type declares an extension that has already been defined, an error will - * be thrown. To suppress this error and force the extension to be associated - * with the new type, pass `force`=true. Alternatively, you may prefix the - * extension with "*" to map the type to extension, without mapping the - * extension to the type. - * - * e.g. mime.define({'audio/wav', ['wav']}, {'audio/x-wav', ['*wav']}); - * - * - * @param map (Object) type definitions - * @param force (Boolean) if true, force overriding of existing definitions - */ -Mime.prototype.define = function(typeMap, force) { - for (var type in typeMap) { - var extensions = typeMap[type].map(function(t) {return t.toLowerCase()}); - type = type.toLowerCase(); +// 分片复制文件 +function sliceCopyFile(params, callback) { + var ep = new EventProxy(); + + var self = this; + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var CopySource = params.CopySource; + var m = CopySource.match(/^([^.]+-\d+)\.cos(v6)?\.([^.]+)\.[^/]+\/(.+)$/); + if (!m) { + callback({error: 'CopySource format error'}); + return; + } - for (var i = 0; i < extensions.length; i++) { - var ext = extensions[i]; + var SourceBucket = m[1]; + var SourceRegion = m[3]; + var SourceKey = decodeURIComponent(m[4]); + var CopySliceSize = params.CopySliceSize === undefined ? self.options.CopySliceSize : params.CopySliceSize; + CopySliceSize = Math.max(0, CopySliceSize); + + var ChunkSize = params.CopyChunkSize || this.options.CopyChunkSize; + var ChunkParallel = this.options.CopyChunkParallelLimit; + + var FinishSize = 0; + var FileSize; + var onProgress; + + // 分片复制完成,开始 multipartComplete 操作 + ep.on('copy_slice_complete', function (UploadData) { + self.multipartComplete({ + Bucket: Bucket, + Region: Region, + Key: Key, + UploadId: UploadData.UploadId, + Parts: UploadData.PartList, + },function (err, data) { + if (err) { + onProgress(null, true); + return callback(err); + } + onProgress({loaded: FileSize, total: FileSize}, true); + callback(null, data); + }); + }); + + ep.on('get_copy_data_finish',function (UploadData) { + Async.eachLimit(UploadData.PartList, ChunkParallel, function (SliceItem, asyncCallback) { + var PartNumber = SliceItem.PartNumber; + var CopySourceRange = SliceItem.CopySourceRange; + var currentSize = SliceItem.end - SliceItem.start; + var preAddSize = 0; + + copySliceItem.call(self, { + Bucket: Bucket, + Region: Region, + Key: Key, + CopySource: CopySource, + UploadId: UploadData.UploadId, + PartNumber: PartNumber, + CopySourceRange: CopySourceRange, + onProgress: function (data) { + FinishSize += data.loaded - preAddSize; + preAddSize = data.loaded; + onProgress({loaded: FinishSize, total: FileSize}); + } + },function (err,data) { + if (err) { + return asyncCallback(err); + } + onProgress({loaded: FinishSize, total: FileSize}); + + FinishSize += currentSize - preAddSize; + SliceItem.ETag = data.ETag; + asyncCallback(err || null, data); + }); + }, function (err) { + if (err) { + onProgress(null, true); + return callback(err); + } - // '*' prefix = not the preferred type for this extension. So fixup the - // extension, and skip it. - if (ext[0] == '*') { - continue; - } + ep.emit('copy_slice_complete', UploadData); + }); + }); + + ep.on('get_file_size_finish', function (SourceHeaders) { + // 控制分片大小 + (function () { + var SIZE = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 1024 * 2, 1024 * 4, 1024 * 5]; + var AutoChunkSize = 1024 * 1024; + for (var i = 0; i < SIZE.length; i++) { + AutoChunkSize = SIZE[i] * 1024 * 1024; + if (FileSize / AutoChunkSize <= self.options.MaxPartNumber) break; + } + params.ChunkSize = ChunkSize = Math.max(ChunkSize, AutoChunkSize); + + var ChunkCount = Math.ceil(FileSize / ChunkSize); + + var list = []; + for (var partNumber = 1; partNumber <= ChunkCount; partNumber++) { + var start = (partNumber - 1) * ChunkSize; + var end = partNumber * ChunkSize < FileSize ? (partNumber * ChunkSize - 1) : FileSize - 1; + var item = { + PartNumber: partNumber, + start: start, + end: end, + CopySourceRange: "bytes=" + start + "-" + end, + }; + list.push(item); + } + params.PartList = list; + })(); - if (!force && (ext in this._types)) { - throw new Error( - 'Attempt to change mapping for "' + ext + - '" extension from "' + this._types[ext] + '" to "' + type + - '". Pass `force=true` to allow this, otherwise remove "' + ext + - '" from the list of extensions for "' + type + '".' - ); - } + var TargetHeader; + if (params.Headers['x-cos-metadata-directive'] === 'Replaced') { + TargetHeader = params.Headers; + } else { + TargetHeader = SourceHeaders; + } + TargetHeader['x-cos-storage-class'] = params.Headers['x-cos-storage-class'] || SourceHeaders['x-cos-storage-class']; + TargetHeader = util.clearKey(TargetHeader); + /** + * 对于归档存储的对象,如果未恢复副本,则不允许 Copy + */ + if (SourceHeaders['x-cos-storage-class'] === 'ARCHIVE' || SourceHeaders['x-cos-storage-class'] === 'DEEP_ARCHIVE') { + var restoreHeader = SourceHeaders['x-cos-restore']; + if (!restoreHeader || restoreHeader === 'ongoing-request="true"') { + callback({ error: 'Unrestored archive object is not allowed to be copied' }); + return; + } + } + /** + * 去除一些无用的头部,规避 multipartInit 出错 + * 这些头部通常是在 putObjectCopy 时才使用 + */ + delete TargetHeader['x-cos-copy-source']; + delete TargetHeader['x-cos-metadata-directive']; + delete TargetHeader['x-cos-copy-source-If-Modified-Since']; + delete TargetHeader['x-cos-copy-source-If-Unmodified-Since']; + delete TargetHeader['x-cos-copy-source-If-Match']; + delete TargetHeader['x-cos-copy-source-If-None-Match']; + self.multipartInit({ + Bucket: Bucket, + Region: Region, + Key: Key, + Headers: TargetHeader, + },function (err,data) { + if (err) { + return callback(err); + } + params.UploadId = data.UploadId; + ep.emit('get_copy_data_finish', params); + }); + }); + + // 获取远端复制源文件的大小 + self.headObject({ + Bucket: SourceBucket, + Region: SourceRegion, + Key: SourceKey, + },function(err, data) { + if (err) { + if (err.statusCode && err.statusCode === 404) { + callback({ErrorStatus: SourceKey + ' Not Exist'}); + } else { + callback(err); + } + return; + } - this._types[ext] = type; - } + FileSize = params.FileSize = data.headers['content-length']; + if (FileSize === undefined || !FileSize) { + callback({error: 'get Content-Length error, please add "Content-Length" to CORS ExposeHeader setting.'}); + return; + } - // Use first extension as default - if (force || !this._extensions[type]) { - var ext = extensions[0]; - this._extensions[type] = (ext[0] != '*') ? ext : ext.substr(1) - } - } -}; + onProgress = util.throttleOnProgress.call(self, FileSize, params.onProgress); -/** - * Lookup a mime type based on extension - */ -Mime.prototype.getType = function(path) { - path = String(path); - var last = path.replace(/^.*[/\\]/, '').toLowerCase(); - var ext = last.replace(/^.*\./, '').toLowerCase(); + // 开始上传 + if (FileSize <= CopySliceSize) { + if (!params.Headers['x-cos-metadata-directive']) { + params.Headers['x-cos-metadata-directive'] = 'Copy'; + } + self.putObjectCopy(params, function (err, data) { + if (err) { + onProgress(null, true); + return callback(err); + } + onProgress({loaded: FileSize, total: FileSize}, true); + callback(err, data); + }); + } else { + var resHeaders = data.headers; + var SourceHeaders = { + 'Cache-Control': resHeaders['cache-control'], + 'Content-Disposition': resHeaders['content-disposition'], + 'Content-Encoding': resHeaders['content-encoding'], + 'Content-Type': resHeaders['content-type'], + 'Expires': resHeaders['expires'], + 'x-cos-storage-class': resHeaders['x-cos-storage-class'], + }; + util.each(resHeaders, function (v, k) { + var metaPrefix = 'x-cos-meta-'; + if (k.indexOf(metaPrefix) === 0 && k.length > metaPrefix.length) { + SourceHeaders[k] = v; + } + }); + ep.emit('get_file_size_finish', SourceHeaders); + } + }); +} - var hasPath = last.length < path.length; - var hasDot = ext.length < last.length - 1; +// 复制指定分片 +function copySliceItem(params, callback) { + var TaskId = params.TaskId; + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var CopySource = params.CopySource; + var UploadId = params.UploadId; + var PartNumber = params.PartNumber * 1; + var CopySourceRange = params.CopySourceRange; + + var ChunkRetryTimes = this.options.ChunkRetryTimes + 1; + var self = this; + + Async.retry(ChunkRetryTimes, function (tryCallback) { + self.uploadPartCopy({ + TaskId: TaskId, + Bucket: Bucket, + Region: Region, + Key: Key, + CopySource: CopySource, + UploadId: UploadId, + PartNumber:PartNumber, + CopySourceRange:CopySourceRange, + onProgress:params.onProgress, + },function (err,data) { + tryCallback(err || null, data); + }) + }, function (err, data) { + return callback(err, data); + }); +} - return (hasDot || !hasPath) && this._types[ext] || null; -}; -/** - * Return file extension associated with a mime type - */ -Mime.prototype.getExtension = function(type) { - type = /^\s*([^;\s]*)/.test(type) && RegExp.$1; - return type && this._extensions[type.toLowerCase()] || null; +var API_MAP = { + sliceUploadFile: sliceUploadFile, + abortUploadTask: abortUploadTask, + uploadFile: uploadFile, + uploadFiles: uploadFiles, + sliceCopyFile: sliceCopyFile, }; -module.exports = Mime; +module.exports.init = function (COS, task) { + task.transferToTaskMethod(API_MAP, 'sliceUploadFile'); + util.each(API_MAP, function (fn, apiName) { + COS.prototype[apiName] = util.apiWrapper(apiName, fn); + }); +}; /***/ }), -/* 21 */ +/* 24 */ /***/ (function(module, exports) { -module.exports = {"application/andrew-inset":["ez"],"application/applixware":["aw"],"application/atom+xml":["atom"],"application/atomcat+xml":["atomcat"],"application/atomdeleted+xml":["atomdeleted"],"application/atomsvc+xml":["atomsvc"],"application/atsc-dwd+xml":["dwd"],"application/atsc-held+xml":["held"],"application/atsc-rsat+xml":["rsat"],"application/bdoc":["bdoc"],"application/calendar+xml":["xcs"],"application/ccxml+xml":["ccxml"],"application/cdfx+xml":["cdfx"],"application/cdmi-capability":["cdmia"],"application/cdmi-container":["cdmic"],"application/cdmi-domain":["cdmid"],"application/cdmi-object":["cdmio"],"application/cdmi-queue":["cdmiq"],"application/cu-seeme":["cu"],"application/dash+xml":["mpd"],"application/davmount+xml":["davmount"],"application/docbook+xml":["dbk"],"application/dssc+der":["dssc"],"application/dssc+xml":["xdssc"],"application/ecmascript":["ecma","es"],"application/emma+xml":["emma"],"application/emotionml+xml":["emotionml"],"application/epub+zip":["epub"],"application/exi":["exi"],"application/fdt+xml":["fdt"],"application/font-tdpfr":["pfr"],"application/geo+json":["geojson"],"application/gml+xml":["gml"],"application/gpx+xml":["gpx"],"application/gxf":["gxf"],"application/gzip":["gz"],"application/hjson":["hjson"],"application/hyperstudio":["stk"],"application/inkml+xml":["ink","inkml"],"application/ipfix":["ipfix"],"application/its+xml":["its"],"application/java-archive":["jar","war","ear"],"application/java-serialized-object":["ser"],"application/java-vm":["class"],"application/javascript":["js","mjs"],"application/json":["json","map"],"application/json5":["json5"],"application/jsonml+json":["jsonml"],"application/ld+json":["jsonld"],"application/lgr+xml":["lgr"],"application/lost+xml":["lostxml"],"application/mac-binhex40":["hqx"],"application/mac-compactpro":["cpt"],"application/mads+xml":["mads"],"application/manifest+json":["webmanifest"],"application/marc":["mrc"],"application/marcxml+xml":["mrcx"],"application/mathematica":["ma","nb","mb"],"application/mathml+xml":["mathml"],"application/mbox":["mbox"],"application/mediaservercontrol+xml":["mscml"],"application/metalink+xml":["metalink"],"application/metalink4+xml":["meta4"],"application/mets+xml":["mets"],"application/mmt-aei+xml":["maei"],"application/mmt-usd+xml":["musd"],"application/mods+xml":["mods"],"application/mp21":["m21","mp21"],"application/mp4":["mp4s","m4p"],"application/mrb-consumer+xml":["*xdf"],"application/mrb-publish+xml":["*xdf"],"application/msword":["doc","dot"],"application/mxf":["mxf"],"application/n-quads":["nq"],"application/n-triples":["nt"],"application/node":["cjs"],"application/octet-stream":["bin","dms","lrf","mar","so","dist","distz","pkg","bpk","dump","elc","deploy","exe","dll","deb","dmg","iso","img","msi","msp","msm","buffer"],"application/oda":["oda"],"application/oebps-package+xml":["opf"],"application/ogg":["ogx"],"application/omdoc+xml":["omdoc"],"application/onenote":["onetoc","onetoc2","onetmp","onepkg"],"application/oxps":["oxps"],"application/p2p-overlay+xml":["relo"],"application/patch-ops-error+xml":["*xer"],"application/pdf":["pdf"],"application/pgp-encrypted":["pgp"],"application/pgp-signature":["asc","sig"],"application/pics-rules":["prf"],"application/pkcs10":["p10"],"application/pkcs7-mime":["p7m","p7c"],"application/pkcs7-signature":["p7s"],"application/pkcs8":["p8"],"application/pkix-attr-cert":["ac"],"application/pkix-cert":["cer"],"application/pkix-crl":["crl"],"application/pkix-pkipath":["pkipath"],"application/pkixcmp":["pki"],"application/pls+xml":["pls"],"application/postscript":["ai","eps","ps"],"application/provenance+xml":["provx"],"application/pskc+xml":["pskcxml"],"application/raml+yaml":["raml"],"application/rdf+xml":["rdf","owl"],"application/reginfo+xml":["rif"],"application/relax-ng-compact-syntax":["rnc"],"application/resource-lists+xml":["rl"],"application/resource-lists-diff+xml":["rld"],"application/rls-services+xml":["rs"],"application/route-apd+xml":["rapd"],"application/route-s-tsid+xml":["sls"],"application/route-usd+xml":["rusd"],"application/rpki-ghostbusters":["gbr"],"application/rpki-manifest":["mft"],"application/rpki-roa":["roa"],"application/rsd+xml":["rsd"],"application/rss+xml":["rss"],"application/rtf":["rtf"],"application/sbml+xml":["sbml"],"application/scvp-cv-request":["scq"],"application/scvp-cv-response":["scs"],"application/scvp-vp-request":["spq"],"application/scvp-vp-response":["spp"],"application/sdp":["sdp"],"application/senml+xml":["senmlx"],"application/sensml+xml":["sensmlx"],"application/set-payment-initiation":["setpay"],"application/set-registration-initiation":["setreg"],"application/shf+xml":["shf"],"application/sieve":["siv","sieve"],"application/smil+xml":["smi","smil"],"application/sparql-query":["rq"],"application/sparql-results+xml":["srx"],"application/srgs":["gram"],"application/srgs+xml":["grxml"],"application/sru+xml":["sru"],"application/ssdl+xml":["ssdl"],"application/ssml+xml":["ssml"],"application/swid+xml":["swidtag"],"application/tei+xml":["tei","teicorpus"],"application/thraud+xml":["tfi"],"application/timestamped-data":["tsd"],"application/toml":["toml"],"application/ttml+xml":["ttml"],"application/urc-ressheet+xml":["rsheet"],"application/voicexml+xml":["vxml"],"application/wasm":["wasm"],"application/widget":["wgt"],"application/winhlp":["hlp"],"application/wsdl+xml":["wsdl"],"application/wspolicy+xml":["wspolicy"],"application/xaml+xml":["xaml"],"application/xcap-att+xml":["xav"],"application/xcap-caps+xml":["xca"],"application/xcap-diff+xml":["xdf"],"application/xcap-el+xml":["xel"],"application/xcap-error+xml":["xer"],"application/xcap-ns+xml":["xns"],"application/xenc+xml":["xenc"],"application/xhtml+xml":["xhtml","xht"],"application/xliff+xml":["xlf"],"application/xml":["xml","xsl","xsd","rng"],"application/xml-dtd":["dtd"],"application/xop+xml":["xop"],"application/xproc+xml":["xpl"],"application/xslt+xml":["xslt"],"application/xspf+xml":["xspf"],"application/xv+xml":["mxml","xhvml","xvml","xvm"],"application/yang":["yang"],"application/yin+xml":["yin"],"application/zip":["zip"],"audio/3gpp":["*3gpp"],"audio/adpcm":["adp"],"audio/basic":["au","snd"],"audio/midi":["mid","midi","kar","rmi"],"audio/mobile-xmf":["mxmf"],"audio/mp3":["*mp3"],"audio/mp4":["m4a","mp4a"],"audio/mpeg":["mpga","mp2","mp2a","mp3","m2a","m3a"],"audio/ogg":["oga","ogg","spx"],"audio/s3m":["s3m"],"audio/silk":["sil"],"audio/wav":["wav"],"audio/wave":["*wav"],"audio/webm":["weba"],"audio/xm":["xm"],"font/collection":["ttc"],"font/otf":["otf"],"font/ttf":["ttf"],"font/woff":["woff"],"font/woff2":["woff2"],"image/aces":["exr"],"image/apng":["apng"],"image/bmp":["bmp"],"image/cgm":["cgm"],"image/dicom-rle":["drle"],"image/emf":["emf"],"image/fits":["fits"],"image/g3fax":["g3"],"image/gif":["gif"],"image/heic":["heic"],"image/heic-sequence":["heics"],"image/heif":["heif"],"image/heif-sequence":["heifs"],"image/hej2k":["hej2"],"image/hsj2":["hsj2"],"image/ief":["ief"],"image/jls":["jls"],"image/jp2":["jp2","jpg2"],"image/jpeg":["jpeg","jpg","jpe"],"image/jph":["jph"],"image/jphc":["jhc"],"image/jpm":["jpm"],"image/jpx":["jpx","jpf"],"image/jxr":["jxr"],"image/jxra":["jxra"],"image/jxrs":["jxrs"],"image/jxs":["jxs"],"image/jxsc":["jxsc"],"image/jxsi":["jxsi"],"image/jxss":["jxss"],"image/ktx":["ktx"],"image/png":["png"],"image/sgi":["sgi"],"image/svg+xml":["svg","svgz"],"image/t38":["t38"],"image/tiff":["tif","tiff"],"image/tiff-fx":["tfx"],"image/webp":["webp"],"image/wmf":["wmf"],"message/disposition-notification":["disposition-notification"],"message/global":["u8msg"],"message/global-delivery-status":["u8dsn"],"message/global-disposition-notification":["u8mdn"],"message/global-headers":["u8hdr"],"message/rfc822":["eml","mime"],"model/3mf":["3mf"],"model/gltf+json":["gltf"],"model/gltf-binary":["glb"],"model/iges":["igs","iges"],"model/mesh":["msh","mesh","silo"],"model/mtl":["mtl"],"model/obj":["obj"],"model/stl":["stl"],"model/vrml":["wrl","vrml"],"model/x3d+binary":["*x3db","x3dbz"],"model/x3d+fastinfoset":["x3db"],"model/x3d+vrml":["*x3dv","x3dvz"],"model/x3d+xml":["x3d","x3dz"],"model/x3d-vrml":["x3dv"],"text/cache-manifest":["appcache","manifest"],"text/calendar":["ics","ifb"],"text/coffeescript":["coffee","litcoffee"],"text/css":["css"],"text/csv":["csv"],"text/html":["html","htm","shtml"],"text/jade":["jade"],"text/jsx":["jsx"],"text/less":["less"],"text/markdown":["markdown","md"],"text/mathml":["mml"],"text/mdx":["mdx"],"text/n3":["n3"],"text/plain":["txt","text","conf","def","list","log","in","ini"],"text/richtext":["rtx"],"text/rtf":["*rtf"],"text/sgml":["sgml","sgm"],"text/shex":["shex"],"text/slim":["slim","slm"],"text/stylus":["stylus","styl"],"text/tab-separated-values":["tsv"],"text/troff":["t","tr","roff","man","me","ms"],"text/turtle":["ttl"],"text/uri-list":["uri","uris","urls"],"text/vcard":["vcard"],"text/vtt":["vtt"],"text/xml":["*xml"],"text/yaml":["yaml","yml"],"video/3gpp":["3gp","3gpp"],"video/3gpp2":["3g2"],"video/h261":["h261"],"video/h263":["h263"],"video/h264":["h264"],"video/jpeg":["jpgv"],"video/jpm":["*jpm","jpgm"],"video/mj2":["mj2","mjp2"],"video/mp2t":["ts"],"video/mp4":["mp4","mp4v","mpg4"],"video/mpeg":["mpeg","mpg","mpe","m1v","m2v"],"video/ogg":["ogv"],"video/quicktime":["qt","mov"],"video/webm":["webm"]}; - -/***/ }), -/* 22 */ -/***/ (function(module, exports) { +var eachLimit = function (arr, limit, iterator, callback) { + callback = callback || function () {}; + if (!arr.length || limit <= 0) { + return callback(); + } -module.exports = {"application/prs.cww":["cww"],"application/vnd.1000minds.decision-model+xml":["1km"],"application/vnd.3gpp.pic-bw-large":["plb"],"application/vnd.3gpp.pic-bw-small":["psb"],"application/vnd.3gpp.pic-bw-var":["pvb"],"application/vnd.3gpp2.tcap":["tcap"],"application/vnd.3m.post-it-notes":["pwn"],"application/vnd.accpac.simply.aso":["aso"],"application/vnd.accpac.simply.imp":["imp"],"application/vnd.acucobol":["acu"],"application/vnd.acucorp":["atc","acutc"],"application/vnd.adobe.air-application-installer-package+zip":["air"],"application/vnd.adobe.formscentral.fcdt":["fcdt"],"application/vnd.adobe.fxp":["fxp","fxpl"],"application/vnd.adobe.xdp+xml":["xdp"],"application/vnd.adobe.xfdf":["xfdf"],"application/vnd.ahead.space":["ahead"],"application/vnd.airzip.filesecure.azf":["azf"],"application/vnd.airzip.filesecure.azs":["azs"],"application/vnd.amazon.ebook":["azw"],"application/vnd.americandynamics.acc":["acc"],"application/vnd.amiga.ami":["ami"],"application/vnd.android.package-archive":["apk"],"application/vnd.anser-web-certificate-issue-initiation":["cii"],"application/vnd.anser-web-funds-transfer-initiation":["fti"],"application/vnd.antix.game-component":["atx"],"application/vnd.apple.installer+xml":["mpkg"],"application/vnd.apple.keynote":["keynote"],"application/vnd.apple.mpegurl":["m3u8"],"application/vnd.apple.numbers":["numbers"],"application/vnd.apple.pages":["pages"],"application/vnd.apple.pkpass":["pkpass"],"application/vnd.aristanetworks.swi":["swi"],"application/vnd.astraea-software.iota":["iota"],"application/vnd.audiograph":["aep"],"application/vnd.balsamiq.bmml+xml":["bmml"],"application/vnd.blueice.multipass":["mpm"],"application/vnd.bmi":["bmi"],"application/vnd.businessobjects":["rep"],"application/vnd.chemdraw+xml":["cdxml"],"application/vnd.chipnuts.karaoke-mmd":["mmd"],"application/vnd.cinderella":["cdy"],"application/vnd.citationstyles.style+xml":["csl"],"application/vnd.claymore":["cla"],"application/vnd.cloanto.rp9":["rp9"],"application/vnd.clonk.c4group":["c4g","c4d","c4f","c4p","c4u"],"application/vnd.cluetrust.cartomobile-config":["c11amc"],"application/vnd.cluetrust.cartomobile-config-pkg":["c11amz"],"application/vnd.commonspace":["csp"],"application/vnd.contact.cmsg":["cdbcmsg"],"application/vnd.cosmocaller":["cmc"],"application/vnd.crick.clicker":["clkx"],"application/vnd.crick.clicker.keyboard":["clkk"],"application/vnd.crick.clicker.palette":["clkp"],"application/vnd.crick.clicker.template":["clkt"],"application/vnd.crick.clicker.wordbank":["clkw"],"application/vnd.criticaltools.wbs+xml":["wbs"],"application/vnd.ctc-posml":["pml"],"application/vnd.cups-ppd":["ppd"],"application/vnd.curl.car":["car"],"application/vnd.curl.pcurl":["pcurl"],"application/vnd.dart":["dart"],"application/vnd.data-vision.rdz":["rdz"],"application/vnd.dece.data":["uvf","uvvf","uvd","uvvd"],"application/vnd.dece.ttml+xml":["uvt","uvvt"],"application/vnd.dece.unspecified":["uvx","uvvx"],"application/vnd.dece.zip":["uvz","uvvz"],"application/vnd.denovo.fcselayout-link":["fe_launch"],"application/vnd.dna":["dna"],"application/vnd.dolby.mlp":["mlp"],"application/vnd.dpgraph":["dpg"],"application/vnd.dreamfactory":["dfac"],"application/vnd.ds-keypoint":["kpxx"],"application/vnd.dvb.ait":["ait"],"application/vnd.dvb.service":["svc"],"application/vnd.dynageo":["geo"],"application/vnd.ecowin.chart":["mag"],"application/vnd.enliven":["nml"],"application/vnd.epson.esf":["esf"],"application/vnd.epson.msf":["msf"],"application/vnd.epson.quickanime":["qam"],"application/vnd.epson.salt":["slt"],"application/vnd.epson.ssf":["ssf"],"application/vnd.eszigno3+xml":["es3","et3"],"application/vnd.ezpix-album":["ez2"],"application/vnd.ezpix-package":["ez3"],"application/vnd.fdf":["fdf"],"application/vnd.fdsn.mseed":["mseed"],"application/vnd.fdsn.seed":["seed","dataless"],"application/vnd.flographit":["gph"],"application/vnd.fluxtime.clip":["ftc"],"application/vnd.framemaker":["fm","frame","maker","book"],"application/vnd.frogans.fnc":["fnc"],"application/vnd.frogans.ltf":["ltf"],"application/vnd.fsc.weblaunch":["fsc"],"application/vnd.fujitsu.oasys":["oas"],"application/vnd.fujitsu.oasys2":["oa2"],"application/vnd.fujitsu.oasys3":["oa3"],"application/vnd.fujitsu.oasysgp":["fg5"],"application/vnd.fujitsu.oasysprs":["bh2"],"application/vnd.fujixerox.ddd":["ddd"],"application/vnd.fujixerox.docuworks":["xdw"],"application/vnd.fujixerox.docuworks.binder":["xbd"],"application/vnd.fuzzysheet":["fzs"],"application/vnd.genomatix.tuxedo":["txd"],"application/vnd.geogebra.file":["ggb"],"application/vnd.geogebra.tool":["ggt"],"application/vnd.geometry-explorer":["gex","gre"],"application/vnd.geonext":["gxt"],"application/vnd.geoplan":["g2w"],"application/vnd.geospace":["g3w"],"application/vnd.gmx":["gmx"],"application/vnd.google-apps.document":["gdoc"],"application/vnd.google-apps.presentation":["gslides"],"application/vnd.google-apps.spreadsheet":["gsheet"],"application/vnd.google-earth.kml+xml":["kml"],"application/vnd.google-earth.kmz":["kmz"],"application/vnd.grafeq":["gqf","gqs"],"application/vnd.groove-account":["gac"],"application/vnd.groove-help":["ghf"],"application/vnd.groove-identity-message":["gim"],"application/vnd.groove-injector":["grv"],"application/vnd.groove-tool-message":["gtm"],"application/vnd.groove-tool-template":["tpl"],"application/vnd.groove-vcard":["vcg"],"application/vnd.hal+xml":["hal"],"application/vnd.handheld-entertainment+xml":["zmm"],"application/vnd.hbci":["hbci"],"application/vnd.hhe.lesson-player":["les"],"application/vnd.hp-hpgl":["hpgl"],"application/vnd.hp-hpid":["hpid"],"application/vnd.hp-hps":["hps"],"application/vnd.hp-jlyt":["jlt"],"application/vnd.hp-pcl":["pcl"],"application/vnd.hp-pclxl":["pclxl"],"application/vnd.hydrostatix.sof-data":["sfd-hdstx"],"application/vnd.ibm.minipay":["mpy"],"application/vnd.ibm.modcap":["afp","listafp","list3820"],"application/vnd.ibm.rights-management":["irm"],"application/vnd.ibm.secure-container":["sc"],"application/vnd.iccprofile":["icc","icm"],"application/vnd.igloader":["igl"],"application/vnd.immervision-ivp":["ivp"],"application/vnd.immervision-ivu":["ivu"],"application/vnd.insors.igm":["igm"],"application/vnd.intercon.formnet":["xpw","xpx"],"application/vnd.intergeo":["i2g"],"application/vnd.intu.qbo":["qbo"],"application/vnd.intu.qfx":["qfx"],"application/vnd.ipunplugged.rcprofile":["rcprofile"],"application/vnd.irepository.package+xml":["irp"],"application/vnd.is-xpr":["xpr"],"application/vnd.isac.fcs":["fcs"],"application/vnd.jam":["jam"],"application/vnd.jcp.javame.midlet-rms":["rms"],"application/vnd.jisp":["jisp"],"application/vnd.joost.joda-archive":["joda"],"application/vnd.kahootz":["ktz","ktr"],"application/vnd.kde.karbon":["karbon"],"application/vnd.kde.kchart":["chrt"],"application/vnd.kde.kformula":["kfo"],"application/vnd.kde.kivio":["flw"],"application/vnd.kde.kontour":["kon"],"application/vnd.kde.kpresenter":["kpr","kpt"],"application/vnd.kde.kspread":["ksp"],"application/vnd.kde.kword":["kwd","kwt"],"application/vnd.kenameaapp":["htke"],"application/vnd.kidspiration":["kia"],"application/vnd.kinar":["kne","knp"],"application/vnd.koan":["skp","skd","skt","skm"],"application/vnd.kodak-descriptor":["sse"],"application/vnd.las.las+xml":["lasxml"],"application/vnd.llamagraphics.life-balance.desktop":["lbd"],"application/vnd.llamagraphics.life-balance.exchange+xml":["lbe"],"application/vnd.lotus-1-2-3":["123"],"application/vnd.lotus-approach":["apr"],"application/vnd.lotus-freelance":["pre"],"application/vnd.lotus-notes":["nsf"],"application/vnd.lotus-organizer":["org"],"application/vnd.lotus-screencam":["scm"],"application/vnd.lotus-wordpro":["lwp"],"application/vnd.macports.portpkg":["portpkg"],"application/vnd.mcd":["mcd"],"application/vnd.medcalcdata":["mc1"],"application/vnd.mediastation.cdkey":["cdkey"],"application/vnd.mfer":["mwf"],"application/vnd.mfmp":["mfm"],"application/vnd.micrografx.flo":["flo"],"application/vnd.micrografx.igx":["igx"],"application/vnd.mif":["mif"],"application/vnd.mobius.daf":["daf"],"application/vnd.mobius.dis":["dis"],"application/vnd.mobius.mbk":["mbk"],"application/vnd.mobius.mqy":["mqy"],"application/vnd.mobius.msl":["msl"],"application/vnd.mobius.plc":["plc"],"application/vnd.mobius.txf":["txf"],"application/vnd.mophun.application":["mpn"],"application/vnd.mophun.certificate":["mpc"],"application/vnd.mozilla.xul+xml":["xul"],"application/vnd.ms-artgalry":["cil"],"application/vnd.ms-cab-compressed":["cab"],"application/vnd.ms-excel":["xls","xlm","xla","xlc","xlt","xlw"],"application/vnd.ms-excel.addin.macroenabled.12":["xlam"],"application/vnd.ms-excel.sheet.binary.macroenabled.12":["xlsb"],"application/vnd.ms-excel.sheet.macroenabled.12":["xlsm"],"application/vnd.ms-excel.template.macroenabled.12":["xltm"],"application/vnd.ms-fontobject":["eot"],"application/vnd.ms-htmlhelp":["chm"],"application/vnd.ms-ims":["ims"],"application/vnd.ms-lrm":["lrm"],"application/vnd.ms-officetheme":["thmx"],"application/vnd.ms-outlook":["msg"],"application/vnd.ms-pki.seccat":["cat"],"application/vnd.ms-pki.stl":["*stl"],"application/vnd.ms-powerpoint":["ppt","pps","pot"],"application/vnd.ms-powerpoint.addin.macroenabled.12":["ppam"],"application/vnd.ms-powerpoint.presentation.macroenabled.12":["pptm"],"application/vnd.ms-powerpoint.slide.macroenabled.12":["sldm"],"application/vnd.ms-powerpoint.slideshow.macroenabled.12":["ppsm"],"application/vnd.ms-powerpoint.template.macroenabled.12":["potm"],"application/vnd.ms-project":["mpp","mpt"],"application/vnd.ms-word.document.macroenabled.12":["docm"],"application/vnd.ms-word.template.macroenabled.12":["dotm"],"application/vnd.ms-works":["wps","wks","wcm","wdb"],"application/vnd.ms-wpl":["wpl"],"application/vnd.ms-xpsdocument":["xps"],"application/vnd.mseq":["mseq"],"application/vnd.musician":["mus"],"application/vnd.muvee.style":["msty"],"application/vnd.mynfc":["taglet"],"application/vnd.neurolanguage.nlu":["nlu"],"application/vnd.nitf":["ntf","nitf"],"application/vnd.noblenet-directory":["nnd"],"application/vnd.noblenet-sealer":["nns"],"application/vnd.noblenet-web":["nnw"],"application/vnd.nokia.n-gage.ac+xml":["*ac"],"application/vnd.nokia.n-gage.data":["ngdat"],"application/vnd.nokia.n-gage.symbian.install":["n-gage"],"application/vnd.nokia.radio-preset":["rpst"],"application/vnd.nokia.radio-presets":["rpss"],"application/vnd.novadigm.edm":["edm"],"application/vnd.novadigm.edx":["edx"],"application/vnd.novadigm.ext":["ext"],"application/vnd.oasis.opendocument.chart":["odc"],"application/vnd.oasis.opendocument.chart-template":["otc"],"application/vnd.oasis.opendocument.database":["odb"],"application/vnd.oasis.opendocument.formula":["odf"],"application/vnd.oasis.opendocument.formula-template":["odft"],"application/vnd.oasis.opendocument.graphics":["odg"],"application/vnd.oasis.opendocument.graphics-template":["otg"],"application/vnd.oasis.opendocument.image":["odi"],"application/vnd.oasis.opendocument.image-template":["oti"],"application/vnd.oasis.opendocument.presentation":["odp"],"application/vnd.oasis.opendocument.presentation-template":["otp"],"application/vnd.oasis.opendocument.spreadsheet":["ods"],"application/vnd.oasis.opendocument.spreadsheet-template":["ots"],"application/vnd.oasis.opendocument.text":["odt"],"application/vnd.oasis.opendocument.text-master":["odm"],"application/vnd.oasis.opendocument.text-template":["ott"],"application/vnd.oasis.opendocument.text-web":["oth"],"application/vnd.olpc-sugar":["xo"],"application/vnd.oma.dd2+xml":["dd2"],"application/vnd.openblox.game+xml":["obgx"],"application/vnd.openofficeorg.extension":["oxt"],"application/vnd.openstreetmap.data+xml":["osm"],"application/vnd.openxmlformats-officedocument.presentationml.presentation":["pptx"],"application/vnd.openxmlformats-officedocument.presentationml.slide":["sldx"],"application/vnd.openxmlformats-officedocument.presentationml.slideshow":["ppsx"],"application/vnd.openxmlformats-officedocument.presentationml.template":["potx"],"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":["xlsx"],"application/vnd.openxmlformats-officedocument.spreadsheetml.template":["xltx"],"application/vnd.openxmlformats-officedocument.wordprocessingml.document":["docx"],"application/vnd.openxmlformats-officedocument.wordprocessingml.template":["dotx"],"application/vnd.osgeo.mapguide.package":["mgp"],"application/vnd.osgi.dp":["dp"],"application/vnd.osgi.subsystem":["esa"],"application/vnd.palm":["pdb","pqa","oprc"],"application/vnd.pawaafile":["paw"],"application/vnd.pg.format":["str"],"application/vnd.pg.osasli":["ei6"],"application/vnd.picsel":["efif"],"application/vnd.pmi.widget":["wg"],"application/vnd.pocketlearn":["plf"],"application/vnd.powerbuilder6":["pbd"],"application/vnd.previewsystems.box":["box"],"application/vnd.proteus.magazine":["mgz"],"application/vnd.publishare-delta-tree":["qps"],"application/vnd.pvi.ptid1":["ptid"],"application/vnd.quark.quarkxpress":["qxd","qxt","qwd","qwt","qxl","qxb"],"application/vnd.realvnc.bed":["bed"],"application/vnd.recordare.musicxml":["mxl"],"application/vnd.recordare.musicxml+xml":["musicxml"],"application/vnd.rig.cryptonote":["cryptonote"],"application/vnd.rim.cod":["cod"],"application/vnd.rn-realmedia":["rm"],"application/vnd.rn-realmedia-vbr":["rmvb"],"application/vnd.route66.link66+xml":["link66"],"application/vnd.sailingtracker.track":["st"],"application/vnd.seemail":["see"],"application/vnd.sema":["sema"],"application/vnd.semd":["semd"],"application/vnd.semf":["semf"],"application/vnd.shana.informed.formdata":["ifm"],"application/vnd.shana.informed.formtemplate":["itp"],"application/vnd.shana.informed.interchange":["iif"],"application/vnd.shana.informed.package":["ipk"],"application/vnd.simtech-mindmapper":["twd","twds"],"application/vnd.smaf":["mmf"],"application/vnd.smart.teacher":["teacher"],"application/vnd.software602.filler.form+xml":["fo"],"application/vnd.solent.sdkm+xml":["sdkm","sdkd"],"application/vnd.spotfire.dxp":["dxp"],"application/vnd.spotfire.sfs":["sfs"],"application/vnd.stardivision.calc":["sdc"],"application/vnd.stardivision.draw":["sda"],"application/vnd.stardivision.impress":["sdd"],"application/vnd.stardivision.math":["smf"],"application/vnd.stardivision.writer":["sdw","vor"],"application/vnd.stardivision.writer-global":["sgl"],"application/vnd.stepmania.package":["smzip"],"application/vnd.stepmania.stepchart":["sm"],"application/vnd.sun.wadl+xml":["wadl"],"application/vnd.sun.xml.calc":["sxc"],"application/vnd.sun.xml.calc.template":["stc"],"application/vnd.sun.xml.draw":["sxd"],"application/vnd.sun.xml.draw.template":["std"],"application/vnd.sun.xml.impress":["sxi"],"application/vnd.sun.xml.impress.template":["sti"],"application/vnd.sun.xml.math":["sxm"],"application/vnd.sun.xml.writer":["sxw"],"application/vnd.sun.xml.writer.global":["sxg"],"application/vnd.sun.xml.writer.template":["stw"],"application/vnd.sus-calendar":["sus","susp"],"application/vnd.svd":["svd"],"application/vnd.symbian.install":["sis","sisx"],"application/vnd.syncml+xml":["xsm"],"application/vnd.syncml.dm+wbxml":["bdm"],"application/vnd.syncml.dm+xml":["xdm"],"application/vnd.syncml.dmddf+xml":["ddf"],"application/vnd.tao.intent-module-archive":["tao"],"application/vnd.tcpdump.pcap":["pcap","cap","dmp"],"application/vnd.tmobile-livetv":["tmo"],"application/vnd.trid.tpt":["tpt"],"application/vnd.triscape.mxs":["mxs"],"application/vnd.trueapp":["tra"],"application/vnd.ufdl":["ufd","ufdl"],"application/vnd.uiq.theme":["utz"],"application/vnd.umajin":["umj"],"application/vnd.unity":["unityweb"],"application/vnd.uoml+xml":["uoml"],"application/vnd.vcx":["vcx"],"application/vnd.visio":["vsd","vst","vss","vsw"],"application/vnd.visionary":["vis"],"application/vnd.vsf":["vsf"],"application/vnd.wap.wbxml":["wbxml"],"application/vnd.wap.wmlc":["wmlc"],"application/vnd.wap.wmlscriptc":["wmlsc"],"application/vnd.webturbo":["wtb"],"application/vnd.wolfram.player":["nbp"],"application/vnd.wordperfect":["wpd"],"application/vnd.wqd":["wqd"],"application/vnd.wt.stf":["stf"],"application/vnd.xara":["xar"],"application/vnd.xfdl":["xfdl"],"application/vnd.yamaha.hv-dic":["hvd"],"application/vnd.yamaha.hv-script":["hvs"],"application/vnd.yamaha.hv-voice":["hvp"],"application/vnd.yamaha.openscoreformat":["osf"],"application/vnd.yamaha.openscoreformat.osfpvg+xml":["osfpvg"],"application/vnd.yamaha.smaf-audio":["saf"],"application/vnd.yamaha.smaf-phrase":["spf"],"application/vnd.yellowriver-custom-menu":["cmp"],"application/vnd.zul":["zir","zirz"],"application/vnd.zzazz.deck+xml":["zaz"],"application/x-7z-compressed":["7z"],"application/x-abiword":["abw"],"application/x-ace-compressed":["ace"],"application/x-apple-diskimage":["*dmg"],"application/x-arj":["arj"],"application/x-authorware-bin":["aab","x32","u32","vox"],"application/x-authorware-map":["aam"],"application/x-authorware-seg":["aas"],"application/x-bcpio":["bcpio"],"application/x-bdoc":["*bdoc"],"application/x-bittorrent":["torrent"],"application/x-blorb":["blb","blorb"],"application/x-bzip":["bz"],"application/x-bzip2":["bz2","boz"],"application/x-cbr":["cbr","cba","cbt","cbz","cb7"],"application/x-cdlink":["vcd"],"application/x-cfs-compressed":["cfs"],"application/x-chat":["chat"],"application/x-chess-pgn":["pgn"],"application/x-chrome-extension":["crx"],"application/x-cocoa":["cco"],"application/x-conference":["nsc"],"application/x-cpio":["cpio"],"application/x-csh":["csh"],"application/x-debian-package":["*deb","udeb"],"application/x-dgc-compressed":["dgc"],"application/x-director":["dir","dcr","dxr","cst","cct","cxt","w3d","fgd","swa"],"application/x-doom":["wad"],"application/x-dtbncx+xml":["ncx"],"application/x-dtbook+xml":["dtb"],"application/x-dtbresource+xml":["res"],"application/x-dvi":["dvi"],"application/x-envoy":["evy"],"application/x-eva":["eva"],"application/x-font-bdf":["bdf"],"application/x-font-ghostscript":["gsf"],"application/x-font-linux-psf":["psf"],"application/x-font-pcf":["pcf"],"application/x-font-snf":["snf"],"application/x-font-type1":["pfa","pfb","pfm","afm"],"application/x-freearc":["arc"],"application/x-futuresplash":["spl"],"application/x-gca-compressed":["gca"],"application/x-glulx":["ulx"],"application/x-gnumeric":["gnumeric"],"application/x-gramps-xml":["gramps"],"application/x-gtar":["gtar"],"application/x-hdf":["hdf"],"application/x-httpd-php":["php"],"application/x-install-instructions":["install"],"application/x-iso9660-image":["*iso"],"application/x-java-archive-diff":["jardiff"],"application/x-java-jnlp-file":["jnlp"],"application/x-keepass2":["kdbx"],"application/x-latex":["latex"],"application/x-lua-bytecode":["luac"],"application/x-lzh-compressed":["lzh","lha"],"application/x-makeself":["run"],"application/x-mie":["mie"],"application/x-mobipocket-ebook":["prc","mobi"],"application/x-ms-application":["application"],"application/x-ms-shortcut":["lnk"],"application/x-ms-wmd":["wmd"],"application/x-ms-wmz":["wmz"],"application/x-ms-xbap":["xbap"],"application/x-msaccess":["mdb"],"application/x-msbinder":["obd"],"application/x-mscardfile":["crd"],"application/x-msclip":["clp"],"application/x-msdos-program":["*exe"],"application/x-msdownload":["*exe","*dll","com","bat","*msi"],"application/x-msmediaview":["mvb","m13","m14"],"application/x-msmetafile":["*wmf","*wmz","*emf","emz"],"application/x-msmoney":["mny"],"application/x-mspublisher":["pub"],"application/x-msschedule":["scd"],"application/x-msterminal":["trm"],"application/x-mswrite":["wri"],"application/x-netcdf":["nc","cdf"],"application/x-ns-proxy-autoconfig":["pac"],"application/x-nzb":["nzb"],"application/x-perl":["pl","pm"],"application/x-pilot":["*prc","*pdb"],"application/x-pkcs12":["p12","pfx"],"application/x-pkcs7-certificates":["p7b","spc"],"application/x-pkcs7-certreqresp":["p7r"],"application/x-rar-compressed":["rar"],"application/x-redhat-package-manager":["rpm"],"application/x-research-info-systems":["ris"],"application/x-sea":["sea"],"application/x-sh":["sh"],"application/x-shar":["shar"],"application/x-shockwave-flash":["swf"],"application/x-silverlight-app":["xap"],"application/x-sql":["sql"],"application/x-stuffit":["sit"],"application/x-stuffitx":["sitx"],"application/x-subrip":["srt"],"application/x-sv4cpio":["sv4cpio"],"application/x-sv4crc":["sv4crc"],"application/x-t3vm-image":["t3"],"application/x-tads":["gam"],"application/x-tar":["tar"],"application/x-tcl":["tcl","tk"],"application/x-tex":["tex"],"application/x-tex-tfm":["tfm"],"application/x-texinfo":["texinfo","texi"],"application/x-tgif":["*obj"],"application/x-ustar":["ustar"],"application/x-virtualbox-hdd":["hdd"],"application/x-virtualbox-ova":["ova"],"application/x-virtualbox-ovf":["ovf"],"application/x-virtualbox-vbox":["vbox"],"application/x-virtualbox-vbox-extpack":["vbox-extpack"],"application/x-virtualbox-vdi":["vdi"],"application/x-virtualbox-vhd":["vhd"],"application/x-virtualbox-vmdk":["vmdk"],"application/x-wais-source":["src"],"application/x-web-app-manifest+json":["webapp"],"application/x-x509-ca-cert":["der","crt","pem"],"application/x-xfig":["fig"],"application/x-xliff+xml":["*xlf"],"application/x-xpinstall":["xpi"],"application/x-xz":["xz"],"application/x-zmachine":["z1","z2","z3","z4","z5","z6","z7","z8"],"audio/vnd.dece.audio":["uva","uvva"],"audio/vnd.digital-winds":["eol"],"audio/vnd.dra":["dra"],"audio/vnd.dts":["dts"],"audio/vnd.dts.hd":["dtshd"],"audio/vnd.lucent.voice":["lvp"],"audio/vnd.ms-playready.media.pya":["pya"],"audio/vnd.nuera.ecelp4800":["ecelp4800"],"audio/vnd.nuera.ecelp7470":["ecelp7470"],"audio/vnd.nuera.ecelp9600":["ecelp9600"],"audio/vnd.rip":["rip"],"audio/x-aac":["aac"],"audio/x-aiff":["aif","aiff","aifc"],"audio/x-caf":["caf"],"audio/x-flac":["flac"],"audio/x-m4a":["*m4a"],"audio/x-matroska":["mka"],"audio/x-mpegurl":["m3u"],"audio/x-ms-wax":["wax"],"audio/x-ms-wma":["wma"],"audio/x-pn-realaudio":["ram","ra"],"audio/x-pn-realaudio-plugin":["rmp"],"audio/x-realaudio":["*ra"],"audio/x-wav":["*wav"],"chemical/x-cdx":["cdx"],"chemical/x-cif":["cif"],"chemical/x-cmdf":["cmdf"],"chemical/x-cml":["cml"],"chemical/x-csml":["csml"],"chemical/x-xyz":["xyz"],"image/prs.btif":["btif"],"image/prs.pti":["pti"],"image/vnd.adobe.photoshop":["psd"],"image/vnd.airzip.accelerator.azv":["azv"],"image/vnd.dece.graphic":["uvi","uvvi","uvg","uvvg"],"image/vnd.djvu":["djvu","djv"],"image/vnd.dvb.subtitle":["*sub"],"image/vnd.dwg":["dwg"],"image/vnd.dxf":["dxf"],"image/vnd.fastbidsheet":["fbs"],"image/vnd.fpx":["fpx"],"image/vnd.fst":["fst"],"image/vnd.fujixerox.edmics-mmr":["mmr"],"image/vnd.fujixerox.edmics-rlc":["rlc"],"image/vnd.microsoft.icon":["ico"],"image/vnd.ms-dds":["dds"],"image/vnd.ms-modi":["mdi"],"image/vnd.ms-photo":["wdp"],"image/vnd.net-fpx":["npx"],"image/vnd.tencent.tap":["tap"],"image/vnd.valve.source.texture":["vtf"],"image/vnd.wap.wbmp":["wbmp"],"image/vnd.xiff":["xif"],"image/vnd.zbrush.pcx":["pcx"],"image/x-3ds":["3ds"],"image/x-cmu-raster":["ras"],"image/x-cmx":["cmx"],"image/x-freehand":["fh","fhc","fh4","fh5","fh7"],"image/x-icon":["*ico"],"image/x-jng":["jng"],"image/x-mrsid-image":["sid"],"image/x-ms-bmp":["*bmp"],"image/x-pcx":["*pcx"],"image/x-pict":["pic","pct"],"image/x-portable-anymap":["pnm"],"image/x-portable-bitmap":["pbm"],"image/x-portable-graymap":["pgm"],"image/x-portable-pixmap":["ppm"],"image/x-rgb":["rgb"],"image/x-tga":["tga"],"image/x-xbitmap":["xbm"],"image/x-xpixmap":["xpm"],"image/x-xwindowdump":["xwd"],"message/vnd.wfa.wsc":["wsc"],"model/vnd.collada+xml":["dae"],"model/vnd.dwf":["dwf"],"model/vnd.gdl":["gdl"],"model/vnd.gtw":["gtw"],"model/vnd.mts":["mts"],"model/vnd.opengex":["ogex"],"model/vnd.parasolid.transmit.binary":["x_b"],"model/vnd.parasolid.transmit.text":["x_t"],"model/vnd.usdz+zip":["usdz"],"model/vnd.valve.source.compiled-map":["bsp"],"model/vnd.vtu":["vtu"],"text/prs.lines.tag":["dsc"],"text/vnd.curl":["curl"],"text/vnd.curl.dcurl":["dcurl"],"text/vnd.curl.mcurl":["mcurl"],"text/vnd.curl.scurl":["scurl"],"text/vnd.dvb.subtitle":["sub"],"text/vnd.fly":["fly"],"text/vnd.fmi.flexstor":["flx"],"text/vnd.graphviz":["gv"],"text/vnd.in3d.3dml":["3dml"],"text/vnd.in3d.spot":["spot"],"text/vnd.sun.j2me.app-descriptor":["jad"],"text/vnd.wap.wml":["wml"],"text/vnd.wap.wmlscript":["wmls"],"text/x-asm":["s","asm"],"text/x-c":["c","cc","cxx","cpp","h","hh","dic"],"text/x-component":["htc"],"text/x-fortran":["f","for","f77","f90"],"text/x-handlebars-template":["hbs"],"text/x-java-source":["java"],"text/x-lua":["lua"],"text/x-markdown":["mkd"],"text/x-nfo":["nfo"],"text/x-opml":["opml"],"text/x-org":["*org"],"text/x-pascal":["p","pas"],"text/x-processing":["pde"],"text/x-sass":["sass"],"text/x-scss":["scss"],"text/x-setext":["etx"],"text/x-sfv":["sfv"],"text/x-suse-ymp":["ymp"],"text/x-uuencode":["uu"],"text/x-vcalendar":["vcs"],"text/x-vcard":["vcf"],"video/vnd.dece.hd":["uvh","uvvh"],"video/vnd.dece.mobile":["uvm","uvvm"],"video/vnd.dece.pd":["uvp","uvvp"],"video/vnd.dece.sd":["uvs","uvvs"],"video/vnd.dece.video":["uvv","uvvv"],"video/vnd.dvb.file":["dvb"],"video/vnd.fvt":["fvt"],"video/vnd.mpegurl":["mxu","m4u"],"video/vnd.ms-playready.media.pyv":["pyv"],"video/vnd.uvvu.mp4":["uvu","uvvu"],"video/vnd.vivo":["viv"],"video/x-f4v":["f4v"],"video/x-fli":["fli"],"video/x-flv":["flv"],"video/x-m4v":["m4v"],"video/x-matroska":["mkv","mk3d","mks"],"video/x-mng":["mng"],"video/x-ms-asf":["asf","asx"],"video/x-ms-vob":["vob"],"video/x-ms-wm":["wm"],"video/x-ms-wmv":["wmv"],"video/x-ms-wmx":["wmx"],"video/x-ms-wvx":["wvx"],"video/x-msvideo":["avi"],"video/x-sgi-movie":["movie"],"video/x-smv":["smv"],"x-conference/x-cooltalk":["ice"]}; + var completed = 0; + var started = 0; + var running = 0; -/***/ }), -/* 23 */ -/***/ (function(module, exports, __webpack_require__) { + (function replenish () { + if (completed >= arr.length) { + return callback(); + } -var session = __webpack_require__(5); -var Async = __webpack_require__(24); -var EventProxy = __webpack_require__(4).EventProxy; -var util = __webpack_require__(0); - -// 文件分块上传全过程,暴露的分块上传接口 -function sliceUploadFile(params, callback) { - var self = this; - - // 如果小程序版本不支持获取文件分片内容,统一转到 postObject 接口上传 - if (!util.canFileSlice()) { - params.SkipTask = true; - self.postObject(params, callback); - return; - } - - var ep = new EventProxy(); - var TaskId = params.TaskId; - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var FilePath = params.FilePath; - var ChunkSize = params.ChunkSize || params.SliceSize || self.options.ChunkSize; - var AsyncLimit = params.AsyncLimit; - var StorageClass = params.StorageClass; - var ServerSideEncryption = params.ServerSideEncryption; - var FileSize; - - var onProgress; - var onHashProgress = params.onHashProgress; - - // 上传过程中出现错误,返回错误 - ep.on('error', function (err) { - if (!self._isRunningTask(TaskId)) return; - return callback(err); - }); - - // 上传分块完成,开始 uploadSliceComplete 操作 - ep.on('upload_complete', function (UploadCompleteData) { - callback(null, UploadCompleteData); - }); - - // 上传分块完成,开始 uploadSliceComplete 操作 - ep.on('upload_slice_complete', function (UploadData) { - uploadSliceComplete.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key, - UploadId: UploadData.UploadId, - SliceList: UploadData.SliceList, - }, function (err, data) { - if (!self._isRunningTask(TaskId)) return; - session.removeUsing(UploadData.UploadId); - if (err) { - onProgress(null, true); - return ep.emit('error', err); - } - session.removeUploadId(UploadData.UploadId); - onProgress({loaded: FileSize, total: FileSize}, true); - ep.emit('upload_complete', data); - }); - }); - - // 获取 UploadId 完成,开始上传每个分片 - ep.on('get_upload_data_finish', function (UploadData) { - - // 处理 UploadId 缓存 - var uuid = session.getFileId(params.FileStat, params.ChunkSize, Bucket, Key); - uuid && session.saveUploadId(uuid, UploadData.UploadId, self.options.UploadIdCacheLimit); // 缓存 UploadId - session.setUsing(UploadData.UploadId); // 标记 UploadId 为正在使用 - - // 获取 UploadId - onProgress(null, true); // 任务状态开始 uploading - uploadSliceList.call(self, { - TaskId: TaskId, - Bucket: Bucket, - Region: Region, - Key: Key, - FilePath: FilePath, - FileSize: FileSize, - SliceSize: ChunkSize, - AsyncLimit: AsyncLimit, - ServerSideEncryption: ServerSideEncryption, - UploadData: UploadData, - onProgress: onProgress - }, function (err, data) { - if (!self._isRunningTask(TaskId)) return; - if (err) { - onProgress(null, true); - return ep.emit('error', err); - } - ep.emit('upload_slice_complete', data); - }); - }); - - // 开始获取文件 UploadId,里面会视情况计算 ETag,并比对,保证文件一致性,也优化上传 - ep.on('get_file_size_finish', function () { - - onProgress = util.throttleOnProgress.call(self, FileSize, params.onProgress); - - if (params.UploadData.UploadId) { - ep.emit('get_upload_data_finish', params.UploadData); - } else { - var _params = util.extend({ - TaskId: TaskId, - Bucket: Bucket, - Region: Region, - Key: Key, - Headers: params.Headers, - StorageClass: StorageClass, - FilePath: FilePath, - FileSize: FileSize, - SliceSize: ChunkSize, - onHashProgress: onHashProgress, - }, params); - getUploadIdAndPartList.call(self, _params, function (err, UploadData) { - if (!self._isRunningTask(TaskId)) return; - if (err) return ep.emit('error', err); - params.UploadData.UploadId = UploadData.UploadId; - params.UploadData.PartList = UploadData.PartList; - ep.emit('get_upload_data_finish', params.UploadData); - }); - } - }); - - // 获取上传文件大小 - FileSize = params.ContentLength; - delete params.ContentLength; - !params.Headers && (params.Headers = {}); - util.each(params.Headers, function (item, key) { - if (key.toLowerCase() === 'content-length') { - delete params.Headers[key]; - } - }); - - // 控制分片大小 - (function () { - var SIZE = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 1024 * 2, 1024 * 4, 1024 * 5]; - var AutoChunkSize = 1024 * 1024; - for (var i = 0; i < SIZE.length; i++) { - AutoChunkSize = SIZE[i] * 1024 * 1024; - if (FileSize / AutoChunkSize <= self.options.MaxPartNumber) break; - } - params.ChunkSize = params.SliceSize = ChunkSize = Math.max(ChunkSize, AutoChunkSize); - })(); - - // 开始上传 - if (FileSize === 0) { - params.Body = ''; - params.ContentLength = 0; - params.SkipTask = true; - self.putObject(params, function (err, data) { - if (err) { - return callback(err); - } - callback(null, data); - }); - } else { - ep.emit('get_file_size_finish'); - } - -} - -// 获取上传任务的 UploadId -function getUploadIdAndPartList(params, callback) { - var TaskId = params.TaskId; - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var StorageClass = params.StorageClass; - var self = this; - - // 计算 ETag - var ETagMap = {}; - var FileSize = params.FileSize; - var SliceSize = params.SliceSize; - var SliceCount = Math.ceil(FileSize / SliceSize); - var FinishSliceCount = 0; - var FinishSize = 0; - var onHashProgress = util.throttleOnProgress.call(self, FileSize, params.onHashProgress); - var getChunkETag = function (PartNumber, callback) { - var start = SliceSize * (PartNumber - 1); - var end = Math.min(start + SliceSize, FileSize); - var ChunkSize = end - start; - - if (ETagMap[PartNumber]) { - callback(null, { - PartNumber: PartNumber, - ETag: ETagMap[PartNumber], - Size: ChunkSize - }); - } else { - util.fileSlice(params.FilePath, start, end, function (chunkItem) { - try { - var md5 = util.getFileMd5(chunkItem); - } catch (err) { - return callback(err); - } - var ETag = '"' + md5 + '"'; - ETagMap[PartNumber] = ETag; - FinishSliceCount += 1; - FinishSize += ChunkSize; - callback(null, { - PartNumber: PartNumber, - ETag: ETag, - Size: ChunkSize - }); - onHashProgress({loaded: FinishSize, total: FileSize}); - }); - } - }; - - // 通过和文件的 md5 对比,判断 UploadId 是否可用 - var isAvailableUploadList = function (PartList, callback) { - var PartCount = PartList.length; - // 如果没有分片,通过 - if (PartCount === 0) { - return callback(null, true); - } - // 检查分片数量 - if (PartCount > SliceCount) { - return callback(null, false); - } - // 检查分片大小 - if (PartCount > 1) { - var PartSliceSize = Math.max(PartList[0].Size, PartList[1].Size); - if (PartSliceSize !== SliceSize) { - return callback(null, false); - } - } - // 逐个分片计算并检查 ETag 是否一致 - var next = function (index) { - if (index < PartCount) { - var Part = PartList[index]; - getChunkETag(Part.PartNumber, function (err, chunk) { - if (chunk && chunk.ETag === Part.ETag && chunk.Size === Part.Size) { - next(index + 1); - } else { - callback(null, false); - } - }); - } else { - callback(null, true); - } - }; - next(0); - }; - - var ep = new EventProxy(); - ep.on('error', function (errData) { - if (!self._isRunningTask(TaskId)) return; - return callback(errData); - }); - - // 存在 UploadId - ep.on('upload_id_available', function (UploadData) { - // 转换成 map - var map = {}; - var list = []; - util.each(UploadData.PartList, function (item) { - map[item.PartNumber] = item; - }); - for (var PartNumber = 1; PartNumber <= SliceCount; PartNumber++) { - var item = map[PartNumber]; - if (item) { - item.PartNumber = PartNumber; - item.Uploaded = true; - } else { - item = { - PartNumber: PartNumber, - ETag: null, - Uploaded: false - }; - } - list.push(item); - } - UploadData.PartList = list; - callback(null, UploadData); - }); - - // 不存在 UploadId, 初始化生成 UploadId - ep.on('no_available_upload_id', function () { - if (!self._isRunningTask(TaskId)) return; - var _params = util.extend({ - Bucket: Bucket, - Region: Region, - Key: Key, - Headers: util.clone(params.Headers), - Query: util.clone(params.Query), - StorageClass: StorageClass, - }, params); - self.multipartInit(_params, function (err, data) { - if (!self._isRunningTask(TaskId)) return; - if (err) return ep.emit('error', err); - var UploadId = data.UploadId; - if (!UploadId) { - return callback({Message: 'no upload id'}); - } - ep.emit('upload_id_available', {UploadId: UploadId, PartList: []}); - }); - }); - - // 如果已存在 UploadId,找一个可以用的 UploadId - ep.on('has_and_check_upload_id', function (UploadIdList) { - // 串行地,找一个内容一致的 UploadId - UploadIdList = UploadIdList.reverse(); - Async.eachLimit(UploadIdList, 1, function (UploadId, asyncCallback) { - if (!self._isRunningTask(TaskId)) return; - // 如果正在上传,跳过 - if (session.using[UploadId]) { - asyncCallback(); // 检查下一个 UploadId - return; - } - // 判断 UploadId 是否可用 - wholeMultipartListPart.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key, - UploadId: UploadId, - }, function (err, PartListData) { - if (!self._isRunningTask(TaskId)) return; - if (err) { - session.removeUsing(UploadId); - return ep.emit('error', err); - } - var PartList = PartListData.PartList; - PartList.forEach(function (item) { - item.PartNumber *= 1; - item.Size *= 1; - item.ETag = item.ETag || ''; - }); - isAvailableUploadList(PartList, function (err, isAvailable) { - if (!self._isRunningTask(TaskId)) return; - if (err) return ep.emit('error', err); - if (isAvailable) { - asyncCallback({ - UploadId: UploadId, - PartList: PartList - }); // 马上结束 - } else { - asyncCallback(); // 检查下一个 UploadId - } - }); - }); - }, function (AvailableUploadData) { - if (!self._isRunningTask(TaskId)) return; - onHashProgress(null, true); - if (AvailableUploadData && AvailableUploadData.UploadId) { - ep.emit('upload_id_available', AvailableUploadData); - } else { - ep.emit('no_available_upload_id'); - } - }); - }); - - // 在本地缓存找可用的 UploadId - ep.on('seek_local_avail_upload_id', function (RemoteUploadIdList) { - // 在本地找可用的 UploadId - var uuid = session.getFileId(params.FileStat, params.ChunkSize, Bucket, Key); - var LocalUploadIdList = session.getUploadIdList(uuid); - if (!uuid || !LocalUploadIdList) { - ep.emit('has_and_check_upload_id', RemoteUploadIdList); - return; - } - var next = function (index) { - // 如果本地找不到可用 UploadId,再一个个遍历校验远端 - if (index >= LocalUploadIdList.length) { - ep.emit('has_and_check_upload_id', RemoteUploadIdList); - return; - } - var UploadId = LocalUploadIdList[index]; - // 如果不在远端 UploadId 列表里,跳过并删除 - if (!util.isInArray(RemoteUploadIdList, UploadId)) { - session.removeUploadId(UploadId); - next(index + 1); - return; - } - // 如果正在上传,跳过 - if (session.using[UploadId]) { - next(index + 1); - return; - } - // 判断 UploadId 是否存在线上 - wholeMultipartListPart.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key, - UploadId: UploadId, - }, function (err, PartListData) { - if (!self._isRunningTask(TaskId)) return; - if (err) { - // 如果 UploadId 获取会出错,跳过并删除 - session.removeUploadId(UploadId); - next(index + 1); - } else { - // 找到可用 UploadId - ep.emit('upload_id_available', { - UploadId: UploadId, - PartList: PartListData.PartList, - }); - } - }); - }; - next(0); - }); - - // 获取线上 UploadId 列表 - ep.on('get_remote_upload_id_list', function () { - // 获取符合条件的 UploadId 列表,因为同一个文件可以有多个上传任务。 - wholeMultipartList.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key, - }, function (err, data) { - if (!self._isRunningTask(TaskId)) return; - if (err) { - return ep.emit('error', err); - } - // 整理远端 UploadId 列表 - var RemoteUploadIdList = util.filter(data.UploadList, function (item) { - return item.Key === Key && (!StorageClass || item.StorageClass.toUpperCase() === StorageClass.toUpperCase()); - }).reverse().map(function (item) { - return item.UploadId || item.UploadID; - }); - if (RemoteUploadIdList.length) { - ep.emit('seek_local_avail_upload_id', RemoteUploadIdList); - } else { - // 远端没有 UploadId,清理缓存的 UploadId - var uuid = session.getFileId(params.FileStat, params.ChunkSize, Bucket, Key), LocalUploadIdList; - if (uuid && (LocalUploadIdList = session.getUploadIdList(uuid))) { - util.each(LocalUploadIdList, function (UploadId) { - session.removeUploadId(UploadId); - }); - } - ep.emit('no_available_upload_id'); - } - }); - }); - - // 开始找可用 UploadId - ep.emit('get_remote_upload_id_list'); - -} - -// 获取符合条件的全部上传任务 (条件包括 Bucket, Region, Prefix) -function wholeMultipartList(params, callback) { - var self = this; - var UploadList = []; - var sendParams = { - Bucket: params.Bucket, - Region: params.Region, - Prefix: params.Key - }; - var next = function () { - self.multipartList(sendParams, function (err, data) { - if (err) return callback(err); - UploadList.push.apply(UploadList, data.Upload || []); - if (data.IsTruncated === 'true') { // 列表不完整 - sendParams.KeyMarker = data.NextKeyMarker; - sendParams.UploadIdMarker = data.NextUploadIdMarker; - next(); - } else { - callback(null, {UploadList: UploadList}); - } - }); - }; - next(); -} - -// 获取指定上传任务的分块列表 -function wholeMultipartListPart(params, callback) { - var self = this; - var PartList = []; - var sendParams = { - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - UploadId: params.UploadId - }; - var next = function () { - self.multipartListPart(sendParams, function (err, data) { - if (err) return callback(err); - PartList.push.apply(PartList, data.Part || []); - if (data.IsTruncated === 'true') { // 列表不完整 - sendParams.PartNumberMarker = data.NextPartNumberMarker; - next(); - } else { - callback(null, {PartList: PartList}); - } - }); - }; - next(); -} - -// 上传文件分块,包括 -/* - UploadId (上传任务编号) - AsyncLimit (并发量), - SliceList (上传的分块数组), - FilePath (本地文件的位置), - SliceSize (文件分块大小) - FileSize (文件大小) - onProgress (上传成功之后的回调函数) - */ -function uploadSliceList(params, cb) { - var self = this; - var TaskId = params.TaskId; - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var UploadData = params.UploadData; - var FileSize = params.FileSize; - var SliceSize = params.SliceSize; - var ChunkParallel = Math.min(params.AsyncLimit || self.options.ChunkParallelLimit || 1, 256); - var FilePath = params.FilePath; - var SliceCount = Math.ceil(FileSize / SliceSize); - var FinishSize = 0; - var ServerSideEncryption = params.ServerSideEncryption; - var needUploadSlices = util.filter(UploadData.PartList, function (SliceItem) { - if (SliceItem['Uploaded']) { - FinishSize += SliceItem['PartNumber'] >= SliceCount ? (FileSize % SliceSize || SliceSize) : SliceSize; - } - return !SliceItem['Uploaded']; - }); - var onProgress = params.onProgress; - - Async.eachLimit(needUploadSlices, ChunkParallel, function (SliceItem, asyncCallback) { - if (!self._isRunningTask(TaskId)) return; - var PartNumber = SliceItem['PartNumber']; - var currentSize = Math.min(FileSize, SliceItem['PartNumber'] * SliceSize) - (SliceItem['PartNumber'] - 1) * SliceSize; - var preAddSize = 0; - uploadSliceItem.call(self, { - TaskId: TaskId, - Bucket: Bucket, - Region: Region, - Key: Key, - SliceSize: SliceSize, - FileSize: FileSize, - PartNumber: PartNumber, - ServerSideEncryption: ServerSideEncryption, - FilePath: FilePath, - UploadData: UploadData, - onProgress: function (data) { - FinishSize += data.loaded - preAddSize; - preAddSize = data.loaded; - onProgress({loaded: FinishSize, total: FileSize}); - }, - }, function (err, data) { - if (!self._isRunningTask(TaskId)) return; - if (err) { - FinishSize -= preAddSize; - } else { - FinishSize += currentSize - preAddSize; - SliceItem.ETag = data.ETag; - } - onProgress({loaded: FinishSize, total: FileSize}); - asyncCallback(err || null, data); - }); - }, function (err) { - if (!self._isRunningTask(TaskId)) return; - if (err) return cb(err); - cb(null, { - UploadId: UploadData.UploadId, - SliceList: UploadData.PartList - }); - }); -} - -// 上传指定分片 -function uploadSliceItem(params, callback) { - var self = this; - var TaskId = params.TaskId; - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var FileSize = params.FileSize; - var FilePath = params.FilePath; - var PartNumber = params.PartNumber * 1; - var SliceSize = params.SliceSize; - var ServerSideEncryption = params.ServerSideEncryption; - var UploadData = params.UploadData; - var ChunkRetryTimes = self.options.ChunkRetryTimes + 1; - - var start = SliceSize * (PartNumber - 1); - - var ContentLength = SliceSize; - - var end = start + SliceSize; - - if (end > FileSize) { - end = FileSize; - ContentLength = end - start; - } - - util.fileSlice(FilePath, start, end, function (Body) { - var md5 = util.getFileMd5(Body); - var contentMd5 = md5 ? util.binaryBase64(md5) : null; - var PartItem = UploadData.PartList[PartNumber - 1]; - Async.retry(ChunkRetryTimes, function (tryCallback) { - if (!self._isRunningTask(TaskId)) return; - self.multipartUpload({ - TaskId: TaskId, - Bucket: Bucket, - Region: Region, - Key: Key, - ContentLength: ContentLength, - PartNumber: PartNumber, - UploadId: UploadData.UploadId, - ServerSideEncryption: ServerSideEncryption, - Body: Body, - onProgress: params.onProgress, - ContentMD5: contentMd5, - }, function (err, data) { - if (!self._isRunningTask(TaskId)) return; - if (err) { - return tryCallback(err); - } else { - PartItem.Uploaded = true; - return tryCallback(null, data); - } - }); - }, function (err, data) { - if (!self._isRunningTask(TaskId)) return; - return callback(err, data); - }); - }); -} - - -// 完成分块上传 -function uploadSliceComplete(params, callback) { - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var UploadId = params.UploadId; - var SliceList = params.SliceList; - var self = this; - var ChunkRetryTimes = this.options.ChunkRetryTimes + 1; - var Parts = SliceList.map(function (item) { - return { - PartNumber: item.PartNumber, - ETag: item.ETag - }; - }); - // 完成上传的请求也做重试 - Async.retry(ChunkRetryTimes, function (tryCallback) { - self.multipartComplete({ - Bucket: Bucket, - Region: Region, - Key: Key, - UploadId: UploadId, - Parts: Parts - }, tryCallback); - }, function (err, data) { - callback(err, data); - }); -} - -// 抛弃分块上传任务 -/* - AsyncLimit (抛弃上传任务的并发量), - UploadId (上传任务的编号,当 Level 为 task 时候需要) - Level (抛弃分块上传任务的级别,task : 抛弃指定的上传任务,file : 抛弃指定的文件对应的上传任务,其他值 :抛弃指定Bucket 的全部上传任务) - */ -function abortUploadTask(params, callback) { - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var UploadId = params.UploadId; - var Level = params.Level || 'task'; - var AsyncLimit = params.AsyncLimit; - var self = this; - - var ep = new EventProxy(); - - ep.on('error', function (errData) { - return callback(errData); - }); - - // 已经获取到需要抛弃的任务列表 - ep.on('get_abort_array', function (AbortArray) { - abortUploadTaskArray.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key, - Headers: params.Headers, - AsyncLimit: AsyncLimit, - AbortArray: AbortArray - }, function (err, data) { - if (err) { - return callback(err); - } - callback(null, data); - }); - }); - - if (Level === 'bucket') { - // Bucket 级别的任务抛弃,抛弃该 Bucket 下的全部上传任务 - wholeMultipartList.call(self, { - Bucket: Bucket, - Region: Region - }, function (err, data) { - if (err) { - return callback(err); - } - ep.emit('get_abort_array', data.UploadList || []); - }); - } else if (Level === 'file') { - // 文件级别的任务抛弃,抛弃该文件的全部上传任务 - if (!Key) return callback({error: 'abort_upload_task_no_key'}); - wholeMultipartList.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key - }, function (err, data) { - if (err) { - return callback(err); - } - ep.emit('get_abort_array', data.UploadList || []); - }); - } else if (Level === 'task') { - // 单个任务级别的任务抛弃,抛弃指定 UploadId 的上传任务 - if (!UploadId) return callback({error: 'abort_upload_task_no_id'}); - if (!Key) return callback({error: 'abort_upload_task_no_key'}); - ep.emit('get_abort_array', [{ - Key: Key, - UploadId: UploadId - }]); - } else { - return callback({error: 'abort_unknown_level'}); - } -} - -// 批量抛弃分块上传任务 -function abortUploadTaskArray(params, callback) { - - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var AbortArray = params.AbortArray; - var AsyncLimit = params.AsyncLimit || 1; - var self = this; - - var index = 0; - var resultList = new Array(AbortArray.length); - Async.eachLimit(AbortArray, AsyncLimit, function (AbortItem, callback) { - var eachIndex = index; - if (Key && Key !== AbortItem.Key) { - resultList[eachIndex] = {error: {KeyNotMatch: true}}; - callback(null); - return; - } - var UploadId = AbortItem.UploadId || AbortItem.UploadID; - - self.multipartAbort({ - Bucket: Bucket, - Region: Region, - Key: AbortItem.Key, - Headers: params.Headers, - UploadId: UploadId - }, function (err) { - var task = { - Bucket: Bucket, - Region: Region, - Key: AbortItem.Key, - UploadId: UploadId - }; - resultList[eachIndex] = {error: err, task: task}; - callback(null); - }); - index++; - - }, function (err) { - if (err) { - return callback(err); - } - - var successList = []; - var errorList = []; - - for (var i = 0, len = resultList.length; i < len; i++) { - var item = resultList[i]; - if (item['task']) { - if (item['error']) { - errorList.push(item['task']); - } else { - successList.push(item['task']); - } - } - } - - return callback(null, { - successList: successList, - errorList: errorList - }); - }); -} - - -// 批量上传文件 -function uploadFiles(params, callback) { - var self = this; - - // 判断多大的文件使用分片上传 - var SliceSize = params.SliceSize === undefined ? self.options.SliceSize : params.SliceSize; - - // 汇总返回进度 - var TotalSize = 0; - var TotalFinish = 0; - var onTotalProgress = util.throttleOnProgress.call(self, TotalFinish, params.onProgress); - - // 汇总返回回调 - var unFinishCount = params.files.length; - var _onTotalFileFinish = params.onFileFinish; - var resultList = Array(unFinishCount); - var onTotalFileFinish = function (err, data, options) { - onTotalProgress(null, true); - _onTotalFileFinish && _onTotalFileFinish(err, data, options); - resultList[options.Index] = { - options: options, - error: err, - data: data - }; - if (--unFinishCount <= 0 && callback) { - callback(null, { - files: resultList, - }); - } - }; - - // 开始处理每个文件 - var taskList = []; - util.each(params.files, function (fileParams, index) { - var FileSize = fileParams.FileSize; - var fileInfo = {Index: index, TaskId: ''}; - - // 更新文件总大小 - TotalSize += FileSize; - - // 整理 option,用于返回给回调 - util.each(fileParams, function (v, k) { - if (typeof v !== 'object' && typeof v !== 'function') { - fileInfo[k] = v; - } - }); - - // 处理单个文件 TaskReady - var _onTaskReady = fileParams.onTaskReady; - fileParams.onTaskReady = function (tid) { - fileInfo.TaskId = tid; - _onTaskReady && _onTaskReady(tid); - }; - - // 处理单个文件进度 - var PreAddSize = 0; - var _onProgress = fileParams.onProgress; - fileParams.onProgress = function (info) { - TotalFinish = TotalFinish - PreAddSize + info.loaded; - PreAddSize = info.loaded; - _onProgress && _onProgress(info); - onTotalProgress({loaded: TotalFinish, total: TotalSize}); - }; - - // 处理单个文件完成 - var _onFileFinish = fileParams.onFileFinish; - var onFileFinish = function (err, data) { - _onFileFinish && _onFileFinish(err, data); - onTotalFileFinish && onTotalFileFinish(err, data, fileInfo); - }; - - // 添加上传任务 - var api = FileSize > SliceSize ? 'sliceUploadFile' : 'postObject'; - taskList.push({ - api: api, - params: fileParams, - callback: onFileFinish, - }); - }); - self._addTasks(taskList); -} - -// 分片复制文件 -function sliceCopyFile(params, callback) { - var ep = new EventProxy(); - - var self = this; - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var CopySource = params.CopySource; - var m = CopySource.match(/^([^.]+-\d+)\.cos(v6)?\.([^.]+)\.[^/]+\/(.+)$/); - if (!m) { - callback({error: 'CopySource format error'}); - return; - } - - var SourceBucket = m[1]; - var SourceRegion = m[3]; - var SourceKey = decodeURIComponent(m[4]); - var CopySliceSize = params.CopySliceSize === undefined ? self.options.CopySliceSize : params.CopySliceSize; - CopySliceSize = Math.max(0, CopySliceSize); - - var ChunkSize = params.CopyChunkSize || this.options.CopyChunkSize; - var ChunkParallel = this.options.CopyChunkParallelLimit; - - var FinishSize = 0; - var FileSize; - var onProgress; - - // 分片复制完成,开始 multipartComplete 操作 - ep.on('copy_slice_complete', function (UploadData) { - self.multipartComplete({ - Bucket: Bucket, - Region: Region, - Key: Key, - UploadId: UploadData.UploadId, - Parts: UploadData.PartList, - },function (err, data) { - if (err) { - onProgress(null, true); - return callback(err); - } - onProgress({loaded: FileSize, total: FileSize}, true); - callback(null, data); - }); - }); - - ep.on('get_copy_data_finish',function (UploadData) { - Async.eachLimit(UploadData.PartList, ChunkParallel, function (SliceItem, asyncCallback) { - var PartNumber = SliceItem.PartNumber; - var CopySourceRange = SliceItem.CopySourceRange; - var currentSize = SliceItem.end - SliceItem.start; - var preAddSize = 0; - - copySliceItem.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key, - CopySource: CopySource, - UploadId: UploadData.UploadId, - PartNumber: PartNumber, - CopySourceRange: CopySourceRange, - onProgress: function (data) { - FinishSize += data.loaded - preAddSize; - preAddSize = data.loaded; - onProgress({loaded: FinishSize, total: FileSize}); - } - },function (err,data) { - if (err) { - return asyncCallback(err); - } - onProgress({loaded: FinishSize, total: FileSize}); - - FinishSize += currentSize - preAddSize; - SliceItem.ETag = data.ETag; - asyncCallback(err || null, data); - }); - }, function (err) { - if (err) { - onProgress(null, true); - return callback(err); - } - - ep.emit('copy_slice_complete', UploadData); - }); - }); - - ep.on('get_file_size_finish', function (SourceHeaders) { - // 控制分片大小 - (function () { - var SIZE = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 1024 * 2, 1024 * 4, 1024 * 5]; - var AutoChunkSize = 1024 * 1024; - for (var i = 0; i < SIZE.length; i++) { - AutoChunkSize = SIZE[i] * 1024 * 1024; - if (FileSize / AutoChunkSize <= self.options.MaxPartNumber) break; - } - params.ChunkSize = ChunkSize = Math.max(ChunkSize, AutoChunkSize); - - var ChunkCount = Math.ceil(FileSize / ChunkSize); - - var list = []; - for (var partNumber = 1; partNumber <= ChunkCount; partNumber++) { - var start = (partNumber - 1) * ChunkSize; - var end = partNumber * ChunkSize < FileSize ? (partNumber * ChunkSize - 1) : FileSize - 1; - var item = { - PartNumber: partNumber, - start: start, - end: end, - CopySourceRange: "bytes=" + start + "-" + end, - }; - list.push(item); - } - params.PartList = list; - })(); - - var TargetHeader; - if (params.Headers['x-cos-metadata-directive'] === 'Replaced') { - TargetHeader = params.Headers; - } else { - TargetHeader = SourceHeaders; - } - TargetHeader['x-cos-storage-class'] = params.Headers['x-cos-storage-class'] || SourceHeaders['x-cos-storage-class']; - TargetHeader = util.clearKey(TargetHeader); - /** - * 对于归档存储的对象,如果未恢复副本,则不允许 Copy - */ - if (SourceHeaders['x-cos-storage-class'] === 'ARCHIVE' || SourceHeaders['x-cos-storage-class'] === 'DEEP_ARCHIVE') { - var restoreHeader = SourceHeaders['x-cos-restore']; - if (!restoreHeader || restoreHeader === 'ongoing-request="true"') { - callback({ error: 'Unrestored archive object is not allowed to be copied' }); - return; - } - } - /** - * 去除一些无用的头部,规避 multipartInit 出错 - * 这些头部通常是在 putObjectCopy 时才使用 - */ - delete TargetHeader['x-cos-copy-source']; - delete TargetHeader['x-cos-metadata-directive']; - delete TargetHeader['x-cos-copy-source-If-Modified-Since']; - delete TargetHeader['x-cos-copy-source-If-Unmodified-Since']; - delete TargetHeader['x-cos-copy-source-If-Match']; - delete TargetHeader['x-cos-copy-source-If-None-Match']; - self.multipartInit({ - Bucket: Bucket, - Region: Region, - Key: Key, - Headers: TargetHeader, - },function (err,data) { - if (err) { - return callback(err); - } - params.UploadId = data.UploadId; - ep.emit('get_copy_data_finish', params); - }); - }); - - // 获取远端复制源文件的大小 - self.headObject({ - Bucket: SourceBucket, - Region: SourceRegion, - Key: SourceKey, - },function(err, data) { - if (err) { - if (err.statusCode && err.statusCode === 404) { - callback({ErrorStatus: SourceKey + ' Not Exist'}); - } else { - callback(err); - } - return; - } - - FileSize = params.FileSize = data.headers['content-length']; - if (FileSize === undefined || !FileSize) { - callback({error: 'get Content-Length error, please add "Content-Length" to CORS ExposeHeader setting.'}); - return; - } - - onProgress = util.throttleOnProgress.call(self, FileSize, params.onProgress); - - // 开始上传 - if (FileSize <= CopySliceSize) { - if (!params.Headers['x-cos-metadata-directive']) { - params.Headers['x-cos-metadata-directive'] = 'Copy'; - } - self.putObjectCopy(params, function (err, data) { - if (err) { - onProgress(null, true); - return callback(err); - } - onProgress({loaded: FileSize, total: FileSize}, true); - callback(err, data); - }); - } else { - var resHeaders = data.headers; - var SourceHeaders = { - 'Cache-Control': resHeaders['cache-control'], - 'Content-Disposition': resHeaders['content-disposition'], - 'Content-Encoding': resHeaders['content-encoding'], - 'Content-Type': resHeaders['content-type'], - 'Expires': resHeaders['expires'], - 'x-cos-storage-class': resHeaders['x-cos-storage-class'], - }; - util.each(resHeaders, function (v, k) { - var metaPrefix = 'x-cos-meta-'; - if (k.indexOf(metaPrefix) === 0 && k.length > metaPrefix.length) { - SourceHeaders[k] = v; - } - }); - ep.emit('get_file_size_finish', SourceHeaders); - } - }); -} - -// 复制指定分片 -function copySliceItem(params, callback) { - var TaskId = params.TaskId; - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var CopySource = params.CopySource; - var UploadId = params.UploadId; - var PartNumber = params.PartNumber * 1; - var CopySourceRange = params.CopySourceRange; - - var ChunkRetryTimes = this.options.ChunkRetryTimes + 1; - var self = this; - - Async.retry(ChunkRetryTimes, function (tryCallback) { - self.uploadPartCopy({ - TaskId: TaskId, - Bucket: Bucket, - Region: Region, - Key: Key, - CopySource: CopySource, - UploadId: UploadId, - PartNumber:PartNumber, - CopySourceRange:CopySourceRange, - onProgress:params.onProgress, - },function (err,data) { - tryCallback(err || null, data); - }) - }, function (err, data) { - return callback(err, data); - }); -} - - -var API_MAP = { - sliceUploadFile: sliceUploadFile, - abortUploadTask: abortUploadTask, - uploadFiles: uploadFiles, - sliceCopyFile: sliceCopyFile, -}; - -module.exports.init = function (COS, task) { - task.transferToTaskMethod(API_MAP, 'sliceUploadFile'); - util.each(API_MAP, function (fn, apiName) { - COS.prototype[apiName] = util.apiWrapper(apiName, fn); - }); -}; + while (running < limit && started < arr.length) { + started += 1; + running += 1; + iterator(arr[started - 1], function (err) { + + if (err) { + callback(err); + callback = function () {}; + } else { + completed += 1; + running -= 1; + if (completed >= arr.length) { + callback(); + } else { + replenish(); + } + } + }); + } + })(); +}; +var retry = function (times, iterator, callback) { + var next = function (index) { + iterator(function (err, data) { + if (err && index < times) { + next(index + 1); + } else { + callback(err, data); + } + }); + }; + if (times < 1) { + callback(); + } else { + next(1); + } +}; -/***/ }), -/* 24 */ -/***/ (function(module, exports) { +var async = { + eachLimit: eachLimit, + retry: retry +}; -var eachLimit = function (arr, limit, iterator, callback) { - callback = callback || function () {}; - if (!arr.length || limit <= 0) { - return callback(); - } - - var completed = 0; - var started = 0; - var running = 0; - - (function replenish () { - if (completed >= arr.length) { - return callback(); - } - - while (running < limit && started < arr.length) { - started += 1; - running += 1; - iterator(arr[started - 1], function (err) { - - if (err) { - callback(err); - callback = function () {}; - } else { - completed += 1; - running -= 1; - if (completed >= arr.length) { - callback(); - } else { - replenish(); - } - } - }); - } - })(); -}; - -var retry = function (times, iterator, callback) { - var next = function (index) { - iterator(function (err, data) { - if (err && index < times) { - next(index + 1); - } else { - callback(err, data); - } - }); - }; - if (times < 1) { - callback(); - } else { - next(1); - } -}; - -var async = { - eachLimit: eachLimit, - retry: retry -}; - module.exports = async; /***/ }) diff --git a/demo/demo-sdk.js b/demo/demo-sdk.js index 3eeb6a7..134ec00 100644 --- a/demo/demo-sdk.js +++ b/demo/demo-sdk.js @@ -151,6 +151,67 @@ var dao = { console.log(err || data) }); }, + 'uploadFile 高级上传': function() { + var uploadFile = function(file) { + cos.uploadFile({ + Bucket: config.Bucket, + Region: config.Region, + Key: file.name, + FilePath: file.path, + SliceSize: 1024 * 1024 * 5, // 文件大于5mb自动使用分块上传 + onProgress: function (info) { + var percent = parseInt(info.percent * 10000) / 100; + var speed = parseInt(info.speed / 1024 / 1024 * 100) / 100; + console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;'); + }, + onFileFinish: function (err, data, options) { + console.log(options.Key + '上传' + (err ? '失败' : '完成')); + }, + }, function (err, data) { + console.log(err || data); + }); + } + wx.chooseMessageFile({ + count: 10, + type: 'all', + success: function(res) { + uploadFile(res.tempFiles[0]); + } + }); + }, + 'uploadFiles 批量上传': function() { + var uploadFiles = function(files) { + const fileList = files.map(function(file) { + return Object.assign(file, { + Bucket: config.Bucket, + Region: config.Region, + Key: file.name, + FilePath: file.path, + }); + }); + cos.uploadFiles({ + files: fileList, + SliceSize: 1024 * 1024 * 5, // 文件大于5mb自动使用分块上传 + onProgress: function (info) { + var percent = parseInt(info.percent * 10000) / 100; + var speed = parseInt(info.speed / 1024 / 1024 * 100) / 100; + console.log('进度:' + percent + '%; 速度:' + speed + 'Mb/s;'); + }, + onFileFinish: function (err, data, options) { + console.log(options.Key + '上传' + (err ? '失败' : '完成')); + }, + }, function (err, data) { + console.log(err || data); + }); + } + wx.chooseMessageFile({ + count: 10, + type: 'all', + success: function(res) { + uploadFiles(res.tempFiles); + } + }); + }, '分片上传': function() { var sliceUploadFile = function (file) { var key = file.name; diff --git a/demo/lib/cos-wx-sdk-v5.js b/demo/lib/cos-wx-sdk-v5.js index 0de1a00..c7ba392 100644 --- a/demo/lib/cos-wx-sdk-v5.js +++ b/demo/lib/cos-wx-sdk-v5.js @@ -67,7 +67,7 @@ return /******/ (function(modules) { // webpackBootstrap /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ -/******/ __webpack_require__.p = "D:\\code\\cos-wx-sdk-v5\\demo\\lib"; +/******/ __webpack_require__.p = "/Users/tianfeng/Documents/项目/sdk/cos-wx-sdk-v5/demo/lib"; /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = 6); @@ -78,590 +78,590 @@ return /******/ (function(modules) { // webpackBootstrap /***/ (function(module, exports, __webpack_require__) { "use strict"; -/* WEBPACK VAR INJECTION */(function(global) { - -var md5 = __webpack_require__(8); -var CryptoJS = __webpack_require__(11); -var xml2json = __webpack_require__(12); -var json2xml = __webpack_require__(15); -var base64 = __webpack_require__(3); -var btoa = base64.btoa; -var wxfs = wx.getFileSystemManager(); - -function camSafeUrlEncode(str) { - return encodeURIComponent(str) - .replace(/!/g, '%21') - .replace(/'/g, '%27') - .replace(/\(/g, '%28') - .replace(/\)/g, '%29') - .replace(/\*/g, '%2A'); -} - -//测试用的key后面可以去掉 -var getAuth = function (opt) { - opt = opt || {}; - - var SecretId = opt.SecretId; - var SecretKey = opt.SecretKey; - var KeyTime = opt.KeyTime; - var method = (opt.method || opt.Method || 'get').toLowerCase(); - var queryParams = clone(opt.Query || opt.params || {}); - var headers = clone(opt.Headers || opt.headers || {}); - - var Key = opt.Key || ''; - var pathname; - if (opt.UseRawKey) { - pathname = opt.Pathname || opt.pathname || '/' + Key; - } else { - pathname = opt.Pathname || opt.pathname || Key; - pathname.indexOf('/') !== 0 && (pathname = '/' + pathname); - } - - if (!SecretId) return console.error('missing param SecretId'); - if (!SecretKey) return console.error('missing param SecretKey'); - - var getObjectKeys = function (obj, forKey) { - var list = []; - for (var key in obj) { - if (obj.hasOwnProperty(key)) { - list.push(forKey ? camSafeUrlEncode(key).toLowerCase() : key); - } - } - return list.sort(function (a, b) { - a = a.toLowerCase(); - b = b.toLowerCase(); - return a === b ? 0 : (a > b ? 1 : -1); - }); - }; - - var obj2str = function (obj) { - var i, key, val; - var list = []; - var keyList = getObjectKeys(obj); - for (i = 0; i < keyList.length; i++) { - key = keyList[i]; - val = (obj[key] === undefined || obj[key] === null) ? '' : ('' + obj[key]); - key = camSafeUrlEncode(key).toLowerCase(); - val = camSafeUrlEncode(val) || ''; - list.push(key + '=' + val) - } - return list.join('&'); - }; - - // 签名有效起止时间 - var now = Math.round(getSkewTime(opt.SystemClockOffset) / 1000) - 1; - var exp = now; - - var Expires = opt.Expires || opt.expires; - if (Expires === undefined) { - exp += 900; // 签名过期时间为当前 + 900s - } else { - exp += (Expires * 1) || 0; - } - - // 要用到的 Authorization 参数列表 - var qSignAlgorithm = 'sha1'; - var qAk = SecretId; - var qSignTime = KeyTime || now + ';' + exp; - var qKeyTime = KeyTime || now + ';' + exp; - var qHeaderList = getObjectKeys(headers, true).join(';').toLowerCase(); - var qUrlParamList = getObjectKeys(queryParams, true).join(';').toLowerCase(); - - // 签名算法说明文档:https://www.qcloud.com/document/product/436/7778 - // 步骤一:计算 SignKey - var signKey = CryptoJS.HmacSHA1(qKeyTime, SecretKey).toString(); - - // 步骤二:构成 FormatString - var formatString = [method, pathname, obj2str(queryParams), obj2str(headers), ''].join('\n'); - - // 步骤三:计算 StringToSign - var stringToSign = ['sha1', qSignTime, CryptoJS.SHA1(formatString).toString(), ''].join('\n'); - - // 步骤四:计算 Signature - var qSignature = CryptoJS.HmacSHA1(stringToSign, signKey).toString(); - - // 步骤五:构造 Authorization - var authorization = [ - 'q-sign-algorithm=' + qSignAlgorithm, - 'q-ak=' + qAk, - 'q-sign-time=' + qSignTime, - 'q-key-time=' + qKeyTime, - 'q-header-list=' + qHeaderList, - 'q-url-param-list=' + qUrlParamList, - 'q-signature=' + qSignature - ].join('&'); - - return authorization; - -}; - -var noop = function () { - -}; - -// 清除对象里值为的 undefined 或 null 的属性 -var clearKey = function (obj) { - var retObj = {}; - for (var key in obj) { - if (obj.hasOwnProperty(key) && obj[key] !== undefined && obj[key] !== null) { - retObj[key] = obj[key]; - } - } - return retObj; -}; - -// 获取文件分片 -var fileSlice = function (FilePath, start, end, callback) { - if (FilePath) { - wxfs.readFile({ - filePath: FilePath, - position: start, - length: end - start, - success: function (res) { - callback(res.data); - }, - fail: function () { - callback(null); - }, - }); - } else { - callback(null); - } -}; - -// 获取文件内容的 MD5 -var getBodyMd5 = function (UploadCheckContentMd5, Body, callback) { - callback = callback || noop; - if (UploadCheckContentMd5) { - if (Body && Body instanceof ArrayBuffer) { - util.getFileMd5(Body, function (err, md5) { - callback(md5); - }); - } else { - callback(); - } - } else { - callback(); - } -}; - -// 获取文件 md5 值 -var getFileMd5 = function (body, callback) { - var hash = md5(body); - callback && callback(hash); - return hash; -}; - -function clone(obj) { - return map(obj, function (v) { - return typeof v === 'object' ? clone(v) : v; - }); -} - -function attr(obj, name, defaultValue) { - return obj && name in obj ? obj[name] : defaultValue; -} - -function extend(target, source) { - each(source, function (val, key) { - target[key] = source[key]; - }); - return target; -} - -function isArray(arr) { - return arr instanceof Array; -} - -function isInArray(arr, item) { - var flag = false; - for (var i = 0; i < arr.length; i++) { - if (item === arr[i]) { - flag = true; - break; - } - } - return flag; -} - -function makeArray(arr) { - return isArray(arr) ? arr : [arr]; -} - -function each(obj, fn) { - for (var i in obj) { - if (obj.hasOwnProperty(i)) { - fn(obj[i], i); - } - } -} - -function map(obj, fn) { - var o = isArray(obj) ? [] : {}; - for (var i in obj) { - if (obj.hasOwnProperty(i)) { - o[i] = fn(obj[i], i); - } - } - return o; -} - -function filter(obj, fn) { - var iaArr = isArray(obj); - var o = iaArr ? [] : {}; - for (var i in obj) { - if (obj.hasOwnProperty(i)) { - if (fn(obj[i], i)) { - if (iaArr) { - o.push(obj[i]); - } else { - o[i] = obj[i]; - } - } - } - } - return o; -} - -var binaryBase64 = function (str) { - var i, len, char, res = ''; - for (i = 0, len = str.length / 2; i < len; i++) { - char = parseInt(str[i * 2] + str[i * 2 + 1], 16); - res += String.fromCharCode(char); - } - return btoa(res); -}; -var uuid = function () { - var S4 = function () { - return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); - }; - return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4()); -}; - -var hasMissingParams = function (apiName, params) { - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - if (apiName.indexOf('Bucket') > -1 || apiName === 'deleteMultipleObject' || apiName === 'multipartList' || apiName === 'listObjectVersions') { - if (!Bucket) return 'Bucket'; - if (!Region) return 'Region'; - } else if (apiName.indexOf('Object') > -1 || apiName.indexOf('multipart') > -1 || apiName === 'sliceUploadFile' || apiName === 'abortUploadTask') { - if (!Bucket) return 'Bucket'; - if (!Region) return 'Region'; - if (!Key) return 'Key'; - } - return false; -}; - -var formatParams = function (apiName, params) { - - // 复制参数对象 - params = extend({}, params); - - // 统一处理 Headers - if (apiName !== 'getAuth' && apiName !== 'getV4Auth' && apiName !== 'getObjectUrl') { - var Headers = params.Headers || {}; - if (params && typeof params === 'object') { - (function () { - for (var key in params) { - if (params.hasOwnProperty(key) && key.indexOf('x-cos-') > -1) { - Headers[key] = params[key]; - } - } - })(); - - var headerMap = { - // params headers - 'x-cos-mfa': 'MFA', - 'Content-MD5': 'ContentMD5', - 'Content-Length': 'ContentLength', - 'Content-Type': 'ContentType', - 'Expect': 'Expect', - 'Expires': 'Expires', - 'Cache-Control': 'CacheControl', - 'Content-Disposition': 'ContentDisposition', - 'Content-Encoding': 'ContentEncoding', - 'Range': 'Range', - 'If-Modified-Since': 'IfModifiedSince', - 'If-Unmodified-Since': 'IfUnmodifiedSince', - 'If-Match': 'IfMatch', - 'If-None-Match': 'IfNoneMatch', - 'x-cos-copy-source': 'CopySource', - 'x-cos-copy-source-Range': 'CopySourceRange', - 'x-cos-metadata-directive': 'MetadataDirective', - 'x-cos-copy-source-If-Modified-Since': 'CopySourceIfModifiedSince', - 'x-cos-copy-source-If-Unmodified-Since': 'CopySourceIfUnmodifiedSince', - 'x-cos-copy-source-If-Match': 'CopySourceIfMatch', - 'x-cos-copy-source-If-None-Match': 'CopySourceIfNoneMatch', - 'x-cos-acl': 'ACL', - 'x-cos-grant-read': 'GrantRead', - 'x-cos-grant-write': 'GrantWrite', - 'x-cos-grant-full-control': 'GrantFullControl', - 'x-cos-grant-read-acp': 'GrantReadAcp', - 'x-cos-grant-write-acp': 'GrantWriteAcp', - 'x-cos-storage-class': 'StorageClass', - // SSE-C - 'x-cos-server-side-encryption-customer-algorithm': 'SSECustomerAlgorithm', - 'x-cos-server-side-encryption-customer-key': 'SSECustomerKey', - 'x-cos-server-side-encryption-customer-key-MD5': 'SSECustomerKeyMD5', - // SSE-COS、SSE-KMS - 'x-cos-server-side-encryption': 'ServerSideEncryption', - 'x-cos-server-side-encryption-cos-kms-key-id': 'SSEKMSKeyId', - 'x-cos-server-side-encryption-context': 'SSEContext', - }; - util.each(headerMap, function (paramKey, headerKey) { - if (params[paramKey] !== undefined) { - Headers[headerKey] = params[paramKey]; - } - }); - - params.Headers = clearKey(Headers); - } - } - - return params; -}; - -var apiWrapper = function (apiName, apiFn) { - return function (params, callback) { - - var self = this; - - // 处理参数 - if (typeof params === 'function') { - callback = params; - params = {}; - } - - // 整理参数格式 - params = formatParams(apiName, params); - - // 代理回调函数 - var formatResult = function (result) { - if (result && result.headers) { - result.headers['x-cos-version-id'] && (result.VersionId = result.headers['x-cos-version-id']); - result.headers['x-cos-delete-marker'] && (result.DeleteMarker = result.headers['x-cos-delete-marker']); - } - return result; - }; - var _callback = function (err, data) { - callback && callback(formatResult(err), formatResult(data)); - }; - - var checkParams = function () { - if (apiName !== 'getService' && apiName !== 'abortUploadTask') { - // 判断参数是否完整 - var missingResult = hasMissingParams(apiName, params) - if (missingResult) { - return 'missing param ' + missingResult; - } - // 判断 region 格式 - if (params.Region) { - if (params.Region.indexOf('cos.') > -1) { - return 'param Region should not be start with "cos."'; - } else if (!/^([a-z\d-]+)$/.test(params.Region)) { - return 'Region format error.'; - } - // 判断 region 格式 - if (!self.options.CompatibilityMode - && params.Region.indexOf('-') === -1 - && params.Region !== 'yfb' - && params.Region !== 'default' - && params.Region !== 'accelerate') { - console.warn('warning: param Region format error, find help here: https://cloud.tencent.com/document/product/436/6224'); - } - } - // 兼容不带 AppId 的 Bucket - if (params.Bucket) { - if (!/^([a-z\d-]+)-(\d+)$/.test(params.Bucket)) { - if (params.AppId) { - params.Bucket = params.Bucket + '-' + params.AppId; - } else if (self.options.AppId) { - params.Bucket = params.Bucket + '-' + self.options.AppId; - } else { - return 'Bucket should format as "test-1250000000".'; - } - } - if (params.AppId) { - console.warn('warning: AppId has been deprecated, Please put it at the end of parameter Bucket(E.g Bucket:"test-1250000000" ).'); - delete params.AppId; - } - } - // 如果 Key 是 / 开头,强制去掉第一个 / - if (params.Key && params.Key.substr(0, 1) === '/') { - params.Key = params.Key.substr(1); - } - } - }; - - var errMsg = checkParams(); - var isSync = apiName === 'getAuth' || apiName === 'getObjectUrl'; - var Promise = global.Promise; - if (!isSync && Promise && !callback) { - return new Promise(function (resolve, reject) { - callback = function (err, data) { - err ? reject(err) : resolve(data); - }; - if (errMsg) return _callback({error: errMsg}); - apiFn.call(self, params, _callback); - }); - } else { - if (errMsg) return _callback({error: errMsg}); - var res = apiFn.call(self, params, _callback); - if (isSync) return res; - } - } -}; - -var throttleOnProgress = function (total, onProgress) { - var self = this; - var size0 = 0; - var size1 = 0; - var time0 = Date.now(); - var time1; - var timer; - - function update() { - timer = 0; - if (onProgress && (typeof onProgress === 'function')) { - time1 = Date.now(); - var speed = Math.max(0, Math.round((size1 - size0) / ((time1 - time0) / 1000) * 100) / 100) || 0; - var percent; - if (size1 === 0 && total === 0) { - percent = 1; - } else { - percent = Math.floor(size1 / total * 100) / 100 || 0; - } - time0 = time1; - size0 = size1; - try { - onProgress({loaded: size1, total: total, speed: speed, percent: percent}); - } catch (e) { - } - } - } - - return function (info, immediately) { - if (info) { - size1 = info.loaded; - total = info.total; - } - if (immediately) { - clearTimeout(timer); - update(); - } else { - if (timer) return; - timer = setTimeout(update, self.options.ProgressInterval); - } - }; -}; - -var getFileSize = function (api, params, callback) { - if (api === 'postObject') { - callback(); - } else if (api === 'putObject') { - if (params.Body !== undefined) { - params.ContentLength = params.Body.byteLength; - callback(null, params.ContentLength); - } else { - callback({error: 'missing param Body'}); - } - } else { - if (params.FilePath) { - wxfs.stat({ - path: params.FilePath, - success: function (res) { - var stats = res.stats; - params.FileStat = stats; - params.FileStat.FilePath = params.FilePath; - var size = stats.isDirectory() ? 0 : stats.size; - params.ContentLength = size = size || 0; - callback(null, size); - }, - fail: function (err) { - callback(err); - }, - }); - } else { - callback({error: 'missing param FilePath'}); - } - } -}; - -var getSkewTime = function (offset) { - return Date.now() + (offset || 0); -}; - -var compareVersion = function (v1, v2) { - v1 = v1.split('.') - v2 = v2.split('.') - var len = Math.max(v1.length, v2.length) - - while (v1.length < len) { - v1.push('0') - } - while (v2.length < len) { - v2.push('0') - } - - for (var i = 0; i < len; i++) { - var num1 = parseInt(v1[i]) - var num2 = parseInt(v2[i]) - - if (num1 > num2) { - return 1 - } else if (num1 < num2) { - return -1 - } - } - - return 0 -}; - -var canFileSlice = (function () { - var systemInfo = wx.getSystemInfoSync(); - var support = compareVersion(systemInfo.SDKVersion, '2.10.0') >= 0; - var needWarning = !support && systemInfo.platform === "devtools"; - return function () { - if (needWarning) console.warn('当前小程序版本小于 2.10.0,不支持分片上传,请更新软件。'); - needWarning = false; - return support; - }; -})(); - -var util = { - noop: noop, - formatParams: formatParams, - apiWrapper: apiWrapper, - xml2json: xml2json, - json2xml: json2xml, - md5: md5, - clearKey: clearKey, - fileSlice: fileSlice, - getBodyMd5: getBodyMd5, - getFileMd5: getFileMd5, - binaryBase64: binaryBase64, - extend: extend, - isArray: isArray, - isInArray: isInArray, - makeArray: makeArray, - each: each, - map: map, - filter: filter, - clone: clone, - attr: attr, - uuid: uuid, - camSafeUrlEncode: camSafeUrlEncode, - throttleOnProgress: throttleOnProgress, - getFileSize: getFileSize, - getSkewTime: getSkewTime, - getAuth: getAuth, - compareVersion: compareVersion, - canFileSlice: canFileSlice, -}; - -module.exports = util; -xml2json +/* WEBPACK VAR INJECTION */(function(global) { + +var md5 = __webpack_require__(8); +var CryptoJS = __webpack_require__(11); +var xml2json = __webpack_require__(12); +var json2xml = __webpack_require__(15); +var base64 = __webpack_require__(3); +var btoa = base64.btoa; +var wxfs = wx.getFileSystemManager(); + +function camSafeUrlEncode(str) { + return encodeURIComponent(str) + .replace(/!/g, '%21') + .replace(/'/g, '%27') + .replace(/\(/g, '%28') + .replace(/\)/g, '%29') + .replace(/\*/g, '%2A'); +} + +//测试用的key后面可以去掉 +var getAuth = function (opt) { + opt = opt || {}; + + var SecretId = opt.SecretId; + var SecretKey = opt.SecretKey; + var KeyTime = opt.KeyTime; + var method = (opt.method || opt.Method || 'get').toLowerCase(); + var queryParams = clone(opt.Query || opt.params || {}); + var headers = clone(opt.Headers || opt.headers || {}); + + var Key = opt.Key || ''; + var pathname; + if (opt.UseRawKey) { + pathname = opt.Pathname || opt.pathname || '/' + Key; + } else { + pathname = opt.Pathname || opt.pathname || Key; + pathname.indexOf('/') !== 0 && (pathname = '/' + pathname); + } + + if (!SecretId) return console.error('missing param SecretId'); + if (!SecretKey) return console.error('missing param SecretKey'); + + var getObjectKeys = function (obj, forKey) { + var list = []; + for (var key in obj) { + if (obj.hasOwnProperty(key)) { + list.push(forKey ? camSafeUrlEncode(key).toLowerCase() : key); + } + } + return list.sort(function (a, b) { + a = a.toLowerCase(); + b = b.toLowerCase(); + return a === b ? 0 : (a > b ? 1 : -1); + }); + }; + + var obj2str = function (obj) { + var i, key, val; + var list = []; + var keyList = getObjectKeys(obj); + for (i = 0; i < keyList.length; i++) { + key = keyList[i]; + val = (obj[key] === undefined || obj[key] === null) ? '' : ('' + obj[key]); + key = camSafeUrlEncode(key).toLowerCase(); + val = camSafeUrlEncode(val) || ''; + list.push(key + '=' + val) + } + return list.join('&'); + }; + + // 签名有效起止时间 + var now = Math.round(getSkewTime(opt.SystemClockOffset) / 1000) - 1; + var exp = now; + + var Expires = opt.Expires || opt.expires; + if (Expires === undefined) { + exp += 900; // 签名过期时间为当前 + 900s + } else { + exp += (Expires * 1) || 0; + } + + // 要用到的 Authorization 参数列表 + var qSignAlgorithm = 'sha1'; + var qAk = SecretId; + var qSignTime = KeyTime || now + ';' + exp; + var qKeyTime = KeyTime || now + ';' + exp; + var qHeaderList = getObjectKeys(headers, true).join(';').toLowerCase(); + var qUrlParamList = getObjectKeys(queryParams, true).join(';').toLowerCase(); + + // 签名算法说明文档:https://www.qcloud.com/document/product/436/7778 + // 步骤一:计算 SignKey + var signKey = CryptoJS.HmacSHA1(qKeyTime, SecretKey).toString(); + + // 步骤二:构成 FormatString + var formatString = [method, pathname, obj2str(queryParams), obj2str(headers), ''].join('\n'); + + // 步骤三:计算 StringToSign + var stringToSign = ['sha1', qSignTime, CryptoJS.SHA1(formatString).toString(), ''].join('\n'); + + // 步骤四:计算 Signature + var qSignature = CryptoJS.HmacSHA1(stringToSign, signKey).toString(); + + // 步骤五:构造 Authorization + var authorization = [ + 'q-sign-algorithm=' + qSignAlgorithm, + 'q-ak=' + qAk, + 'q-sign-time=' + qSignTime, + 'q-key-time=' + qKeyTime, + 'q-header-list=' + qHeaderList, + 'q-url-param-list=' + qUrlParamList, + 'q-signature=' + qSignature + ].join('&'); + + return authorization; + +}; + +var noop = function () { + +}; + +// 清除对象里值为的 undefined 或 null 的属性 +var clearKey = function (obj) { + var retObj = {}; + for (var key in obj) { + if (obj.hasOwnProperty(key) && obj[key] !== undefined && obj[key] !== null) { + retObj[key] = obj[key]; + } + } + return retObj; +}; + +// 获取文件分片 +var fileSlice = function (FilePath, start, end, callback) { + if (FilePath) { + wxfs.readFile({ + filePath: FilePath, + position: start, + length: end - start, + success: function (res) { + callback(res.data); + }, + fail: function () { + callback(null); + }, + }); + } else { + callback(null); + } +}; + +// 获取文件内容的 MD5 +var getBodyMd5 = function (UploadCheckContentMd5, Body, callback) { + callback = callback || noop; + if (UploadCheckContentMd5) { + if (Body && Body instanceof ArrayBuffer) { + util.getFileMd5(Body, function (err, md5) { + callback(md5); + }); + } else { + callback(); + } + } else { + callback(); + } +}; + +// 获取文件 md5 值 +var getFileMd5 = function (body, callback) { + var hash = md5(body); + callback && callback(hash); + return hash; +}; + +function clone(obj) { + return map(obj, function (v) { + return typeof v === 'object' ? clone(v) : v; + }); +} + +function attr(obj, name, defaultValue) { + return obj && name in obj ? obj[name] : defaultValue; +} + +function extend(target, source) { + each(source, function (val, key) { + target[key] = source[key]; + }); + return target; +} + +function isArray(arr) { + return arr instanceof Array; +} + +function isInArray(arr, item) { + var flag = false; + for (var i = 0; i < arr.length; i++) { + if (item === arr[i]) { + flag = true; + break; + } + } + return flag; +} + +function makeArray(arr) { + return isArray(arr) ? arr : [arr]; +} + +function each(obj, fn) { + for (var i in obj) { + if (obj.hasOwnProperty(i)) { + fn(obj[i], i); + } + } +} + +function map(obj, fn) { + var o = isArray(obj) ? [] : {}; + for (var i in obj) { + if (obj.hasOwnProperty(i)) { + o[i] = fn(obj[i], i); + } + } + return o; +} + +function filter(obj, fn) { + var iaArr = isArray(obj); + var o = iaArr ? [] : {}; + for (var i in obj) { + if (obj.hasOwnProperty(i)) { + if (fn(obj[i], i)) { + if (iaArr) { + o.push(obj[i]); + } else { + o[i] = obj[i]; + } + } + } + } + return o; +} + +var binaryBase64 = function (str) { + var i, len, char, res = ''; + for (i = 0, len = str.length / 2; i < len; i++) { + char = parseInt(str[i * 2] + str[i * 2 + 1], 16); + res += String.fromCharCode(char); + } + return btoa(res); +}; +var uuid = function () { + var S4 = function () { + return (((1 + Math.random()) * 0x10000) | 0).toString(16).substring(1); + }; + return (S4() + S4() + "-" + S4() + "-" + S4() + "-" + S4() + "-" + S4() + S4() + S4()); +}; + +var hasMissingParams = function (apiName, params) { + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + if (apiName.indexOf('Bucket') > -1 || apiName === 'deleteMultipleObject' || apiName === 'multipartList' || apiName === 'listObjectVersions') { + if (!Bucket) return 'Bucket'; + if (!Region) return 'Region'; + } else if (apiName.indexOf('Object') > -1 || apiName.indexOf('multipart') > -1 || apiName === 'sliceUploadFile' || apiName === 'abortUploadTask') { + if (!Bucket) return 'Bucket'; + if (!Region) return 'Region'; + if (!Key) return 'Key'; + } + return false; +}; + +var formatParams = function (apiName, params) { + + // 复制参数对象 + params = extend({}, params); + + // 统一处理 Headers + if (apiName !== 'getAuth' && apiName !== 'getV4Auth' && apiName !== 'getObjectUrl') { + var Headers = params.Headers || {}; + if (params && typeof params === 'object') { + (function () { + for (var key in params) { + if (params.hasOwnProperty(key) && key.indexOf('x-cos-') > -1) { + Headers[key] = params[key]; + } + } + })(); + + var headerMap = { + // params headers + 'x-cos-mfa': 'MFA', + 'Content-MD5': 'ContentMD5', + 'Content-Length': 'ContentLength', + 'Content-Type': 'ContentType', + 'Expect': 'Expect', + 'Expires': 'Expires', + 'Cache-Control': 'CacheControl', + 'Content-Disposition': 'ContentDisposition', + 'Content-Encoding': 'ContentEncoding', + 'Range': 'Range', + 'If-Modified-Since': 'IfModifiedSince', + 'If-Unmodified-Since': 'IfUnmodifiedSince', + 'If-Match': 'IfMatch', + 'If-None-Match': 'IfNoneMatch', + 'x-cos-copy-source': 'CopySource', + 'x-cos-copy-source-Range': 'CopySourceRange', + 'x-cos-metadata-directive': 'MetadataDirective', + 'x-cos-copy-source-If-Modified-Since': 'CopySourceIfModifiedSince', + 'x-cos-copy-source-If-Unmodified-Since': 'CopySourceIfUnmodifiedSince', + 'x-cos-copy-source-If-Match': 'CopySourceIfMatch', + 'x-cos-copy-source-If-None-Match': 'CopySourceIfNoneMatch', + 'x-cos-acl': 'ACL', + 'x-cos-grant-read': 'GrantRead', + 'x-cos-grant-write': 'GrantWrite', + 'x-cos-grant-full-control': 'GrantFullControl', + 'x-cos-grant-read-acp': 'GrantReadAcp', + 'x-cos-grant-write-acp': 'GrantWriteAcp', + 'x-cos-storage-class': 'StorageClass', + // SSE-C + 'x-cos-server-side-encryption-customer-algorithm': 'SSECustomerAlgorithm', + 'x-cos-server-side-encryption-customer-key': 'SSECustomerKey', + 'x-cos-server-side-encryption-customer-key-MD5': 'SSECustomerKeyMD5', + // SSE-COS、SSE-KMS + 'x-cos-server-side-encryption': 'ServerSideEncryption', + 'x-cos-server-side-encryption-cos-kms-key-id': 'SSEKMSKeyId', + 'x-cos-server-side-encryption-context': 'SSEContext', + }; + util.each(headerMap, function (paramKey, headerKey) { + if (params[paramKey] !== undefined) { + Headers[headerKey] = params[paramKey]; + } + }); + + params.Headers = clearKey(Headers); + } + } + + return params; +}; + +var apiWrapper = function (apiName, apiFn) { + return function (params, callback) { + + var self = this; + + // 处理参数 + if (typeof params === 'function') { + callback = params; + params = {}; + } + + // 整理参数格式 + params = formatParams(apiName, params); + + // 代理回调函数 + var formatResult = function (result) { + if (result && result.headers) { + result.headers['x-cos-version-id'] && (result.VersionId = result.headers['x-cos-version-id']); + result.headers['x-cos-delete-marker'] && (result.DeleteMarker = result.headers['x-cos-delete-marker']); + } + return result; + }; + var _callback = function (err, data) { + callback && callback(formatResult(err), formatResult(data)); + }; + + var checkParams = function () { + if (apiName !== 'getService' && apiName !== 'abortUploadTask') { + // 判断参数是否完整 + var missingResult = hasMissingParams(apiName, params) + if (missingResult) { + return 'missing param ' + missingResult; + } + // 判断 region 格式 + if (params.Region) { + if (params.Region.indexOf('cos.') > -1) { + return 'param Region should not be start with "cos."'; + } else if (!/^([a-z\d-]+)$/.test(params.Region)) { + return 'Region format error.'; + } + // 判断 region 格式 + if (!self.options.CompatibilityMode + && params.Region.indexOf('-') === -1 + && params.Region !== 'yfb' + && params.Region !== 'default' + && params.Region !== 'accelerate') { + console.warn('warning: param Region format error, find help here: https://cloud.tencent.com/document/product/436/6224'); + } + } + // 兼容不带 AppId 的 Bucket + if (params.Bucket) { + if (!/^([a-z\d-]+)-(\d+)$/.test(params.Bucket)) { + if (params.AppId) { + params.Bucket = params.Bucket + '-' + params.AppId; + } else if (self.options.AppId) { + params.Bucket = params.Bucket + '-' + self.options.AppId; + } else { + return 'Bucket should format as "test-1250000000".'; + } + } + if (params.AppId) { + console.warn('warning: AppId has been deprecated, Please put it at the end of parameter Bucket(E.g Bucket:"test-1250000000" ).'); + delete params.AppId; + } + } + // 如果 Key 是 / 开头,强制去掉第一个 / + if (params.Key && params.Key.substr(0, 1) === '/') { + params.Key = params.Key.substr(1); + } + } + }; + + var errMsg = checkParams(); + var isSync = apiName === 'getAuth' || apiName === 'getObjectUrl'; + var Promise = global.Promise; + if (!isSync && Promise && !callback) { + return new Promise(function (resolve, reject) { + callback = function (err, data) { + err ? reject(err) : resolve(data); + }; + if (errMsg) return _callback({error: errMsg}); + apiFn.call(self, params, _callback); + }); + } else { + if (errMsg) return _callback({error: errMsg}); + var res = apiFn.call(self, params, _callback); + if (isSync) return res; + } + } +}; + +var throttleOnProgress = function (total, onProgress) { + var self = this; + var size0 = 0; + var size1 = 0; + var time0 = Date.now(); + var time1; + var timer; + + function update() { + timer = 0; + if (onProgress && (typeof onProgress === 'function')) { + time1 = Date.now(); + var speed = Math.max(0, Math.round((size1 - size0) / ((time1 - time0) / 1000) * 100) / 100) || 0; + var percent; + if (size1 === 0 && total === 0) { + percent = 1; + } else { + percent = Math.floor(size1 / total * 100) / 100 || 0; + } + time0 = time1; + size0 = size1; + try { + onProgress({loaded: size1, total: total, speed: speed, percent: percent}); + } catch (e) { + } + } + } + + return function (info, immediately) { + if (info) { + size1 = info.loaded; + total = info.total; + } + if (immediately) { + clearTimeout(timer); + update(); + } else { + if (timer) return; + timer = setTimeout(update, self.options.ProgressInterval); + } + }; +}; + +var getFileSize = function (api, params, callback) { + if (api === 'postObject') { + callback(); + } else if (api === 'putObject') { + if (params.Body !== undefined) { + params.ContentLength = params.Body.byteLength; + callback(null, params.ContentLength); + } else { + callback({error: 'missing param Body'}); + } + } else { + if (params.FilePath) { + wxfs.stat({ + path: params.FilePath, + success: function (res) { + var stats = res.stats; + params.FileStat = stats; + params.FileStat.FilePath = params.FilePath; + var size = stats.isDirectory() ? 0 : stats.size; + params.ContentLength = size = size || 0; + callback(null, size); + }, + fail: function (err) { + callback(err); + }, + }); + } else { + callback({error: 'missing param FilePath'}); + } + } +}; + +var getSkewTime = function (offset) { + return Date.now() + (offset || 0); +}; + +var compareVersion = function (v1, v2) { + v1 = v1.split('.') + v2 = v2.split('.') + var len = Math.max(v1.length, v2.length) + + while (v1.length < len) { + v1.push('0') + } + while (v2.length < len) { + v2.push('0') + } + + for (var i = 0; i < len; i++) { + var num1 = parseInt(v1[i]) + var num2 = parseInt(v2[i]) + + if (num1 > num2) { + return 1 + } else if (num1 < num2) { + return -1 + } + } + + return 0 +}; + +var canFileSlice = (function () { + var systemInfo = wx.getSystemInfoSync(); + var support = compareVersion(systemInfo.SDKVersion, '2.10.0') >= 0; + var needWarning = !support && systemInfo.platform === "devtools"; + return function () { + if (needWarning) console.warn('当前小程序版本小于 2.10.0,不支持分片上传,请更新软件。'); + needWarning = false; + return support; + }; +})(); + +var util = { + noop: noop, + formatParams: formatParams, + apiWrapper: apiWrapper, + xml2json: xml2json, + json2xml: json2xml, + md5: md5, + clearKey: clearKey, + fileSlice: fileSlice, + getBodyMd5: getBodyMd5, + getFileMd5: getFileMd5, + binaryBase64: binaryBase64, + extend: extend, + isArray: isArray, + isInArray: isInArray, + makeArray: makeArray, + each: each, + map: map, + filter: filter, + clone: clone, + attr: attr, + uuid: uuid, + camSafeUrlEncode: camSafeUrlEncode, + throttleOnProgress: throttleOnProgress, + getFileSize: getFileSize, + getSkewTime: getSkewTime, + getAuth: getAuth, + compareVersion: compareVersion, + canFileSlice: canFileSlice, +}; + +module.exports = util; +xml2json /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(1))) @@ -1946,332 +1946,332 @@ try{ /* 3 */ /***/ (function(module, exports) { -/* - * $Id: base64.js,v 2.15 2014/04/05 12:58:57 dankogai Exp dankogai $ - * - * Licensed under the BSD 3-Clause License. - * http://opensource.org/licenses/BSD-3-Clause - * - * References: - * http://en.wikipedia.org/wiki/Base64 - */ - -var Base64 = (function(global) { - global = global || {}; - 'use strict'; - // existing version for noConflict() - var _Base64 = global.Base64; - var version = "2.1.9"; - // if node.js, we use Buffer - var buffer; - // constants - var b64chars - = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; - var b64tab = function(bin) { - var t = {}; - for (var i = 0, l = bin.length; i < l; i++) t[bin.charAt(i)] = i; - return t; - }(b64chars); - var fromCharCode = String.fromCharCode; - // encoder stuff - var cb_utob = function(c) { - if (c.length < 2) { - var cc = c.charCodeAt(0); - return cc < 0x80 ? c - : cc < 0x800 ? (fromCharCode(0xc0 | (cc >>> 6)) - + fromCharCode(0x80 | (cc & 0x3f))) - : (fromCharCode(0xe0 | ((cc >>> 12) & 0x0f)) - + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) - + fromCharCode(0x80 | ( cc & 0x3f))); - } else { - var cc = 0x10000 - + (c.charCodeAt(0) - 0xD800) * 0x400 - + (c.charCodeAt(1) - 0xDC00); - return (fromCharCode(0xf0 | ((cc >>> 18) & 0x07)) - + fromCharCode(0x80 | ((cc >>> 12) & 0x3f)) - + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) - + fromCharCode(0x80 | ( cc & 0x3f))); - } - }; - var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g; - var utob = function(u) { - return u.replace(re_utob, cb_utob); - }; - var cb_encode = function(ccc) { - var padlen = [0, 2, 1][ccc.length % 3], - ord = ccc.charCodeAt(0) << 16 - | ((ccc.length > 1 ? ccc.charCodeAt(1) : 0) << 8) - | ((ccc.length > 2 ? ccc.charCodeAt(2) : 0)), - chars = [ - b64chars.charAt( ord >>> 18), - b64chars.charAt((ord >>> 12) & 63), - padlen >= 2 ? '=' : b64chars.charAt((ord >>> 6) & 63), - padlen >= 1 ? '=' : b64chars.charAt(ord & 63) - ]; - return chars.join(''); - }; - var btoa = global.btoa ? function(b) { - return global.btoa(b); - } : function(b) { - return b.replace(/[\s\S]{1,3}/g, cb_encode); - }; - var _encode = buffer ? function (u) { - return (u.constructor === buffer.constructor ? u : new buffer(u)) - .toString('base64') - } - : function (u) { return btoa(utob(u)) } - ; - var encode = function(u, urisafe) { - return !urisafe - ? _encode(String(u)) - : _encode(String(u)).replace(/[+\/]/g, function(m0) { - return m0 == '+' ? '-' : '_'; - }).replace(/=/g, ''); - }; - var encodeURI = function(u) { return encode(u, true) }; - // decoder stuff - var re_btou = new RegExp([ - '[\xC0-\xDF][\x80-\xBF]', - '[\xE0-\xEF][\x80-\xBF]{2}', - '[\xF0-\xF7][\x80-\xBF]{3}' - ].join('|'), 'g'); - var cb_btou = function(cccc) { - switch(cccc.length) { - case 4: - var cp = ((0x07 & cccc.charCodeAt(0)) << 18) - | ((0x3f & cccc.charCodeAt(1)) << 12) - | ((0x3f & cccc.charCodeAt(2)) << 6) - | (0x3f & cccc.charCodeAt(3)), - offset = cp - 0x10000; - return (fromCharCode((offset >>> 10) + 0xD800) - + fromCharCode((offset & 0x3FF) + 0xDC00)); - case 3: - return fromCharCode( - ((0x0f & cccc.charCodeAt(0)) << 12) - | ((0x3f & cccc.charCodeAt(1)) << 6) - | (0x3f & cccc.charCodeAt(2)) - ); - default: - return fromCharCode( - ((0x1f & cccc.charCodeAt(0)) << 6) - | (0x3f & cccc.charCodeAt(1)) - ); - } - }; - var btou = function(b) { - return b.replace(re_btou, cb_btou); - }; - var cb_decode = function(cccc) { - var len = cccc.length, - padlen = len % 4, - n = (len > 0 ? b64tab[cccc.charAt(0)] << 18 : 0) - | (len > 1 ? b64tab[cccc.charAt(1)] << 12 : 0) - | (len > 2 ? b64tab[cccc.charAt(2)] << 6 : 0) - | (len > 3 ? b64tab[cccc.charAt(3)] : 0), - chars = [ - fromCharCode( n >>> 16), - fromCharCode((n >>> 8) & 0xff), - fromCharCode( n & 0xff) - ]; - chars.length -= [0, 0, 2, 1][padlen]; - return chars.join(''); - }; - var atob = global.atob ? function(a) { - return global.atob(a); - } : function(a){ - return a.replace(/[\s\S]{1,4}/g, cb_decode); - }; - var _decode = buffer ? function(a) { - return (a.constructor === buffer.constructor - ? a : new buffer(a, 'base64')).toString(); - } - : function(a) { return btou(atob(a)) }; - var decode = function(a){ - return _decode( - String(a).replace(/[-_]/g, function(m0) { return m0 == '-' ? '+' : '/' }) - .replace(/[^A-Za-z0-9\+\/]/g, '') - ); - }; - var noConflict = function() { - var Base64 = global.Base64; - global.Base64 = _Base64; - return Base64; - }; - // export Base64 - var Base64 = { - VERSION: version, - atob: atob, - btoa: btoa, - fromBase64: decode, - toBase64: encode, - utob: utob, - encode: encode, - encodeURI: encodeURI, - btou: btou, - decode: decode, - noConflict: noConflict - }; - return Base64; -})(); - -module.exports = Base64; - +/* + * $Id: base64.js,v 2.15 2014/04/05 12:58:57 dankogai Exp dankogai $ + * + * Licensed under the BSD 3-Clause License. + * http://opensource.org/licenses/BSD-3-Clause + * + * References: + * http://en.wikipedia.org/wiki/Base64 + */ + +var Base64 = (function(global) { + global = global || {}; + 'use strict'; + // existing version for noConflict() + var _Base64 = global.Base64; + var version = "2.1.9"; + // if node.js, we use Buffer + var buffer; + // constants + var b64chars + = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; + var b64tab = function(bin) { + var t = {}; + for (var i = 0, l = bin.length; i < l; i++) t[bin.charAt(i)] = i; + return t; + }(b64chars); + var fromCharCode = String.fromCharCode; + // encoder stuff + var cb_utob = function(c) { + if (c.length < 2) { + var cc = c.charCodeAt(0); + return cc < 0x80 ? c + : cc < 0x800 ? (fromCharCode(0xc0 | (cc >>> 6)) + + fromCharCode(0x80 | (cc & 0x3f))) + : (fromCharCode(0xe0 | ((cc >>> 12) & 0x0f)) + + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) + + fromCharCode(0x80 | ( cc & 0x3f))); + } else { + var cc = 0x10000 + + (c.charCodeAt(0) - 0xD800) * 0x400 + + (c.charCodeAt(1) - 0xDC00); + return (fromCharCode(0xf0 | ((cc >>> 18) & 0x07)) + + fromCharCode(0x80 | ((cc >>> 12) & 0x3f)) + + fromCharCode(0x80 | ((cc >>> 6) & 0x3f)) + + fromCharCode(0x80 | ( cc & 0x3f))); + } + }; + var re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g; + var utob = function(u) { + return u.replace(re_utob, cb_utob); + }; + var cb_encode = function(ccc) { + var padlen = [0, 2, 1][ccc.length % 3], + ord = ccc.charCodeAt(0) << 16 + | ((ccc.length > 1 ? ccc.charCodeAt(1) : 0) << 8) + | ((ccc.length > 2 ? ccc.charCodeAt(2) : 0)), + chars = [ + b64chars.charAt( ord >>> 18), + b64chars.charAt((ord >>> 12) & 63), + padlen >= 2 ? '=' : b64chars.charAt((ord >>> 6) & 63), + padlen >= 1 ? '=' : b64chars.charAt(ord & 63) + ]; + return chars.join(''); + }; + var btoa = global.btoa ? function(b) { + return global.btoa(b); + } : function(b) { + return b.replace(/[\s\S]{1,3}/g, cb_encode); + }; + var _encode = buffer ? function (u) { + return (u.constructor === buffer.constructor ? u : new buffer(u)) + .toString('base64') + } + : function (u) { return btoa(utob(u)) } + ; + var encode = function(u, urisafe) { + return !urisafe + ? _encode(String(u)) + : _encode(String(u)).replace(/[+\/]/g, function(m0) { + return m0 == '+' ? '-' : '_'; + }).replace(/=/g, ''); + }; + var encodeURI = function(u) { return encode(u, true) }; + // decoder stuff + var re_btou = new RegExp([ + '[\xC0-\xDF][\x80-\xBF]', + '[\xE0-\xEF][\x80-\xBF]{2}', + '[\xF0-\xF7][\x80-\xBF]{3}' + ].join('|'), 'g'); + var cb_btou = function(cccc) { + switch(cccc.length) { + case 4: + var cp = ((0x07 & cccc.charCodeAt(0)) << 18) + | ((0x3f & cccc.charCodeAt(1)) << 12) + | ((0x3f & cccc.charCodeAt(2)) << 6) + | (0x3f & cccc.charCodeAt(3)), + offset = cp - 0x10000; + return (fromCharCode((offset >>> 10) + 0xD800) + + fromCharCode((offset & 0x3FF) + 0xDC00)); + case 3: + return fromCharCode( + ((0x0f & cccc.charCodeAt(0)) << 12) + | ((0x3f & cccc.charCodeAt(1)) << 6) + | (0x3f & cccc.charCodeAt(2)) + ); + default: + return fromCharCode( + ((0x1f & cccc.charCodeAt(0)) << 6) + | (0x3f & cccc.charCodeAt(1)) + ); + } + }; + var btou = function(b) { + return b.replace(re_btou, cb_btou); + }; + var cb_decode = function(cccc) { + var len = cccc.length, + padlen = len % 4, + n = (len > 0 ? b64tab[cccc.charAt(0)] << 18 : 0) + | (len > 1 ? b64tab[cccc.charAt(1)] << 12 : 0) + | (len > 2 ? b64tab[cccc.charAt(2)] << 6 : 0) + | (len > 3 ? b64tab[cccc.charAt(3)] : 0), + chars = [ + fromCharCode( n >>> 16), + fromCharCode((n >>> 8) & 0xff), + fromCharCode( n & 0xff) + ]; + chars.length -= [0, 0, 2, 1][padlen]; + return chars.join(''); + }; + var atob = global.atob ? function(a) { + return global.atob(a); + } : function(a){ + return a.replace(/[\s\S]{1,4}/g, cb_decode); + }; + var _decode = buffer ? function(a) { + return (a.constructor === buffer.constructor + ? a : new buffer(a, 'base64')).toString(); + } + : function(a) { return btou(atob(a)) }; + var decode = function(a){ + return _decode( + String(a).replace(/[-_]/g, function(m0) { return m0 == '-' ? '+' : '/' }) + .replace(/[^A-Za-z0-9\+\/]/g, '') + ); + }; + var noConflict = function() { + var Base64 = global.Base64; + global.Base64 = _Base64; + return Base64; + }; + // export Base64 + var Base64 = { + VERSION: version, + atob: atob, + btoa: btoa, + fromBase64: decode, + toBase64: encode, + utob: utob, + encode: encode, + encodeURI: encodeURI, + btou: btou, + decode: decode, + noConflict: noConflict + }; + return Base64; +})(); + +module.exports = Base64; + /***/ }), /* 4 */ /***/ (function(module, exports) { -var initEvent = function (cos) { - var listeners = {}; - var getList = function (action) { - !listeners[action] && (listeners[action] = []); - return listeners[action]; - }; - cos.on = function (action, callback) { - getList(action).push(callback); - }; - cos.off = function (action, callback) { - var list = getList(action); - for (var i = list.length - 1; i >= 0; i--) { - callback === list[i] && list.splice(i, 1); - } - }; - cos.emit = function (action, data) { - var list = getList(action).map(function (cb) { - return cb; - }); - for (var i = 0; i < list.length; i++) { - list[i](data); - } - }; -}; - -var EventProxy = function () { - initEvent(this); -}; - -module.exports.init = initEvent; +var initEvent = function (cos) { + var listeners = {}; + var getList = function (action) { + !listeners[action] && (listeners[action] = []); + return listeners[action]; + }; + cos.on = function (action, callback) { + getList(action).push(callback); + }; + cos.off = function (action, callback) { + var list = getList(action); + for (var i = list.length - 1; i >= 0; i--) { + callback === list[i] && list.splice(i, 1); + } + }; + cos.emit = function (action, data) { + var list = getList(action).map(function (cb) { + return cb; + }); + for (var i = 0; i < list.length; i++) { + list[i](data); + } + }; +}; + +var EventProxy = function () { + initEvent(this); +}; + +module.exports.init = initEvent; module.exports.EventProxy = EventProxy; /***/ }), /* 5 */ /***/ (function(module, exports, __webpack_require__) { -var util = __webpack_require__(0); - -// 按照文件特征值,缓存 UploadId -var cacheKey = 'cos_sdk_upload_cache'; -var expires = 30 * 24 * 3600; -var cache; -var timer; - -var getCache = function () { - try { - var val = JSON.parse(wx.getStorageSync(cacheKey)); - } catch (e) { - } - if (!val) val = []; - return val; -}; -var setCache = function () { - try { - wx.setStorageSync(cacheKey, JSON.stringify(cache)) - } catch (e) { - } -}; - -var init = function () { - if (cache) return; - cache = getCache(); - // 清理太老旧的数据 - var changed = false; - var now = Math.round(Date.now() / 1000); - for (var i = cache.length - 1; i >= 0; i--) { - var mtime = cache[i][2]; - if (!mtime || mtime + expires < now) { - cache.splice(i, 1); - changed = true; - } - } - changed && setCache(); -}; - -// 把缓存存到本地 -var save = function () { - if (timer) return; - timer = setTimeout(function () { - setCache(); - timer = null; - }, 400); -}; - -var mod = { - using: {}, - // 标记 UploadId 正在使用 - setUsing: function (uuid) { - mod.using[uuid] = true; - }, - // 标记 UploadId 已经没在使用 - removeUsing: function (uuid) { - delete mod.using[uuid]; - }, - // 用上传参数生成哈希值 - getFileId: function (FileStat, ChunkSize, Bucket, Key) { - if (FileStat.FilePath && FileStat.size && FileStat.lastModifiedTime && ChunkSize) { - return util.md5([FileStat.FilePath].join('::')) + '-' + util.md5([FileStat.size, FileStat.mode, FileStat.lastAccessedTime, FileStat.lastModifiedTime, ChunkSize, Bucket, Key].join('::')); - } else { - return null; - } - }, - // 获取文件对应的 UploadId 列表 - getUploadIdList: function (uuid) { - if (!uuid) return null; - init(); - var list = []; - for (var i = 0; i < cache.length; i++) { - if (cache[i][0] === uuid) - list.push(cache[i][1]); - } - return list.length ? list : null; - }, - // 缓存 UploadId - saveUploadId: function (uuid, UploadId, limit) { - init(); - if (!uuid) return; - // 清理没用的 UploadId - var part1 = uuid.substr(0, uuid.indexOf('-') + 1); - for (var i = cache.length - 1; i >= 0; i--) { - var item = cache[i]; - if (item[0] === uuid && item[1] === UploadId) { - cache.splice(i, 1); - } else if (uuid !== item[0] && item[0].indexOf(part1) === 0) { // 文件路径相同,但其他信息不同,说明文件改变了或上传参数(存储桶、路径、分片大小)变了,直接清理掉 - cache.splice(i, 1); - } - } - cache.unshift([uuid, UploadId, Math.round(Date.now() / 1000)]); - if (cache.length > limit) cache.splice(limit); - save(); - }, - // UploadId 已用完,移除掉 - removeUploadId: function (UploadId) { - init(); - delete mod.using[UploadId]; - for (var i = cache.length - 1; i >= 0; i--) { - if (cache[i][1] === UploadId) cache.splice(i, 1) - } - save(); - }, -}; - -module.exports = mod; +var util = __webpack_require__(0); + +// 按照文件特征值,缓存 UploadId +var cacheKey = 'cos_sdk_upload_cache'; +var expires = 30 * 24 * 3600; +var cache; +var timer; + +var getCache = function () { + try { + var val = JSON.parse(wx.getStorageSync(cacheKey)); + } catch (e) { + } + if (!val) val = []; + return val; +}; +var setCache = function () { + try { + wx.setStorageSync(cacheKey, JSON.stringify(cache)) + } catch (e) { + } +}; + +var init = function () { + if (cache) return; + cache = getCache(); + // 清理太老旧的数据 + var changed = false; + var now = Math.round(Date.now() / 1000); + for (var i = cache.length - 1; i >= 0; i--) { + var mtime = cache[i][2]; + if (!mtime || mtime + expires < now) { + cache.splice(i, 1); + changed = true; + } + } + changed && setCache(); +}; + +// 把缓存存到本地 +var save = function () { + if (timer) return; + timer = setTimeout(function () { + setCache(); + timer = null; + }, 400); +}; + +var mod = { + using: {}, + // 标记 UploadId 正在使用 + setUsing: function (uuid) { + mod.using[uuid] = true; + }, + // 标记 UploadId 已经没在使用 + removeUsing: function (uuid) { + delete mod.using[uuid]; + }, + // 用上传参数生成哈希值 + getFileId: function (FileStat, ChunkSize, Bucket, Key) { + if (FileStat.FilePath && FileStat.size && FileStat.lastModifiedTime && ChunkSize) { + return util.md5([FileStat.FilePath].join('::')) + '-' + util.md5([FileStat.size, FileStat.mode, FileStat.lastAccessedTime, FileStat.lastModifiedTime, ChunkSize, Bucket, Key].join('::')); + } else { + return null; + } + }, + // 获取文件对应的 UploadId 列表 + getUploadIdList: function (uuid) { + if (!uuid) return null; + init(); + var list = []; + for (var i = 0; i < cache.length; i++) { + if (cache[i][0] === uuid) + list.push(cache[i][1]); + } + return list.length ? list : null; + }, + // 缓存 UploadId + saveUploadId: function (uuid, UploadId, limit) { + init(); + if (!uuid) return; + // 清理没用的 UploadId + var part1 = uuid.substr(0, uuid.indexOf('-') + 1); + for (var i = cache.length - 1; i >= 0; i--) { + var item = cache[i]; + if (item[0] === uuid && item[1] === UploadId) { + cache.splice(i, 1); + } else if (uuid !== item[0] && item[0].indexOf(part1) === 0) { // 文件路径相同,但其他信息不同,说明文件改变了或上传参数(存储桶、路径、分片大小)变了,直接清理掉 + cache.splice(i, 1); + } + } + cache.unshift([uuid, UploadId, Math.round(Date.now() / 1000)]); + if (cache.length > limit) cache.splice(limit); + save(); + }, + // UploadId 已用完,移除掉 + removeUploadId: function (UploadId) { + init(); + delete mod.using[UploadId]; + for (var i = cache.length - 1; i >= 0; i--) { + if (cache[i][1] === UploadId) cache.splice(i, 1) + } + save(); + }, +}; + +module.exports = mod; /***/ }), /* 6 */ /***/ (function(module, exports, __webpack_require__) { -var COS = __webpack_require__(7); +var COS = __webpack_require__(7); module.exports = COS; /***/ }), @@ -2279,750 +2279,750 @@ module.exports = COS; /***/ (function(module, exports, __webpack_require__) { "use strict"; - - -var util = __webpack_require__(0); -var event = __webpack_require__(4); -var task = __webpack_require__(16); -var base = __webpack_require__(17); -var advance = __webpack_require__(23); - -var defaultOptions = { - SecretId: '', - SecretKey: '', - XCosSecurityToken: '', // 使用临时密钥需要注意自行刷新 Token - ChunkRetryTimes: 2, - FileParallelLimit: 3, - ChunkParallelLimit: 3, - ChunkSize: 1024 * 1024, - SliceSize: 1024 * 1024, - CopyChunkParallelLimit: 20, - CopyChunkSize: 1024 * 1024 * 10, - CopySliceSize: 1024 * 1024 * 10, - MaxPartNumber: 10000, - ProgressInterval: 1000, - UploadQueueSize: 10000, - Domain: '', - ServiceDomain: '', - Protocol: '', - CompatibilityMode: false, - ForcePathStyle: false, - Timeout: 0, // 单位毫秒,0 代表不设置超时时间 - CorrectClockSkew: true, - SystemClockOffset: 0, // 单位毫秒,ms - UploadCheckContentMd5: false, - UploadIdCacheLimit: 50, - UseAccelerate: false, -}; - -// 对外暴露的类 -var COS = function (options) { - this.options = util.extend(util.clone(defaultOptions), options || {}); - this.options.FileParallelLimit = Math.max(1, this.options.FileParallelLimit); - this.options.ChunkParallelLimit = Math.max(1, this.options.ChunkParallelLimit); - this.options.ChunkRetryTimes = Math.max(0, this.options.ChunkRetryTimes); - this.options.ChunkSize = Math.max(1024 * 1024, this.options.ChunkSize); - this.options.CopyChunkParallelLimit = Math.max(1, this.options.CopyChunkParallelLimit); - this.options.CopyChunkSize = Math.max(1024 * 1024, this.options.CopyChunkSize); - this.options.CopySliceSize = Math.max(0, this.options.CopySliceSize); - this.options.MaxPartNumber = Math.max(1024, Math.min(10000, this.options.MaxPartNumber)); - this.options.Timeout = Math.max(0, this.options.Timeout); - if (this.options.AppId) { - console.warn('warning: AppId has been deprecated, Please put it at the end of parameter Bucket(E.g: "test-1250000000").'); - } - event.init(this); - task.init(this); -}; - -base.init(COS, task); -advance.init(COS, task); - -COS.getAuthorization = util.getAuth; -COS.version = '1.0.7'; - -module.exports = COS; + + +var util = __webpack_require__(0); +var event = __webpack_require__(4); +var task = __webpack_require__(16); +var base = __webpack_require__(17); +var advance = __webpack_require__(23); + +var defaultOptions = { + SecretId: '', + SecretKey: '', + XCosSecurityToken: '', // 使用临时密钥需要注意自行刷新 Token + ChunkRetryTimes: 2, + FileParallelLimit: 3, + ChunkParallelLimit: 3, + ChunkSize: 1024 * 1024, + SliceSize: 1024 * 1024, + CopyChunkParallelLimit: 20, + CopyChunkSize: 1024 * 1024 * 10, + CopySliceSize: 1024 * 1024 * 10, + MaxPartNumber: 10000, + ProgressInterval: 1000, + UploadQueueSize: 10000, + Domain: '', + ServiceDomain: '', + Protocol: '', + CompatibilityMode: false, + ForcePathStyle: false, + Timeout: 0, // 单位毫秒,0 代表不设置超时时间 + CorrectClockSkew: true, + SystemClockOffset: 0, // 单位毫秒,ms + UploadCheckContentMd5: false, + UploadIdCacheLimit: 50, + UseAccelerate: false, +}; + +// 对外暴露的类 +var COS = function (options) { + this.options = util.extend(util.clone(defaultOptions), options || {}); + this.options.FileParallelLimit = Math.max(1, this.options.FileParallelLimit); + this.options.ChunkParallelLimit = Math.max(1, this.options.ChunkParallelLimit); + this.options.ChunkRetryTimes = Math.max(0, this.options.ChunkRetryTimes); + this.options.ChunkSize = Math.max(1024 * 1024, this.options.ChunkSize); + this.options.CopyChunkParallelLimit = Math.max(1, this.options.CopyChunkParallelLimit); + this.options.CopyChunkSize = Math.max(1024 * 1024, this.options.CopyChunkSize); + this.options.CopySliceSize = Math.max(0, this.options.CopySliceSize); + this.options.MaxPartNumber = Math.max(1024, Math.min(10000, this.options.MaxPartNumber)); + this.options.Timeout = Math.max(0, this.options.Timeout); + if (this.options.AppId) { + console.warn('warning: AppId has been deprecated, Please put it at the end of parameter Bucket(E.g: "test-1250000000").'); + } + event.init(this); + task.init(this); +}; + +base.init(COS, task); +advance.init(COS, task); + +COS.getAuthorization = util.getAuth; +COS.version = '1.0.10'; + +module.exports = COS; /***/ }), /* 8 */ /***/ (function(module, exports, __webpack_require__) { -/* WEBPACK VAR INJECTION */(function(process, global) {var __WEBPACK_AMD_DEFINE_RESULT__;/* https://github.com/emn178/js-md5 */ -(function () { - 'use strict'; - - var ERROR = 'input is invalid type'; - var WINDOW = typeof window === 'object'; - var root = WINDOW ? window : {}; - if (root.JS_MD5_NO_WINDOW) { - WINDOW = false; - } - var WEB_WORKER = !WINDOW && typeof self === 'object'; - var NODE_JS = !root.JS_MD5_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node; - if (NODE_JS) { - root = global; - } else if (WEB_WORKER) { - root = self; - } - var COMMON_JS = !root.JS_MD5_NO_COMMON_JS && typeof module === 'object' && module.exports; - var AMD = "function" === 'function' && __webpack_require__(10); - var ARRAY_BUFFER = !root.JS_MD5_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined'; - var HEX_CHARS = '0123456789abcdef'.split(''); - var EXTRA = [128, 32768, 8388608, -2147483648]; - var SHIFT = [0, 8, 16, 24]; - var OUTPUT_TYPES = ['hex', 'array', 'digest', 'buffer', 'arrayBuffer', 'base64']; - var BASE64_ENCODE_CHAR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split(''); - - var blocks = [], buffer8; - if (ARRAY_BUFFER) { - var buffer = new ArrayBuffer(68); - buffer8 = new Uint8Array(buffer); - blocks = new Uint32Array(buffer); - } - - if (root.JS_MD5_NO_NODE_JS || !Array.isArray) { - Array.isArray = function (obj) { - return Object.prototype.toString.call(obj) === '[object Array]'; - }; - } - - if (ARRAY_BUFFER && (root.JS_MD5_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) { - ArrayBuffer.isView = function (obj) { - return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer; - }; - } - - /** - * @method hex - * @memberof md5 - * @description Output hash as hex string - * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash - * @returns {String} Hex string - * @example - * md5.hex('The quick brown fox jumps over the lazy dog'); - * // equal to - * md5('The quick brown fox jumps over the lazy dog'); - */ - /** - * @method digest - * @memberof md5 - * @description Output hash as bytes array - * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash - * @returns {Array} Bytes array - * @example - * md5.digest('The quick brown fox jumps over the lazy dog'); - */ - /** - * @method array - * @memberof md5 - * @description Output hash as bytes array - * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash - * @returns {Array} Bytes array - * @example - * md5.array('The quick brown fox jumps over the lazy dog'); - */ - /** - * @method arrayBuffer - * @memberof md5 - * @description Output hash as ArrayBuffer - * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash - * @returns {ArrayBuffer} ArrayBuffer - * @example - * md5.arrayBuffer('The quick brown fox jumps over the lazy dog'); - */ - /** - * @method buffer - * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead. - * @memberof md5 - * @description Output hash as ArrayBuffer - * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash - * @returns {ArrayBuffer} ArrayBuffer - * @example - * md5.buffer('The quick brown fox jumps over the lazy dog'); - */ - /** - * @method base64 - * @memberof md5 - * @description Output hash as base64 string - * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash - * @returns {String} base64 string - * @example - * md5.base64('The quick brown fox jumps over the lazy dog'); - */ - var createOutputMethod = function (outputType) { - return function (message) { - return new Md5(true).update(message)[outputType](); - }; - }; - - /** - * @method create - * @memberof md5 - * @description Create Md5 object - * @returns {Md5} Md5 object. - * @example - * var hash = md5.create(); - */ - /** - * @method update - * @memberof md5 - * @description Create and update Md5 object - * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash - * @returns {Md5} Md5 object. - * @example - * var hash = md5.update('The quick brown fox jumps over the lazy dog'); - * // equal to - * var hash = md5.create(); - * hash.update('The quick brown fox jumps over the lazy dog'); - */ - var createMethod = function () { - var method = createOutputMethod('hex'); - if (NODE_JS) { - method = nodeWrap(method); - } - method.getCtx = method.create = function () { - return new Md5(); - }; - method.update = function (message) { - return method.create().update(message); - }; - for (var i = 0; i < OUTPUT_TYPES.length; ++i) { - var type = OUTPUT_TYPES[i]; - method[type] = createOutputMethod(type); - } - return method; - }; - - var nodeWrap = function (method) { - var crypto = eval("require('crypto')"); - var Buffer = eval("require('buffer').Buffer"); - var nodeMethod = function (message) { - if (typeof message === 'string') { - return crypto.createHash('md5').update(message, 'utf8').digest('hex'); - } else { - if (message === null || message === undefined) { - throw ERROR; - } else if (message.constructor === ArrayBuffer) { - message = new Uint8Array(message); - } - } - if (Array.isArray(message) || ArrayBuffer.isView(message) || - message.constructor === Buffer) { - return crypto.createHash('md5').update(new Buffer(message)).digest('hex'); - } else { - return method(message); - } - }; - return nodeMethod; - }; - - /** - * Md5 class - * @class Md5 - * @description This is internal class. - * @see {@link md5.create} - */ - function Md5(sharedMemory) { - if (sharedMemory) { - blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] = - blocks[4] = blocks[5] = blocks[6] = blocks[7] = - blocks[8] = blocks[9] = blocks[10] = blocks[11] = - blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; - this.blocks = blocks; - this.buffer8 = buffer8; - } else { - if (ARRAY_BUFFER) { - var buffer = new ArrayBuffer(68); - this.buffer8 = new Uint8Array(buffer); - this.blocks = new Uint32Array(buffer); - } else { - this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - } - } - this.h0 = this.h1 = this.h2 = this.h3 = this.start = this.bytes = this.hBytes = 0; - this.finalized = this.hashed = false; - this.first = true; - } - - /** - * @method update - * @memberof Md5 - * @instance - * @description Update hash - * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash - * @returns {Md5} Md5 object. - * @see {@link md5.update} - */ - Md5.prototype.update = function (message) { - if (this.finalized) { - return; - } - - var notString, type = typeof message; - if (type !== 'string') { - if (type === 'object') { - if (message === null) { - throw ERROR; - } else if (ARRAY_BUFFER && (message.constructor === ArrayBuffer || message.constructor.name === 'ArrayBuffer')) { - message = new Uint8Array(message); - } else if (!Array.isArray(message)) { - if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) { - throw ERROR; - } - } - } else { - throw ERROR; - } - notString = true; - } - var code, index = 0, i, length = message.length, blocks = this.blocks; - var buffer8 = this.buffer8; - - while (index < length) { - if (this.hashed) { - this.hashed = false; - blocks[0] = blocks[16]; - blocks[16] = blocks[1] = blocks[2] = blocks[3] = - blocks[4] = blocks[5] = blocks[6] = blocks[7] = - blocks[8] = blocks[9] = blocks[10] = blocks[11] = - blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; - } - - if (notString) { - if (ARRAY_BUFFER) { - for (i = this.start; index < length && i < 64; ++index) { - buffer8[i++] = message[index]; - } - } else { - for (i = this.start; index < length && i < 64; ++index) { - blocks[i >> 2] |= message[index] << SHIFT[i++ & 3]; - } - } - } else { - if (ARRAY_BUFFER) { - for (i = this.start; index < length && i < 64; ++index) { - code = message.charCodeAt(index); - if (code < 0x80) { - buffer8[i++] = code; - } else if (code < 0x800) { - buffer8[i++] = 0xc0 | (code >> 6); - buffer8[i++] = 0x80 | (code & 0x3f); - } else if (code < 0xd800 || code >= 0xe000) { - buffer8[i++] = 0xe0 | (code >> 12); - buffer8[i++] = 0x80 | ((code >> 6) & 0x3f); - buffer8[i++] = 0x80 | (code & 0x3f); - } else { - code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff)); - buffer8[i++] = 0xf0 | (code >> 18); - buffer8[i++] = 0x80 | ((code >> 12) & 0x3f); - buffer8[i++] = 0x80 | ((code >> 6) & 0x3f); - buffer8[i++] = 0x80 | (code & 0x3f); - } - } - } else { - for (i = this.start; index < length && i < 64; ++index) { - code = message.charCodeAt(index); - if (code < 0x80) { - blocks[i >> 2] |= code << SHIFT[i++ & 3]; - } else if (code < 0x800) { - blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3]; - blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; - } else if (code < 0xd800 || code >= 0xe000) { - blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3]; - blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; - blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; - } else { - code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff)); - blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3]; - blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3]; - blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; - blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; - } - } - } - } - this.lastByteIndex = i; - this.bytes += i - this.start; - if (i >= 64) { - this.start = i - 64; - this.hash(); - this.hashed = true; - } else { - this.start = i; - } - } - if (this.bytes > 4294967295) { - this.hBytes += this.bytes / 4294967296 << 0; - this.bytes = this.bytes % 4294967296; - } - return this; - }; - - Md5.prototype.finalize = function () { - if (this.finalized) { - return; - } - this.finalized = true; - var blocks = this.blocks, i = this.lastByteIndex; - blocks[i >> 2] |= EXTRA[i & 3]; - if (i >= 56) { - if (!this.hashed) { - this.hash(); - } - blocks[0] = blocks[16]; - blocks[16] = blocks[1] = blocks[2] = blocks[3] = - blocks[4] = blocks[5] = blocks[6] = blocks[7] = - blocks[8] = blocks[9] = blocks[10] = blocks[11] = - blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; - } - blocks[14] = this.bytes << 3; - blocks[15] = this.hBytes << 3 | this.bytes >>> 29; - this.hash(); - }; - - Md5.prototype.hash = function () { - var a, b, c, d, bc, da, blocks = this.blocks; - - if (this.first) { - a = blocks[0] - 680876937; - a = (a << 7 | a >>> 25) - 271733879 << 0; - d = (-1732584194 ^ a & 2004318071) + blocks[1] - 117830708; - d = (d << 12 | d >>> 20) + a << 0; - c = (-271733879 ^ (d & (a ^ -271733879))) + blocks[2] - 1126478375; - c = (c << 17 | c >>> 15) + d << 0; - b = (a ^ (c & (d ^ a))) + blocks[3] - 1316259209; - b = (b << 22 | b >>> 10) + c << 0; - } else { - a = this.h0; - b = this.h1; - c = this.h2; - d = this.h3; - a += (d ^ (b & (c ^ d))) + blocks[0] - 680876936; - a = (a << 7 | a >>> 25) + b << 0; - d += (c ^ (a & (b ^ c))) + blocks[1] - 389564586; - d = (d << 12 | d >>> 20) + a << 0; - c += (b ^ (d & (a ^ b))) + blocks[2] + 606105819; - c = (c << 17 | c >>> 15) + d << 0; - b += (a ^ (c & (d ^ a))) + blocks[3] - 1044525330; - b = (b << 22 | b >>> 10) + c << 0; - } - - a += (d ^ (b & (c ^ d))) + blocks[4] - 176418897; - a = (a << 7 | a >>> 25) + b << 0; - d += (c ^ (a & (b ^ c))) + blocks[5] + 1200080426; - d = (d << 12 | d >>> 20) + a << 0; - c += (b ^ (d & (a ^ b))) + blocks[6] - 1473231341; - c = (c << 17 | c >>> 15) + d << 0; - b += (a ^ (c & (d ^ a))) + blocks[7] - 45705983; - b = (b << 22 | b >>> 10) + c << 0; - a += (d ^ (b & (c ^ d))) + blocks[8] + 1770035416; - a = (a << 7 | a >>> 25) + b << 0; - d += (c ^ (a & (b ^ c))) + blocks[9] - 1958414417; - d = (d << 12 | d >>> 20) + a << 0; - c += (b ^ (d & (a ^ b))) + blocks[10] - 42063; - c = (c << 17 | c >>> 15) + d << 0; - b += (a ^ (c & (d ^ a))) + blocks[11] - 1990404162; - b = (b << 22 | b >>> 10) + c << 0; - a += (d ^ (b & (c ^ d))) + blocks[12] + 1804603682; - a = (a << 7 | a >>> 25) + b << 0; - d += (c ^ (a & (b ^ c))) + blocks[13] - 40341101; - d = (d << 12 | d >>> 20) + a << 0; - c += (b ^ (d & (a ^ b))) + blocks[14] - 1502002290; - c = (c << 17 | c >>> 15) + d << 0; - b += (a ^ (c & (d ^ a))) + blocks[15] + 1236535329; - b = (b << 22 | b >>> 10) + c << 0; - a += (c ^ (d & (b ^ c))) + blocks[1] - 165796510; - a = (a << 5 | a >>> 27) + b << 0; - d += (b ^ (c & (a ^ b))) + blocks[6] - 1069501632; - d = (d << 9 | d >>> 23) + a << 0; - c += (a ^ (b & (d ^ a))) + blocks[11] + 643717713; - c = (c << 14 | c >>> 18) + d << 0; - b += (d ^ (a & (c ^ d))) + blocks[0] - 373897302; - b = (b << 20 | b >>> 12) + c << 0; - a += (c ^ (d & (b ^ c))) + blocks[5] - 701558691; - a = (a << 5 | a >>> 27) + b << 0; - d += (b ^ (c & (a ^ b))) + blocks[10] + 38016083; - d = (d << 9 | d >>> 23) + a << 0; - c += (a ^ (b & (d ^ a))) + blocks[15] - 660478335; - c = (c << 14 | c >>> 18) + d << 0; - b += (d ^ (a & (c ^ d))) + blocks[4] - 405537848; - b = (b << 20 | b >>> 12) + c << 0; - a += (c ^ (d & (b ^ c))) + blocks[9] + 568446438; - a = (a << 5 | a >>> 27) + b << 0; - d += (b ^ (c & (a ^ b))) + blocks[14] - 1019803690; - d = (d << 9 | d >>> 23) + a << 0; - c += (a ^ (b & (d ^ a))) + blocks[3] - 187363961; - c = (c << 14 | c >>> 18) + d << 0; - b += (d ^ (a & (c ^ d))) + blocks[8] + 1163531501; - b = (b << 20 | b >>> 12) + c << 0; - a += (c ^ (d & (b ^ c))) + blocks[13] - 1444681467; - a = (a << 5 | a >>> 27) + b << 0; - d += (b ^ (c & (a ^ b))) + blocks[2] - 51403784; - d = (d << 9 | d >>> 23) + a << 0; - c += (a ^ (b & (d ^ a))) + blocks[7] + 1735328473; - c = (c << 14 | c >>> 18) + d << 0; - b += (d ^ (a & (c ^ d))) + blocks[12] - 1926607734; - b = (b << 20 | b >>> 12) + c << 0; - bc = b ^ c; - a += (bc ^ d) + blocks[5] - 378558; - a = (a << 4 | a >>> 28) + b << 0; - d += (bc ^ a) + blocks[8] - 2022574463; - d = (d << 11 | d >>> 21) + a << 0; - da = d ^ a; - c += (da ^ b) + blocks[11] + 1839030562; - c = (c << 16 | c >>> 16) + d << 0; - b += (da ^ c) + blocks[14] - 35309556; - b = (b << 23 | b >>> 9) + c << 0; - bc = b ^ c; - a += (bc ^ d) + blocks[1] - 1530992060; - a = (a << 4 | a >>> 28) + b << 0; - d += (bc ^ a) + blocks[4] + 1272893353; - d = (d << 11 | d >>> 21) + a << 0; - da = d ^ a; - c += (da ^ b) + blocks[7] - 155497632; - c = (c << 16 | c >>> 16) + d << 0; - b += (da ^ c) + blocks[10] - 1094730640; - b = (b << 23 | b >>> 9) + c << 0; - bc = b ^ c; - a += (bc ^ d) + blocks[13] + 681279174; - a = (a << 4 | a >>> 28) + b << 0; - d += (bc ^ a) + blocks[0] - 358537222; - d = (d << 11 | d >>> 21) + a << 0; - da = d ^ a; - c += (da ^ b) + blocks[3] - 722521979; - c = (c << 16 | c >>> 16) + d << 0; - b += (da ^ c) + blocks[6] + 76029189; - b = (b << 23 | b >>> 9) + c << 0; - bc = b ^ c; - a += (bc ^ d) + blocks[9] - 640364487; - a = (a << 4 | a >>> 28) + b << 0; - d += (bc ^ a) + blocks[12] - 421815835; - d = (d << 11 | d >>> 21) + a << 0; - da = d ^ a; - c += (da ^ b) + blocks[15] + 530742520; - c = (c << 16 | c >>> 16) + d << 0; - b += (da ^ c) + blocks[2] - 995338651; - b = (b << 23 | b >>> 9) + c << 0; - a += (c ^ (b | ~d)) + blocks[0] - 198630844; - a = (a << 6 | a >>> 26) + b << 0; - d += (b ^ (a | ~c)) + blocks[7] + 1126891415; - d = (d << 10 | d >>> 22) + a << 0; - c += (a ^ (d | ~b)) + blocks[14] - 1416354905; - c = (c << 15 | c >>> 17) + d << 0; - b += (d ^ (c | ~a)) + blocks[5] - 57434055; - b = (b << 21 | b >>> 11) + c << 0; - a += (c ^ (b | ~d)) + blocks[12] + 1700485571; - a = (a << 6 | a >>> 26) + b << 0; - d += (b ^ (a | ~c)) + blocks[3] - 1894986606; - d = (d << 10 | d >>> 22) + a << 0; - c += (a ^ (d | ~b)) + blocks[10] - 1051523; - c = (c << 15 | c >>> 17) + d << 0; - b += (d ^ (c | ~a)) + blocks[1] - 2054922799; - b = (b << 21 | b >>> 11) + c << 0; - a += (c ^ (b | ~d)) + blocks[8] + 1873313359; - a = (a << 6 | a >>> 26) + b << 0; - d += (b ^ (a | ~c)) + blocks[15] - 30611744; - d = (d << 10 | d >>> 22) + a << 0; - c += (a ^ (d | ~b)) + blocks[6] - 1560198380; - c = (c << 15 | c >>> 17) + d << 0; - b += (d ^ (c | ~a)) + blocks[13] + 1309151649; - b = (b << 21 | b >>> 11) + c << 0; - a += (c ^ (b | ~d)) + blocks[4] - 145523070; - a = (a << 6 | a >>> 26) + b << 0; - d += (b ^ (a | ~c)) + blocks[11] - 1120210379; - d = (d << 10 | d >>> 22) + a << 0; - c += (a ^ (d | ~b)) + blocks[2] + 718787259; - c = (c << 15 | c >>> 17) + d << 0; - b += (d ^ (c | ~a)) + blocks[9] - 343485551; - b = (b << 21 | b >>> 11) + c << 0; - - if (this.first) { - this.h0 = a + 1732584193 << 0; - this.h1 = b - 271733879 << 0; - this.h2 = c - 1732584194 << 0; - this.h3 = d + 271733878 << 0; - this.first = false; - } else { - this.h0 = this.h0 + a << 0; - this.h1 = this.h1 + b << 0; - this.h2 = this.h2 + c << 0; - this.h3 = this.h3 + d << 0; - } - }; - - /** - * @method hex - * @memberof Md5 - * @instance - * @description Output hash as hex string - * @returns {String} Hex string - * @see {@link md5.hex} - * @example - * hash.hex(); - */ - Md5.prototype.hex = function () { - this.finalize(); - - var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3; - - return HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] + - HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] + - HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] + - HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] + - HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] + - HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] + - HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] + - HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] + - HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] + - HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] + - HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] + - HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] + - HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] + - HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] + - HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] + - HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F]; - }; - - /** - * @method toString - * @memberof Md5 - * @instance - * @description Output hash as hex string - * @returns {String} Hex string - * @see {@link md5.hex} - * @example - * hash.toString(); - */ - Md5.prototype.toString = Md5.prototype.hex; - - /** - * @method digest - * @memberof Md5 - * @instance - * @description Output hash as bytes array - * @returns {Array} Bytes array - * @see {@link md5.digest} - * @example - * hash.digest(); - */ - Md5.prototype.digest = function () { - this.finalize(); - - var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3; - return [ - h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 24) & 0xFF, - h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 24) & 0xFF, - h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 24) & 0xFF, - h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 24) & 0xFF - ]; - }; - - /** - * @method array - * @memberof Md5 - * @instance - * @description Output hash as bytes array - * @returns {Array} Bytes array - * @see {@link md5.array} - * @example - * hash.array(); - */ - Md5.prototype.array = Md5.prototype.digest; - - /** - * @method arrayBuffer - * @memberof Md5 - * @instance - * @description Output hash as ArrayBuffer - * @returns {ArrayBuffer} ArrayBuffer - * @see {@link md5.arrayBuffer} - * @example - * hash.arrayBuffer(); - */ - Md5.prototype.arrayBuffer = function () { - this.finalize(); - - var buffer = new ArrayBuffer(16); - var blocks = new Uint32Array(buffer); - blocks[0] = this.h0; - blocks[1] = this.h1; - blocks[2] = this.h2; - blocks[3] = this.h3; - return buffer; - }; - - /** - * @method buffer - * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead. - * @memberof Md5 - * @instance - * @description Output hash as ArrayBuffer - * @returns {ArrayBuffer} ArrayBuffer - * @see {@link md5.buffer} - * @example - * hash.buffer(); - */ - Md5.prototype.buffer = Md5.prototype.arrayBuffer; - - /** - * @method base64 - * @memberof Md5 - * @instance - * @description Output hash as base64 string - * @returns {String} base64 string - * @see {@link md5.base64} - * @example - * hash.base64(); - */ - Md5.prototype.base64 = function () { - var v1, v2, v3, base64Str = '', bytes = this.array(); - for (var i = 0; i < 15;) { - v1 = bytes[i++]; - v2 = bytes[i++]; - v3 = bytes[i++]; - base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] + - BASE64_ENCODE_CHAR[(v1 << 4 | v2 >>> 4) & 63] + - BASE64_ENCODE_CHAR[(v2 << 2 | v3 >>> 6) & 63] + - BASE64_ENCODE_CHAR[v3 & 63]; - } - v1 = bytes[i]; - base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] + - BASE64_ENCODE_CHAR[(v1 << 4) & 63] + - '=='; - return base64Str; - }; - - var exports = createMethod(); - - if (COMMON_JS) { - module.exports = exports; - } else { - /** - * @method md5 - * @description Md5 hash function, export to global in browsers. - * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash - * @returns {String} md5 hashes - * @example - * md5(''); // d41d8cd98f00b204e9800998ecf8427e - * md5('The quick brown fox jumps over the lazy dog'); // 9e107d9d372bb6826bd81d3542a419d6 - * md5('The quick brown fox jumps over the lazy dog.'); // e4d909c290d0fb1ca068ffaddf22cbd0 - * - * // It also supports UTF-8 encoding - * md5('中文'); // a7bac2239fcdcb3a067903d8077c4a07 - * - * // It also supports byte `Array`, `Uint8Array`, `ArrayBuffer` - * md5([]); // d41d8cd98f00b204e9800998ecf8427e - * md5(new Uint8Array([])); // d41d8cd98f00b204e9800998ecf8427e - */ - root.md5 = exports; - if (AMD) { - !(__WEBPACK_AMD_DEFINE_RESULT__ = (function () { - return exports; +/* WEBPACK VAR INJECTION */(function(process, global) {var __WEBPACK_AMD_DEFINE_RESULT__;/* https://github.com/emn178/js-md5 */ +(function () { + 'use strict'; + + var ERROR = 'input is invalid type'; + var WINDOW = typeof window === 'object'; + var root = WINDOW ? window : {}; + if (root.JS_MD5_NO_WINDOW) { + WINDOW = false; + } + var WEB_WORKER = !WINDOW && typeof self === 'object'; + var NODE_JS = !root.JS_MD5_NO_NODE_JS && typeof process === 'object' && process.versions && process.versions.node; + if (NODE_JS) { + root = global; + } else if (WEB_WORKER) { + root = self; + } + var COMMON_JS = !root.JS_MD5_NO_COMMON_JS && typeof module === 'object' && module.exports; + var AMD = "function" === 'function' && __webpack_require__(10); + var ARRAY_BUFFER = !root.JS_MD5_NO_ARRAY_BUFFER && typeof ArrayBuffer !== 'undefined'; + var HEX_CHARS = '0123456789abcdef'.split(''); + var EXTRA = [128, 32768, 8388608, -2147483648]; + var SHIFT = [0, 8, 16, 24]; + var OUTPUT_TYPES = ['hex', 'array', 'digest', 'buffer', 'arrayBuffer', 'base64']; + var BASE64_ENCODE_CHAR = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split(''); + + var blocks = [], buffer8; + if (ARRAY_BUFFER) { + var buffer = new ArrayBuffer(68); + buffer8 = new Uint8Array(buffer); + blocks = new Uint32Array(buffer); + } + + if (root.JS_MD5_NO_NODE_JS || !Array.isArray) { + Array.isArray = function (obj) { + return Object.prototype.toString.call(obj) === '[object Array]'; + }; + } + + if (ARRAY_BUFFER && (root.JS_MD5_NO_ARRAY_BUFFER_IS_VIEW || !ArrayBuffer.isView)) { + ArrayBuffer.isView = function (obj) { + return typeof obj === 'object' && obj.buffer && obj.buffer.constructor === ArrayBuffer; + }; + } + + /** + * @method hex + * @memberof md5 + * @description Output hash as hex string + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {String} Hex string + * @example + * md5.hex('The quick brown fox jumps over the lazy dog'); + * // equal to + * md5('The quick brown fox jumps over the lazy dog'); + */ + /** + * @method digest + * @memberof md5 + * @description Output hash as bytes array + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {Array} Bytes array + * @example + * md5.digest('The quick brown fox jumps over the lazy dog'); + */ + /** + * @method array + * @memberof md5 + * @description Output hash as bytes array + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {Array} Bytes array + * @example + * md5.array('The quick brown fox jumps over the lazy dog'); + */ + /** + * @method arrayBuffer + * @memberof md5 + * @description Output hash as ArrayBuffer + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {ArrayBuffer} ArrayBuffer + * @example + * md5.arrayBuffer('The quick brown fox jumps over the lazy dog'); + */ + /** + * @method buffer + * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead. + * @memberof md5 + * @description Output hash as ArrayBuffer + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {ArrayBuffer} ArrayBuffer + * @example + * md5.buffer('The quick brown fox jumps over the lazy dog'); + */ + /** + * @method base64 + * @memberof md5 + * @description Output hash as base64 string + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {String} base64 string + * @example + * md5.base64('The quick brown fox jumps over the lazy dog'); + */ + var createOutputMethod = function (outputType) { + return function (message) { + return new Md5(true).update(message)[outputType](); + }; + }; + + /** + * @method create + * @memberof md5 + * @description Create Md5 object + * @returns {Md5} Md5 object. + * @example + * var hash = md5.create(); + */ + /** + * @method update + * @memberof md5 + * @description Create and update Md5 object + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {Md5} Md5 object. + * @example + * var hash = md5.update('The quick brown fox jumps over the lazy dog'); + * // equal to + * var hash = md5.create(); + * hash.update('The quick brown fox jumps over the lazy dog'); + */ + var createMethod = function () { + var method = createOutputMethod('hex'); + if (NODE_JS) { + method = nodeWrap(method); + } + method.getCtx = method.create = function () { + return new Md5(); + }; + method.update = function (message) { + return method.create().update(message); + }; + for (var i = 0; i < OUTPUT_TYPES.length; ++i) { + var type = OUTPUT_TYPES[i]; + method[type] = createOutputMethod(type); + } + return method; + }; + + var nodeWrap = function (method) { + var crypto = eval("require('crypto')"); + var Buffer = eval("require('buffer').Buffer"); + var nodeMethod = function (message) { + if (typeof message === 'string') { + return crypto.createHash('md5').update(message, 'utf8').digest('hex'); + } else { + if (message === null || message === undefined) { + throw ERROR; + } else if (message.constructor === ArrayBuffer) { + message = new Uint8Array(message); + } + } + if (Array.isArray(message) || ArrayBuffer.isView(message) || + message.constructor === Buffer) { + return crypto.createHash('md5').update(new Buffer(message)).digest('hex'); + } else { + return method(message); + } + }; + return nodeMethod; + }; + + /** + * Md5 class + * @class Md5 + * @description This is internal class. + * @see {@link md5.create} + */ + function Md5(sharedMemory) { + if (sharedMemory) { + blocks[0] = blocks[16] = blocks[1] = blocks[2] = blocks[3] = + blocks[4] = blocks[5] = blocks[6] = blocks[7] = + blocks[8] = blocks[9] = blocks[10] = blocks[11] = + blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; + this.blocks = blocks; + this.buffer8 = buffer8; + } else { + if (ARRAY_BUFFER) { + var buffer = new ArrayBuffer(68); + this.buffer8 = new Uint8Array(buffer); + this.blocks = new Uint32Array(buffer); + } else { + this.blocks = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + } + } + this.h0 = this.h1 = this.h2 = this.h3 = this.start = this.bytes = this.hBytes = 0; + this.finalized = this.hashed = false; + this.first = true; + } + + /** + * @method update + * @memberof Md5 + * @instance + * @description Update hash + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {Md5} Md5 object. + * @see {@link md5.update} + */ + Md5.prototype.update = function (message) { + if (this.finalized) { + return; + } + + var notString, type = typeof message; + if (type !== 'string') { + if (type === 'object') { + if (message === null) { + throw ERROR; + } else if (ARRAY_BUFFER && (message.constructor === ArrayBuffer || message.constructor.name === 'ArrayBuffer')) { + message = new Uint8Array(message); + } else if (!Array.isArray(message)) { + if (!ARRAY_BUFFER || !ArrayBuffer.isView(message)) { + throw ERROR; + } + } + } else { + throw ERROR; + } + notString = true; + } + var code, index = 0, i, length = message.length, blocks = this.blocks; + var buffer8 = this.buffer8; + + while (index < length) { + if (this.hashed) { + this.hashed = false; + blocks[0] = blocks[16]; + blocks[16] = blocks[1] = blocks[2] = blocks[3] = + blocks[4] = blocks[5] = blocks[6] = blocks[7] = + blocks[8] = blocks[9] = blocks[10] = blocks[11] = + blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; + } + + if (notString) { + if (ARRAY_BUFFER) { + for (i = this.start; index < length && i < 64; ++index) { + buffer8[i++] = message[index]; + } + } else { + for (i = this.start; index < length && i < 64; ++index) { + blocks[i >> 2] |= message[index] << SHIFT[i++ & 3]; + } + } + } else { + if (ARRAY_BUFFER) { + for (i = this.start; index < length && i < 64; ++index) { + code = message.charCodeAt(index); + if (code < 0x80) { + buffer8[i++] = code; + } else if (code < 0x800) { + buffer8[i++] = 0xc0 | (code >> 6); + buffer8[i++] = 0x80 | (code & 0x3f); + } else if (code < 0xd800 || code >= 0xe000) { + buffer8[i++] = 0xe0 | (code >> 12); + buffer8[i++] = 0x80 | ((code >> 6) & 0x3f); + buffer8[i++] = 0x80 | (code & 0x3f); + } else { + code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff)); + buffer8[i++] = 0xf0 | (code >> 18); + buffer8[i++] = 0x80 | ((code >> 12) & 0x3f); + buffer8[i++] = 0x80 | ((code >> 6) & 0x3f); + buffer8[i++] = 0x80 | (code & 0x3f); + } + } + } else { + for (i = this.start; index < length && i < 64; ++index) { + code = message.charCodeAt(index); + if (code < 0x80) { + blocks[i >> 2] |= code << SHIFT[i++ & 3]; + } else if (code < 0x800) { + blocks[i >> 2] |= (0xc0 | (code >> 6)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; + } else if (code < 0xd800 || code >= 0xe000) { + blocks[i >> 2] |= (0xe0 | (code >> 12)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; + } else { + code = 0x10000 + (((code & 0x3ff) << 10) | (message.charCodeAt(++index) & 0x3ff)); + blocks[i >> 2] |= (0xf0 | (code >> 18)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | ((code >> 12) & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | ((code >> 6) & 0x3f)) << SHIFT[i++ & 3]; + blocks[i >> 2] |= (0x80 | (code & 0x3f)) << SHIFT[i++ & 3]; + } + } + } + } + this.lastByteIndex = i; + this.bytes += i - this.start; + if (i >= 64) { + this.start = i - 64; + this.hash(); + this.hashed = true; + } else { + this.start = i; + } + } + if (this.bytes > 4294967295) { + this.hBytes += this.bytes / 4294967296 << 0; + this.bytes = this.bytes % 4294967296; + } + return this; + }; + + Md5.prototype.finalize = function () { + if (this.finalized) { + return; + } + this.finalized = true; + var blocks = this.blocks, i = this.lastByteIndex; + blocks[i >> 2] |= EXTRA[i & 3]; + if (i >= 56) { + if (!this.hashed) { + this.hash(); + } + blocks[0] = blocks[16]; + blocks[16] = blocks[1] = blocks[2] = blocks[3] = + blocks[4] = blocks[5] = blocks[6] = blocks[7] = + blocks[8] = blocks[9] = blocks[10] = blocks[11] = + blocks[12] = blocks[13] = blocks[14] = blocks[15] = 0; + } + blocks[14] = this.bytes << 3; + blocks[15] = this.hBytes << 3 | this.bytes >>> 29; + this.hash(); + }; + + Md5.prototype.hash = function () { + var a, b, c, d, bc, da, blocks = this.blocks; + + if (this.first) { + a = blocks[0] - 680876937; + a = (a << 7 | a >>> 25) - 271733879 << 0; + d = (-1732584194 ^ a & 2004318071) + blocks[1] - 117830708; + d = (d << 12 | d >>> 20) + a << 0; + c = (-271733879 ^ (d & (a ^ -271733879))) + blocks[2] - 1126478375; + c = (c << 17 | c >>> 15) + d << 0; + b = (a ^ (c & (d ^ a))) + blocks[3] - 1316259209; + b = (b << 22 | b >>> 10) + c << 0; + } else { + a = this.h0; + b = this.h1; + c = this.h2; + d = this.h3; + a += (d ^ (b & (c ^ d))) + blocks[0] - 680876936; + a = (a << 7 | a >>> 25) + b << 0; + d += (c ^ (a & (b ^ c))) + blocks[1] - 389564586; + d = (d << 12 | d >>> 20) + a << 0; + c += (b ^ (d & (a ^ b))) + blocks[2] + 606105819; + c = (c << 17 | c >>> 15) + d << 0; + b += (a ^ (c & (d ^ a))) + blocks[3] - 1044525330; + b = (b << 22 | b >>> 10) + c << 0; + } + + a += (d ^ (b & (c ^ d))) + blocks[4] - 176418897; + a = (a << 7 | a >>> 25) + b << 0; + d += (c ^ (a & (b ^ c))) + blocks[5] + 1200080426; + d = (d << 12 | d >>> 20) + a << 0; + c += (b ^ (d & (a ^ b))) + blocks[6] - 1473231341; + c = (c << 17 | c >>> 15) + d << 0; + b += (a ^ (c & (d ^ a))) + blocks[7] - 45705983; + b = (b << 22 | b >>> 10) + c << 0; + a += (d ^ (b & (c ^ d))) + blocks[8] + 1770035416; + a = (a << 7 | a >>> 25) + b << 0; + d += (c ^ (a & (b ^ c))) + blocks[9] - 1958414417; + d = (d << 12 | d >>> 20) + a << 0; + c += (b ^ (d & (a ^ b))) + blocks[10] - 42063; + c = (c << 17 | c >>> 15) + d << 0; + b += (a ^ (c & (d ^ a))) + blocks[11] - 1990404162; + b = (b << 22 | b >>> 10) + c << 0; + a += (d ^ (b & (c ^ d))) + blocks[12] + 1804603682; + a = (a << 7 | a >>> 25) + b << 0; + d += (c ^ (a & (b ^ c))) + blocks[13] - 40341101; + d = (d << 12 | d >>> 20) + a << 0; + c += (b ^ (d & (a ^ b))) + blocks[14] - 1502002290; + c = (c << 17 | c >>> 15) + d << 0; + b += (a ^ (c & (d ^ a))) + blocks[15] + 1236535329; + b = (b << 22 | b >>> 10) + c << 0; + a += (c ^ (d & (b ^ c))) + blocks[1] - 165796510; + a = (a << 5 | a >>> 27) + b << 0; + d += (b ^ (c & (a ^ b))) + blocks[6] - 1069501632; + d = (d << 9 | d >>> 23) + a << 0; + c += (a ^ (b & (d ^ a))) + blocks[11] + 643717713; + c = (c << 14 | c >>> 18) + d << 0; + b += (d ^ (a & (c ^ d))) + blocks[0] - 373897302; + b = (b << 20 | b >>> 12) + c << 0; + a += (c ^ (d & (b ^ c))) + blocks[5] - 701558691; + a = (a << 5 | a >>> 27) + b << 0; + d += (b ^ (c & (a ^ b))) + blocks[10] + 38016083; + d = (d << 9 | d >>> 23) + a << 0; + c += (a ^ (b & (d ^ a))) + blocks[15] - 660478335; + c = (c << 14 | c >>> 18) + d << 0; + b += (d ^ (a & (c ^ d))) + blocks[4] - 405537848; + b = (b << 20 | b >>> 12) + c << 0; + a += (c ^ (d & (b ^ c))) + blocks[9] + 568446438; + a = (a << 5 | a >>> 27) + b << 0; + d += (b ^ (c & (a ^ b))) + blocks[14] - 1019803690; + d = (d << 9 | d >>> 23) + a << 0; + c += (a ^ (b & (d ^ a))) + blocks[3] - 187363961; + c = (c << 14 | c >>> 18) + d << 0; + b += (d ^ (a & (c ^ d))) + blocks[8] + 1163531501; + b = (b << 20 | b >>> 12) + c << 0; + a += (c ^ (d & (b ^ c))) + blocks[13] - 1444681467; + a = (a << 5 | a >>> 27) + b << 0; + d += (b ^ (c & (a ^ b))) + blocks[2] - 51403784; + d = (d << 9 | d >>> 23) + a << 0; + c += (a ^ (b & (d ^ a))) + blocks[7] + 1735328473; + c = (c << 14 | c >>> 18) + d << 0; + b += (d ^ (a & (c ^ d))) + blocks[12] - 1926607734; + b = (b << 20 | b >>> 12) + c << 0; + bc = b ^ c; + a += (bc ^ d) + blocks[5] - 378558; + a = (a << 4 | a >>> 28) + b << 0; + d += (bc ^ a) + blocks[8] - 2022574463; + d = (d << 11 | d >>> 21) + a << 0; + da = d ^ a; + c += (da ^ b) + blocks[11] + 1839030562; + c = (c << 16 | c >>> 16) + d << 0; + b += (da ^ c) + blocks[14] - 35309556; + b = (b << 23 | b >>> 9) + c << 0; + bc = b ^ c; + a += (bc ^ d) + blocks[1] - 1530992060; + a = (a << 4 | a >>> 28) + b << 0; + d += (bc ^ a) + blocks[4] + 1272893353; + d = (d << 11 | d >>> 21) + a << 0; + da = d ^ a; + c += (da ^ b) + blocks[7] - 155497632; + c = (c << 16 | c >>> 16) + d << 0; + b += (da ^ c) + blocks[10] - 1094730640; + b = (b << 23 | b >>> 9) + c << 0; + bc = b ^ c; + a += (bc ^ d) + blocks[13] + 681279174; + a = (a << 4 | a >>> 28) + b << 0; + d += (bc ^ a) + blocks[0] - 358537222; + d = (d << 11 | d >>> 21) + a << 0; + da = d ^ a; + c += (da ^ b) + blocks[3] - 722521979; + c = (c << 16 | c >>> 16) + d << 0; + b += (da ^ c) + blocks[6] + 76029189; + b = (b << 23 | b >>> 9) + c << 0; + bc = b ^ c; + a += (bc ^ d) + blocks[9] - 640364487; + a = (a << 4 | a >>> 28) + b << 0; + d += (bc ^ a) + blocks[12] - 421815835; + d = (d << 11 | d >>> 21) + a << 0; + da = d ^ a; + c += (da ^ b) + blocks[15] + 530742520; + c = (c << 16 | c >>> 16) + d << 0; + b += (da ^ c) + blocks[2] - 995338651; + b = (b << 23 | b >>> 9) + c << 0; + a += (c ^ (b | ~d)) + blocks[0] - 198630844; + a = (a << 6 | a >>> 26) + b << 0; + d += (b ^ (a | ~c)) + blocks[7] + 1126891415; + d = (d << 10 | d >>> 22) + a << 0; + c += (a ^ (d | ~b)) + blocks[14] - 1416354905; + c = (c << 15 | c >>> 17) + d << 0; + b += (d ^ (c | ~a)) + blocks[5] - 57434055; + b = (b << 21 | b >>> 11) + c << 0; + a += (c ^ (b | ~d)) + blocks[12] + 1700485571; + a = (a << 6 | a >>> 26) + b << 0; + d += (b ^ (a | ~c)) + blocks[3] - 1894986606; + d = (d << 10 | d >>> 22) + a << 0; + c += (a ^ (d | ~b)) + blocks[10] - 1051523; + c = (c << 15 | c >>> 17) + d << 0; + b += (d ^ (c | ~a)) + blocks[1] - 2054922799; + b = (b << 21 | b >>> 11) + c << 0; + a += (c ^ (b | ~d)) + blocks[8] + 1873313359; + a = (a << 6 | a >>> 26) + b << 0; + d += (b ^ (a | ~c)) + blocks[15] - 30611744; + d = (d << 10 | d >>> 22) + a << 0; + c += (a ^ (d | ~b)) + blocks[6] - 1560198380; + c = (c << 15 | c >>> 17) + d << 0; + b += (d ^ (c | ~a)) + blocks[13] + 1309151649; + b = (b << 21 | b >>> 11) + c << 0; + a += (c ^ (b | ~d)) + blocks[4] - 145523070; + a = (a << 6 | a >>> 26) + b << 0; + d += (b ^ (a | ~c)) + blocks[11] - 1120210379; + d = (d << 10 | d >>> 22) + a << 0; + c += (a ^ (d | ~b)) + blocks[2] + 718787259; + c = (c << 15 | c >>> 17) + d << 0; + b += (d ^ (c | ~a)) + blocks[9] - 343485551; + b = (b << 21 | b >>> 11) + c << 0; + + if (this.first) { + this.h0 = a + 1732584193 << 0; + this.h1 = b - 271733879 << 0; + this.h2 = c - 1732584194 << 0; + this.h3 = d + 271733878 << 0; + this.first = false; + } else { + this.h0 = this.h0 + a << 0; + this.h1 = this.h1 + b << 0; + this.h2 = this.h2 + c << 0; + this.h3 = this.h3 + d << 0; + } + }; + + /** + * @method hex + * @memberof Md5 + * @instance + * @description Output hash as hex string + * @returns {String} Hex string + * @see {@link md5.hex} + * @example + * hash.hex(); + */ + Md5.prototype.hex = function () { + this.finalize(); + + var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3; + + return HEX_CHARS[(h0 >> 4) & 0x0F] + HEX_CHARS[h0 & 0x0F] + + HEX_CHARS[(h0 >> 12) & 0x0F] + HEX_CHARS[(h0 >> 8) & 0x0F] + + HEX_CHARS[(h0 >> 20) & 0x0F] + HEX_CHARS[(h0 >> 16) & 0x0F] + + HEX_CHARS[(h0 >> 28) & 0x0F] + HEX_CHARS[(h0 >> 24) & 0x0F] + + HEX_CHARS[(h1 >> 4) & 0x0F] + HEX_CHARS[h1 & 0x0F] + + HEX_CHARS[(h1 >> 12) & 0x0F] + HEX_CHARS[(h1 >> 8) & 0x0F] + + HEX_CHARS[(h1 >> 20) & 0x0F] + HEX_CHARS[(h1 >> 16) & 0x0F] + + HEX_CHARS[(h1 >> 28) & 0x0F] + HEX_CHARS[(h1 >> 24) & 0x0F] + + HEX_CHARS[(h2 >> 4) & 0x0F] + HEX_CHARS[h2 & 0x0F] + + HEX_CHARS[(h2 >> 12) & 0x0F] + HEX_CHARS[(h2 >> 8) & 0x0F] + + HEX_CHARS[(h2 >> 20) & 0x0F] + HEX_CHARS[(h2 >> 16) & 0x0F] + + HEX_CHARS[(h2 >> 28) & 0x0F] + HEX_CHARS[(h2 >> 24) & 0x0F] + + HEX_CHARS[(h3 >> 4) & 0x0F] + HEX_CHARS[h3 & 0x0F] + + HEX_CHARS[(h3 >> 12) & 0x0F] + HEX_CHARS[(h3 >> 8) & 0x0F] + + HEX_CHARS[(h3 >> 20) & 0x0F] + HEX_CHARS[(h3 >> 16) & 0x0F] + + HEX_CHARS[(h3 >> 28) & 0x0F] + HEX_CHARS[(h3 >> 24) & 0x0F]; + }; + + /** + * @method toString + * @memberof Md5 + * @instance + * @description Output hash as hex string + * @returns {String} Hex string + * @see {@link md5.hex} + * @example + * hash.toString(); + */ + Md5.prototype.toString = Md5.prototype.hex; + + /** + * @method digest + * @memberof Md5 + * @instance + * @description Output hash as bytes array + * @returns {Array} Bytes array + * @see {@link md5.digest} + * @example + * hash.digest(); + */ + Md5.prototype.digest = function () { + this.finalize(); + + var h0 = this.h0, h1 = this.h1, h2 = this.h2, h3 = this.h3; + return [ + h0 & 0xFF, (h0 >> 8) & 0xFF, (h0 >> 16) & 0xFF, (h0 >> 24) & 0xFF, + h1 & 0xFF, (h1 >> 8) & 0xFF, (h1 >> 16) & 0xFF, (h1 >> 24) & 0xFF, + h2 & 0xFF, (h2 >> 8) & 0xFF, (h2 >> 16) & 0xFF, (h2 >> 24) & 0xFF, + h3 & 0xFF, (h3 >> 8) & 0xFF, (h3 >> 16) & 0xFF, (h3 >> 24) & 0xFF + ]; + }; + + /** + * @method array + * @memberof Md5 + * @instance + * @description Output hash as bytes array + * @returns {Array} Bytes array + * @see {@link md5.array} + * @example + * hash.array(); + */ + Md5.prototype.array = Md5.prototype.digest; + + /** + * @method arrayBuffer + * @memberof Md5 + * @instance + * @description Output hash as ArrayBuffer + * @returns {ArrayBuffer} ArrayBuffer + * @see {@link md5.arrayBuffer} + * @example + * hash.arrayBuffer(); + */ + Md5.prototype.arrayBuffer = function () { + this.finalize(); + + var buffer = new ArrayBuffer(16); + var blocks = new Uint32Array(buffer); + blocks[0] = this.h0; + blocks[1] = this.h1; + blocks[2] = this.h2; + blocks[3] = this.h3; + return buffer; + }; + + /** + * @method buffer + * @deprecated This maybe confuse with Buffer in node.js. Please use arrayBuffer instead. + * @memberof Md5 + * @instance + * @description Output hash as ArrayBuffer + * @returns {ArrayBuffer} ArrayBuffer + * @see {@link md5.buffer} + * @example + * hash.buffer(); + */ + Md5.prototype.buffer = Md5.prototype.arrayBuffer; + + /** + * @method base64 + * @memberof Md5 + * @instance + * @description Output hash as base64 string + * @returns {String} base64 string + * @see {@link md5.base64} + * @example + * hash.base64(); + */ + Md5.prototype.base64 = function () { + var v1, v2, v3, base64Str = '', bytes = this.array(); + for (var i = 0; i < 15;) { + v1 = bytes[i++]; + v2 = bytes[i++]; + v3 = bytes[i++]; + base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] + + BASE64_ENCODE_CHAR[(v1 << 4 | v2 >>> 4) & 63] + + BASE64_ENCODE_CHAR[(v2 << 2 | v3 >>> 6) & 63] + + BASE64_ENCODE_CHAR[v3 & 63]; + } + v1 = bytes[i]; + base64Str += BASE64_ENCODE_CHAR[v1 >>> 2] + + BASE64_ENCODE_CHAR[(v1 << 4) & 63] + + '=='; + return base64Str; + }; + + var exports = createMethod(); + + if (COMMON_JS) { + module.exports = exports; + } else { + /** + * @method md5 + * @description Md5 hash function, export to global in browsers. + * @param {String|Array|Uint8Array|ArrayBuffer} message message to hash + * @returns {String} md5 hashes + * @example + * md5(''); // d41d8cd98f00b204e9800998ecf8427e + * md5('The quick brown fox jumps over the lazy dog'); // 9e107d9d372bb6826bd81d3542a419d6 + * md5('The quick brown fox jumps over the lazy dog.'); // e4d909c290d0fb1ca068ffaddf22cbd0 + * + * // It also supports UTF-8 encoding + * md5('中文'); // a7bac2239fcdcb3a067903d8077c4a07 + * + * // It also supports byte `Array`, `Uint8Array`, `ArrayBuffer` + * md5([]); // d41d8cd98f00b204e9800998ecf8427e + * md5(new Uint8Array([])); // d41d8cd98f00b204e9800998ecf8427e + */ + root.md5 = exports; + if (AMD) { + !(__WEBPACK_AMD_DEFINE_RESULT__ = (function () { + return exports; }).call(exports, __webpack_require__, exports, module), - __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); - } - } -})(); + __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); + } + } +})(); /* WEBPACK VAR INJECTION */}.call(exports, __webpack_require__(9), __webpack_require__(1))) @@ -3229,733 +3229,733 @@ module.exports = __webpack_amd_options__; /* 11 */ /***/ (function(module, exports) { -/* - CryptoJS v3.1.2 - code.google.com/p/crypto-js - (c) 2009-2013 by Jeff Mott. All rights reserved. - code.google.com/p/crypto-js/wiki/License - */ -var CryptoJS=CryptoJS||function(g,l){var e={},d=e.lib={},m=function(){},k=d.Base={extend:function(a){m.prototype=this;var c=new m;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}}, - p=d.WordArray=k.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=l?c:4*a.length},toString:function(a){return(a||n).stringify(this)},concat:function(a){var c=this.words,q=a.words,f=this.sigBytes;a=a.sigBytes;this.clamp();if(f%4)for(var b=0;b>>2]|=(q[b>>>2]>>>24-8*(b%4)&255)<<24-8*((f+b)%4);else if(65535>>2]=q[b>>>2];else c.push.apply(c,q);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<< - 32-8*(c%4);a.length=g.ceil(c/4)},clone:function(){var a=k.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],b=0;b>>2]>>>24-8*(f%4)&255;b.push((d>>>4).toString(16));b.push((d&15).toString(16))}return b.join("")},parse:function(a){for(var c=a.length,b=[],f=0;f>>3]|=parseInt(a.substr(f, - 2),16)<<24-4*(f%8);return new p.init(b,c/2)}},j=b.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var b=[],f=0;f>>2]>>>24-8*(f%4)&255));return b.join("")},parse:function(a){for(var c=a.length,b=[],f=0;f>>2]|=(a.charCodeAt(f)&255)<<24-8*(f%4);return new p.init(b,c)}},h=b.Utf8={stringify:function(a){try{return decodeURIComponent(escape(j.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return j.parse(unescape(encodeURIComponent(a)))}}, - r=d.BufferedBlockAlgorithm=k.extend({reset:function(){this._data=new p.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=h.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,b=c.words,f=c.sigBytes,d=this.blockSize,e=f/(4*d),e=a?g.ceil(e):g.max((e|0)-this._minBufferSize,0);a=e*d;f=g.min(4*a,f);if(a){for(var k=0;ka;a++){if(16>a)m[a]=d[e+a]|0;else{var c=m[a-3]^m[a-8]^m[a-14]^m[a-16];m[a]=c<<1|c>>>31}c=(n<<5|n>>>27)+l+m[a];c=20>a?c+((j&h|~j&g)+1518500249):40>a?c+((j^h^g)+1859775393):60>a?c+((j&h|j&g|h&g)-1894007588):c+((j^h^ -g)-899497514);l=g;g=h;h=j<<30|j>>>2;j=n;n=c}b[0]=b[0]+n|0;b[1]=b[1]+j|0;b[2]=b[2]+h|0;b[3]=b[3]+g|0;b[4]=b[4]+l|0},_doFinalize:function(){var d=this._data,e=d.words,b=8*this._nDataBytes,g=8*d.sigBytes;e[g>>>5]|=128<<24-g%32;e[(g+64>>>9<<4)+14]=Math.floor(b/4294967296);e[(g+64>>>9<<4)+15]=b;d.sigBytes=4*e.length;this._process();return this._hash},clone:function(){var e=d.clone.call(this);e._hash=this._hash.clone();return e}});g.SHA1=d._createHelper(l);g.HmacSHA1=d._createHmacHelper(l)})(); -(function(){var g=CryptoJS,l=g.enc.Utf8;g.algo.HMAC=g.lib.Base.extend({init:function(e,d){e=this._hasher=new e.init;"string"==typeof d&&(d=l.parse(d));var g=e.blockSize,k=4*g;d.sigBytes>k&&(d=e.finalize(d));d.clamp();for(var p=this._oKey=d.clone(),b=this._iKey=d.clone(),n=p.words,j=b.words,h=0;h>> 2] >>> (24 - (i % 4) * 8)) & 0xff; - var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; - var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; - - var triplet = (byte1 << 16) | (byte2 << 8) | byte3; - - for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) { - base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); - } - } - - // Add padding - var paddingChar = map.charAt(64); - if (paddingChar) { - while (base64Chars.length % 4) { - base64Chars.push(paddingChar); - } - } - - return base64Chars.join(''); - }, - - /** - * Converts a Base64 string to a word array. - * - * @param {string} base64Str The Base64 string. - * - * @return {WordArray} The word array. - * - * @static - * - * @example - * - * var wordArray = CryptoJS.enc.Base64.parse(base64String); - */ - parse: function (base64Str) { - // Shortcuts - var base64StrLength = base64Str.length; - var map = this._map; - - // Ignore padding - var paddingChar = map.charAt(64); - if (paddingChar) { - var paddingIndex = base64Str.indexOf(paddingChar); - if (paddingIndex != -1) { - base64StrLength = paddingIndex; - } - } - - // Convert - var words = []; - var nBytes = 0; - for (var i = 0; i < base64StrLength; i++) { - if (i % 4) { - var bits1 = map.indexOf(base64Str.charAt(i - 1)) << ((i % 4) * 2); - var bits2 = map.indexOf(base64Str.charAt(i)) >>> (6 - (i % 4) * 2); - words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8); - nBytes++; - } - } - - return WordArray.create(words, nBytes); - }, - - _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' - }; -}()); - -module.exports = CryptoJS; +/* + CryptoJS v3.1.2 + code.google.com/p/crypto-js + (c) 2009-2013 by Jeff Mott. All rights reserved. + code.google.com/p/crypto-js/wiki/License + */ +var CryptoJS=CryptoJS||function(g,l){var e={},d=e.lib={},m=function(){},k=d.Base={extend:function(a){m.prototype=this;var c=new m;a&&c.mixIn(a);c.hasOwnProperty("init")||(c.init=function(){c.$super.init.apply(this,arguments)});c.init.prototype=c;c.$super=this;return c},create:function(){var a=this.extend();a.init.apply(a,arguments);return a},init:function(){},mixIn:function(a){for(var c in a)a.hasOwnProperty(c)&&(this[c]=a[c]);a.hasOwnProperty("toString")&&(this.toString=a.toString)},clone:function(){return this.init.prototype.extend(this)}}, + p=d.WordArray=k.extend({init:function(a,c){a=this.words=a||[];this.sigBytes=c!=l?c:4*a.length},toString:function(a){return(a||n).stringify(this)},concat:function(a){var c=this.words,q=a.words,f=this.sigBytes;a=a.sigBytes;this.clamp();if(f%4)for(var b=0;b>>2]|=(q[b>>>2]>>>24-8*(b%4)&255)<<24-8*((f+b)%4);else if(65535>>2]=q[b>>>2];else c.push.apply(c,q);this.sigBytes+=a;return this},clamp:function(){var a=this.words,c=this.sigBytes;a[c>>>2]&=4294967295<< + 32-8*(c%4);a.length=g.ceil(c/4)},clone:function(){var a=k.clone.call(this);a.words=this.words.slice(0);return a},random:function(a){for(var c=[],b=0;b>>2]>>>24-8*(f%4)&255;b.push((d>>>4).toString(16));b.push((d&15).toString(16))}return b.join("")},parse:function(a){for(var c=a.length,b=[],f=0;f>>3]|=parseInt(a.substr(f, + 2),16)<<24-4*(f%8);return new p.init(b,c/2)}},j=b.Latin1={stringify:function(a){var c=a.words;a=a.sigBytes;for(var b=[],f=0;f>>2]>>>24-8*(f%4)&255));return b.join("")},parse:function(a){for(var c=a.length,b=[],f=0;f>>2]|=(a.charCodeAt(f)&255)<<24-8*(f%4);return new p.init(b,c)}},h=b.Utf8={stringify:function(a){try{return decodeURIComponent(escape(j.stringify(a)))}catch(c){throw Error("Malformed UTF-8 data");}},parse:function(a){return j.parse(unescape(encodeURIComponent(a)))}}, + r=d.BufferedBlockAlgorithm=k.extend({reset:function(){this._data=new p.init;this._nDataBytes=0},_append:function(a){"string"==typeof a&&(a=h.parse(a));this._data.concat(a);this._nDataBytes+=a.sigBytes},_process:function(a){var c=this._data,b=c.words,f=c.sigBytes,d=this.blockSize,e=f/(4*d),e=a?g.ceil(e):g.max((e|0)-this._minBufferSize,0);a=e*d;f=g.min(4*a,f);if(a){for(var k=0;ka;a++){if(16>a)m[a]=d[e+a]|0;else{var c=m[a-3]^m[a-8]^m[a-14]^m[a-16];m[a]=c<<1|c>>>31}c=(n<<5|n>>>27)+l+m[a];c=20>a?c+((j&h|~j&g)+1518500249):40>a?c+((j^h^g)+1859775393):60>a?c+((j&h|j&g|h&g)-1894007588):c+((j^h^ +g)-899497514);l=g;g=h;h=j<<30|j>>>2;j=n;n=c}b[0]=b[0]+n|0;b[1]=b[1]+j|0;b[2]=b[2]+h|0;b[3]=b[3]+g|0;b[4]=b[4]+l|0},_doFinalize:function(){var d=this._data,e=d.words,b=8*this._nDataBytes,g=8*d.sigBytes;e[g>>>5]|=128<<24-g%32;e[(g+64>>>9<<4)+14]=Math.floor(b/4294967296);e[(g+64>>>9<<4)+15]=b;d.sigBytes=4*e.length;this._process();return this._hash},clone:function(){var e=d.clone.call(this);e._hash=this._hash.clone();return e}});g.SHA1=d._createHelper(l);g.HmacSHA1=d._createHmacHelper(l)})(); +(function(){var g=CryptoJS,l=g.enc.Utf8;g.algo.HMAC=g.lib.Base.extend({init:function(e,d){e=this._hasher=new e.init;"string"==typeof d&&(d=l.parse(d));var g=e.blockSize,k=4*g;d.sigBytes>k&&(d=e.finalize(d));d.clamp();for(var p=this._oKey=d.clone(),b=this._iKey=d.clone(),n=p.words,j=b.words,h=0;h>> 2] >>> (24 - (i % 4) * 8)) & 0xff; + var byte2 = (words[(i + 1) >>> 2] >>> (24 - ((i + 1) % 4) * 8)) & 0xff; + var byte3 = (words[(i + 2) >>> 2] >>> (24 - ((i + 2) % 4) * 8)) & 0xff; + + var triplet = (byte1 << 16) | (byte2 << 8) | byte3; + + for (var j = 0; (j < 4) && (i + j * 0.75 < sigBytes); j++) { + base64Chars.push(map.charAt((triplet >>> (6 * (3 - j))) & 0x3f)); + } + } + + // Add padding + var paddingChar = map.charAt(64); + if (paddingChar) { + while (base64Chars.length % 4) { + base64Chars.push(paddingChar); + } + } + + return base64Chars.join(''); + }, + + /** + * Converts a Base64 string to a word array. + * + * @param {string} base64Str The Base64 string. + * + * @return {WordArray} The word array. + * + * @static + * + * @example + * + * var wordArray = CryptoJS.enc.Base64.parse(base64String); + */ + parse: function (base64Str) { + // Shortcuts + var base64StrLength = base64Str.length; + var map = this._map; + + // Ignore padding + var paddingChar = map.charAt(64); + if (paddingChar) { + var paddingIndex = base64Str.indexOf(paddingChar); + if (paddingIndex != -1) { + base64StrLength = paddingIndex; + } + } + + // Convert + var words = []; + var nBytes = 0; + for (var i = 0; i < base64StrLength; i++) { + if (i % 4) { + var bits1 = map.indexOf(base64Str.charAt(i - 1)) << ((i % 4) * 2); + var bits2 = map.indexOf(base64Str.charAt(i)) >>> (6 - (i % 4) * 2); + words[nBytes >>> 2] |= (bits1 | bits2) << (24 - (nBytes % 4) * 8); + nBytes++; + } + } + + return WordArray.create(words, nBytes); + }, + + _map: 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=' + }; +}()); + +module.exports = CryptoJS; /***/ }), /* 12 */ /***/ (function(module, exports, __webpack_require__) { -/* - Copyright 2011-2013 Abdulla Abdurakhmanov - Original sources are available at https://code.google.com/p/x2js/ - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - */ -var DOMParser = __webpack_require__(13).DOMParser; - -var x2js = function (config) { - 'use strict'; - - var VERSION = "1.2.0"; - - config = config || {}; - initConfigDefaults(); - initRequiredPolyfills(); - - function initConfigDefaults() { - if(config.escapeMode === undefined) { - config.escapeMode = true; - } - - config.attributePrefix = config.attributePrefix || "_"; - config.arrayAccessForm = config.arrayAccessForm || "none"; - config.emptyNodeForm = config.emptyNodeForm || "text"; - - if(config.enableToStringFunc === undefined) { - config.enableToStringFunc = true; - } - config.arrayAccessFormPaths = config.arrayAccessFormPaths || []; - if(config.skipEmptyTextNodesForObj === undefined) { - config.skipEmptyTextNodesForObj = true; - } - if(config.stripWhitespaces === undefined) { - config.stripWhitespaces = true; - } - config.datetimeAccessFormPaths = config.datetimeAccessFormPaths || []; - - if(config.useDoubleQuotes === undefined) { - config.useDoubleQuotes = false; - } - - config.xmlElementsFilter = config.xmlElementsFilter || []; - config.jsonPropertiesFilter = config.jsonPropertiesFilter || []; - - if(config.keepCData === undefined) { - config.keepCData = false; - } - } - - var DOMNodeTypes = { - ELEMENT_NODE : 1, - TEXT_NODE : 3, - CDATA_SECTION_NODE : 4, - COMMENT_NODE : 8, - DOCUMENT_NODE : 9 - }; - - function initRequiredPolyfills() { - } - - function getNodeLocalName( node ) { - var nodeLocalName = node.localName; - if(nodeLocalName == null) // Yeah, this is IE!! - nodeLocalName = node.baseName; - if(nodeLocalName == null || nodeLocalName=="") // =="" is IE too - nodeLocalName = node.nodeName; - return nodeLocalName; - } - - function getNodePrefix(node) { - return node.prefix; - } - - function escapeXmlChars(str) { - if(typeof(str) == "string") - return str.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, '''); - else - return str; - } - - function unescapeXmlChars(str) { - return str.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, '&'); - } - - function checkInStdFiltersArrayForm(stdFiltersArrayForm, obj, name, path) { - var idx = 0; - for(; idx < stdFiltersArrayForm.length; idx++) { - var filterPath = stdFiltersArrayForm[idx]; - if( typeof filterPath === "string" ) { - if(filterPath == path) - break; - } - else - if( filterPath instanceof RegExp) { - if(filterPath.test(path)) - break; - } - else - if( typeof filterPath === "function") { - if(filterPath(obj, name, path)) - break; - } - } - return idx!=stdFiltersArrayForm.length; - } - - function toArrayAccessForm(obj, childName, path) { - switch(config.arrayAccessForm) { - case "property": - if(!(obj[childName] instanceof Array)) - obj[childName+"_asArray"] = [obj[childName]]; - else - obj[childName+"_asArray"] = obj[childName]; - break; - /*case "none": - break;*/ - } - - if(!(obj[childName] instanceof Array) && config.arrayAccessFormPaths.length > 0) { - if(checkInStdFiltersArrayForm(config.arrayAccessFormPaths, obj, childName, path)) { - obj[childName] = [obj[childName]]; - } - } - } - - function fromXmlDateTime(prop) { - // Implementation based up on http://stackoverflow.com/questions/8178598/xml-datetime-to-javascript-date-object - // Improved to support full spec and optional parts - var bits = prop.split(/[-T:+Z]/g); - - var d = new Date(bits[0], bits[1]-1, bits[2]); - var secondBits = bits[5].split("\."); - d.setHours(bits[3], bits[4], secondBits[0]); - if(secondBits.length>1) - d.setMilliseconds(secondBits[1]); - - // Get supplied time zone offset in minutes - if(bits[6] && bits[7]) { - var offsetMinutes = bits[6] * 60 + Number(bits[7]); - var sign = /\d\d-\d\d:\d\d$/.test(prop)? '-' : '+'; - - // Apply the sign - offsetMinutes = 0 + (sign == '-'? -1 * offsetMinutes : offsetMinutes); - - // Apply offset and local timezone - d.setMinutes(d.getMinutes() - offsetMinutes - d.getTimezoneOffset()) - } - else - if(prop.indexOf("Z", prop.length - 1) !== -1) { - d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds())); - } - - // d is now a local time equivalent to the supplied time - return d; - } - - function checkFromXmlDateTimePaths(value, childName, fullPath) { - if(config.datetimeAccessFormPaths.length > 0) { - var path = fullPath.split("\.#")[0]; - if(checkInStdFiltersArrayForm(config.datetimeAccessFormPaths, value, childName, path)) { - return fromXmlDateTime(value); - } - else - return value; - } - else - return value; - } - - function checkXmlElementsFilter(obj, childType, childName, childPath) { - if( childType == DOMNodeTypes.ELEMENT_NODE && config.xmlElementsFilter.length > 0) { - return checkInStdFiltersArrayForm(config.xmlElementsFilter, obj, childName, childPath); - } - else - return true; - } - - function parseDOMChildren( node, path ) { - if(node.nodeType == DOMNodeTypes.DOCUMENT_NODE) { - var result = new Object; - var nodeChildren = node.childNodes; - // Alternative for firstElementChild which is not supported in some environments - for(var cidx=0; cidx 1 && result.__text!=null && config.skipEmptyTextNodesForObj) { - if( (config.stripWhitespaces && result.__text=="") || (result.__text.trim()=="")) { - delete result.__text; - } - } - delete result.__cnt; - - if( config.enableToStringFunc && (result.__text!=null || result.__cdata!=null )) { - result.toString = function() { - return (this.__text!=null? this.__text:'')+( this.__cdata!=null ? this.__cdata:''); - }; - } - - return result; - } - else - if(node.nodeType == DOMNodeTypes.TEXT_NODE || node.nodeType == DOMNodeTypes.CDATA_SECTION_NODE) { - return node.nodeValue; - } - } - - function startTag(jsonObj, element, attrList, closed) { - var resultStr = "<"+ ( (jsonObj!=null && jsonObj.__prefix!=null)? (jsonObj.__prefix+":"):"") + element; - if(attrList!=null) { - for(var aidx = 0; aidx < attrList.length; aidx++) { - var attrName = attrList[aidx]; - var attrVal = jsonObj[attrName]; - if(config.escapeMode) - attrVal=escapeXmlChars(attrVal); - resultStr+=" "+attrName.substr(config.attributePrefix.length)+"="; - if(config.useDoubleQuotes) - resultStr+='"'+attrVal+'"'; - else - resultStr+="'"+attrVal+"'"; - } - } - if(!closed) - resultStr+=">"; - else - resultStr+="/>"; - return resultStr; - } - - function endTag(jsonObj,elementName) { - return ""; - } - - function endsWith(str, suffix) { - return str.indexOf(suffix, str.length - suffix.length) !== -1; - } - - function jsonXmlSpecialElem ( jsonObj, jsonObjField ) { - if((config.arrayAccessForm=="property" && endsWith(jsonObjField.toString(),("_asArray"))) - || jsonObjField.toString().indexOf(config.attributePrefix)==0 - || jsonObjField.toString().indexOf("__")==0 - || (jsonObj[jsonObjField] instanceof Function) ) - return true; - else - return false; - } - - function jsonXmlElemCount ( jsonObj ) { - var elementsCnt = 0; - if(jsonObj instanceof Object ) { - for( var it in jsonObj ) { - if(jsonXmlSpecialElem ( jsonObj, it) ) - continue; - elementsCnt++; - } - } - return elementsCnt; - } - - function checkJsonObjPropertiesFilter(jsonObj, propertyName, jsonObjPath) { - return config.jsonPropertiesFilter.length == 0 - || jsonObjPath=="" - || checkInStdFiltersArrayForm(config.jsonPropertiesFilter, jsonObj, propertyName, jsonObjPath); - } - - function parseJSONAttributes ( jsonObj ) { - var attrList = []; - if(jsonObj instanceof Object ) { - for( var ait in jsonObj ) { - if(ait.toString().indexOf("__")== -1 && ait.toString().indexOf(config.attributePrefix)==0) { - attrList.push(ait); - } - } - } - return attrList; - } - - function parseJSONTextAttrs ( jsonTxtObj ) { - var result =""; - - if(jsonTxtObj.__cdata!=null) { - result+=""; - } - - if(jsonTxtObj.__text!=null) { - if(config.escapeMode) - result+=escapeXmlChars(jsonTxtObj.__text); - else - result+=jsonTxtObj.__text; - } - return result; - } - - function parseJSONTextObject ( jsonTxtObj ) { - var result =""; - - if( jsonTxtObj instanceof Object ) { - result+=parseJSONTextAttrs ( jsonTxtObj ); - } - else - if(jsonTxtObj!=null) { - if(config.escapeMode) - result+=escapeXmlChars(jsonTxtObj); - else - result+=jsonTxtObj; - } - - return result; - } - - function getJsonPropertyPath(jsonObjPath, jsonPropName) { - if (jsonObjPath==="") { - return jsonPropName; - } - else - return jsonObjPath+"."+jsonPropName; - } - - function parseJSONArray ( jsonArrRoot, jsonArrObj, attrList, jsonObjPath ) { - var result = ""; - if(jsonArrRoot.length == 0) { - result+=startTag(jsonArrRoot, jsonArrObj, attrList, true); - } - else { - for(var arIdx = 0; arIdx < jsonArrRoot.length; arIdx++) { - result+=startTag(jsonArrRoot[arIdx], jsonArrObj, parseJSONAttributes(jsonArrRoot[arIdx]), false); - result+=parseJSONObject(jsonArrRoot[arIdx], getJsonPropertyPath(jsonObjPath,jsonArrObj)); - result+=endTag(jsonArrRoot[arIdx],jsonArrObj); - } - } - return result; - } - - function parseJSONObject ( jsonObj, jsonObjPath ) { - var result = ""; - - var elementsCnt = jsonXmlElemCount ( jsonObj ); - - if(elementsCnt > 0) { - for( var it in jsonObj ) { - - if(jsonXmlSpecialElem ( jsonObj, it) || (jsonObjPath!="" && !checkJsonObjPropertiesFilter(jsonObj, it, getJsonPropertyPath(jsonObjPath,it))) ) - continue; - - var subObj = jsonObj[it]; - - var attrList = parseJSONAttributes( subObj ) - - if(subObj == null || subObj == undefined) { - result+=startTag(subObj, it, attrList, true); - } - else - if(subObj instanceof Object) { - - if(subObj instanceof Array) { - result+=parseJSONArray( subObj, it, attrList, jsonObjPath ); - } - else if(subObj instanceof Date) { - result+=startTag(subObj, it, attrList, false); - result+=subObj.toISOString(); - result+=endTag(subObj,it); - } - else { - var subObjElementsCnt = jsonXmlElemCount ( subObj ); - if(subObjElementsCnt > 0 || subObj.__text!=null || subObj.__cdata!=null) { - result+=startTag(subObj, it, attrList, false); - result+=parseJSONObject(subObj, getJsonPropertyPath(jsonObjPath,it)); - result+=endTag(subObj,it); - } - else { - result+=startTag(subObj, it, attrList, true); - } - } - } - else { - result+=startTag(subObj, it, attrList, false); - result+=parseJSONTextObject(subObj); - result+=endTag(subObj,it); - } - } - } - result+=parseJSONTextObject(jsonObj); - - return result; - } - - this.parseXmlString = function(xmlDocStr) { - // var isIEParser = window.ActiveXObject || "ActiveXObject" in window; - var isIEParser = false; - if (xmlDocStr === undefined) { - return null; - } - var xmlDoc; - if (DOMParser) { - var parser=new DOMParser(); - var parsererrorNS = null; - // IE9+ now is here - if(!isIEParser) { - try { - parsererrorNS = parser.parseFromString("INVALID", "text/xml").getElementsByTagName("parsererror")[0].namespaceURI; - } - catch(err) { - parsererrorNS = null; - } - } - try { - xmlDoc = parser.parseFromString( xmlDocStr, "text/xml" ); - if( parsererrorNS!= null && xmlDoc.getElementsByTagNameNS(parsererrorNS, "parsererror").length > 0) { - //throw new Error('Error parsing XML: '+xmlDocStr); - xmlDoc = null; - } - } - catch(err) { - xmlDoc = null; - } - } - else { - // IE :( - if(xmlDocStr.indexOf("") + 2 ); - } - xmlDoc=new ActiveXObject("Microsoft.XMLDOM"); - xmlDoc.async="false"; - xmlDoc.loadXML(xmlDocStr); - } - return xmlDoc; - }; - - this.asArray = function(prop) { - if (prop === undefined || prop == null) - return []; - else - if(prop instanceof Array) - return prop; - else - return [prop]; - }; - - this.toXmlDateTime = function(dt) { - if(dt instanceof Date) - return dt.toISOString(); - else - if(typeof(dt) === 'number' ) - return new Date(dt).toISOString(); - else - return null; - }; - - this.asDateTime = function(prop) { - if(typeof(prop) == "string") { - return fromXmlDateTime(prop); - } - else - return prop; - }; - - this.xml2json = function (xmlDoc) { - return parseDOMChildren ( xmlDoc ); - }; - - this.xml_str2json = function (xmlDocStr) { - var xmlDoc = this.parseXmlString(xmlDocStr); - if(xmlDoc!=null) - return this.xml2json(xmlDoc); - else - return null; - }; - - this.json2xml_str = function (jsonObj) { - return parseJSONObject ( jsonObj, "" ); - }; - - this.json2xml = function (jsonObj) { - var xmlDocStr = this.json2xml_str (jsonObj); - return this.parseXmlString(xmlDocStr); - }; - - this.getVersion = function () { - return VERSION; - }; -}; - -var xml2json = function (str) { - if (!str) return null; - var parser = new DOMParser(); - var xmlDoc = parser.parseFromString(str, "text/xml"); - var x2jsObj = new x2js(); - var data = x2jsObj.xml2json(xmlDoc); - if (data.html && data.getElementsByTagName('parsererror').length) { - return null; - } else { - return data; - } -}; - -var json2xml = function (data) { - var x2jsObj = new x2js(); - return x2jsObj.json2xml(data); -}; - -module.exports = xml2json; +/* + Copyright 2011-2013 Abdulla Abdurakhmanov + Original sources are available at https://code.google.com/p/x2js/ + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + */ +var DOMParser = __webpack_require__(13).DOMParser; + +var x2js = function (config) { + 'use strict'; + + var VERSION = "1.2.0"; + + config = config || {}; + initConfigDefaults(); + initRequiredPolyfills(); + + function initConfigDefaults() { + if(config.escapeMode === undefined) { + config.escapeMode = true; + } + + config.attributePrefix = config.attributePrefix || "_"; + config.arrayAccessForm = config.arrayAccessForm || "none"; + config.emptyNodeForm = config.emptyNodeForm || "text"; + + if(config.enableToStringFunc === undefined) { + config.enableToStringFunc = true; + } + config.arrayAccessFormPaths = config.arrayAccessFormPaths || []; + if(config.skipEmptyTextNodesForObj === undefined) { + config.skipEmptyTextNodesForObj = true; + } + if(config.stripWhitespaces === undefined) { + config.stripWhitespaces = true; + } + config.datetimeAccessFormPaths = config.datetimeAccessFormPaths || []; + + if(config.useDoubleQuotes === undefined) { + config.useDoubleQuotes = false; + } + + config.xmlElementsFilter = config.xmlElementsFilter || []; + config.jsonPropertiesFilter = config.jsonPropertiesFilter || []; + + if(config.keepCData === undefined) { + config.keepCData = false; + } + } + + var DOMNodeTypes = { + ELEMENT_NODE : 1, + TEXT_NODE : 3, + CDATA_SECTION_NODE : 4, + COMMENT_NODE : 8, + DOCUMENT_NODE : 9 + }; + + function initRequiredPolyfills() { + } + + function getNodeLocalName( node ) { + var nodeLocalName = node.localName; + if(nodeLocalName == null) // Yeah, this is IE!! + nodeLocalName = node.baseName; + if(nodeLocalName == null || nodeLocalName=="") // =="" is IE too + nodeLocalName = node.nodeName; + return nodeLocalName; + } + + function getNodePrefix(node) { + return node.prefix; + } + + function escapeXmlChars(str) { + if(typeof(str) == "string") + return str.replace(/&/g, '&').replace(//g, '>').replace(/"/g, '"').replace(/'/g, '''); + else + return str; + } + + function unescapeXmlChars(str) { + return str.replace(/</g, '<').replace(/>/g, '>').replace(/"/g, '"').replace(/'/g, "'").replace(/&/g, '&'); + } + + function checkInStdFiltersArrayForm(stdFiltersArrayForm, obj, name, path) { + var idx = 0; + for(; idx < stdFiltersArrayForm.length; idx++) { + var filterPath = stdFiltersArrayForm[idx]; + if( typeof filterPath === "string" ) { + if(filterPath == path) + break; + } + else + if( filterPath instanceof RegExp) { + if(filterPath.test(path)) + break; + } + else + if( typeof filterPath === "function") { + if(filterPath(obj, name, path)) + break; + } + } + return idx!=stdFiltersArrayForm.length; + } + + function toArrayAccessForm(obj, childName, path) { + switch(config.arrayAccessForm) { + case "property": + if(!(obj[childName] instanceof Array)) + obj[childName+"_asArray"] = [obj[childName]]; + else + obj[childName+"_asArray"] = obj[childName]; + break; + /*case "none": + break;*/ + } + + if(!(obj[childName] instanceof Array) && config.arrayAccessFormPaths.length > 0) { + if(checkInStdFiltersArrayForm(config.arrayAccessFormPaths, obj, childName, path)) { + obj[childName] = [obj[childName]]; + } + } + } + + function fromXmlDateTime(prop) { + // Implementation based up on http://stackoverflow.com/questions/8178598/xml-datetime-to-javascript-date-object + // Improved to support full spec and optional parts + var bits = prop.split(/[-T:+Z]/g); + + var d = new Date(bits[0], bits[1]-1, bits[2]); + var secondBits = bits[5].split("\."); + d.setHours(bits[3], bits[4], secondBits[0]); + if(secondBits.length>1) + d.setMilliseconds(secondBits[1]); + + // Get supplied time zone offset in minutes + if(bits[6] && bits[7]) { + var offsetMinutes = bits[6] * 60 + Number(bits[7]); + var sign = /\d\d-\d\d:\d\d$/.test(prop)? '-' : '+'; + + // Apply the sign + offsetMinutes = 0 + (sign == '-'? -1 * offsetMinutes : offsetMinutes); + + // Apply offset and local timezone + d.setMinutes(d.getMinutes() - offsetMinutes - d.getTimezoneOffset()) + } + else + if(prop.indexOf("Z", prop.length - 1) !== -1) { + d = new Date(Date.UTC(d.getFullYear(), d.getMonth(), d.getDate(), d.getHours(), d.getMinutes(), d.getSeconds(), d.getMilliseconds())); + } + + // d is now a local time equivalent to the supplied time + return d; + } + + function checkFromXmlDateTimePaths(value, childName, fullPath) { + if(config.datetimeAccessFormPaths.length > 0) { + var path = fullPath.split("\.#")[0]; + if(checkInStdFiltersArrayForm(config.datetimeAccessFormPaths, value, childName, path)) { + return fromXmlDateTime(value); + } + else + return value; + } + else + return value; + } + + function checkXmlElementsFilter(obj, childType, childName, childPath) { + if( childType == DOMNodeTypes.ELEMENT_NODE && config.xmlElementsFilter.length > 0) { + return checkInStdFiltersArrayForm(config.xmlElementsFilter, obj, childName, childPath); + } + else + return true; + } + + function parseDOMChildren( node, path ) { + if(node.nodeType == DOMNodeTypes.DOCUMENT_NODE) { + var result = new Object; + var nodeChildren = node.childNodes; + // Alternative for firstElementChild which is not supported in some environments + for(var cidx=0; cidx 1 && result.__text!=null && config.skipEmptyTextNodesForObj) { + if( (config.stripWhitespaces && result.__text=="") || (result.__text.trim()=="")) { + delete result.__text; + } + } + delete result.__cnt; + + if( config.enableToStringFunc && (result.__text!=null || result.__cdata!=null )) { + result.toString = function() { + return (this.__text!=null? this.__text:'')+( this.__cdata!=null ? this.__cdata:''); + }; + } + + return result; + } + else + if(node.nodeType == DOMNodeTypes.TEXT_NODE || node.nodeType == DOMNodeTypes.CDATA_SECTION_NODE) { + return node.nodeValue; + } + } + + function startTag(jsonObj, element, attrList, closed) { + var resultStr = "<"+ ( (jsonObj!=null && jsonObj.__prefix!=null)? (jsonObj.__prefix+":"):"") + element; + if(attrList!=null) { + for(var aidx = 0; aidx < attrList.length; aidx++) { + var attrName = attrList[aidx]; + var attrVal = jsonObj[attrName]; + if(config.escapeMode) + attrVal=escapeXmlChars(attrVal); + resultStr+=" "+attrName.substr(config.attributePrefix.length)+"="; + if(config.useDoubleQuotes) + resultStr+='"'+attrVal+'"'; + else + resultStr+="'"+attrVal+"'"; + } + } + if(!closed) + resultStr+=">"; + else + resultStr+="/>"; + return resultStr; + } + + function endTag(jsonObj,elementName) { + return ""; + } + + function endsWith(str, suffix) { + return str.indexOf(suffix, str.length - suffix.length) !== -1; + } + + function jsonXmlSpecialElem ( jsonObj, jsonObjField ) { + if((config.arrayAccessForm=="property" && endsWith(jsonObjField.toString(),("_asArray"))) + || jsonObjField.toString().indexOf(config.attributePrefix)==0 + || jsonObjField.toString().indexOf("__")==0 + || (jsonObj[jsonObjField] instanceof Function) ) + return true; + else + return false; + } + + function jsonXmlElemCount ( jsonObj ) { + var elementsCnt = 0; + if(jsonObj instanceof Object ) { + for( var it in jsonObj ) { + if(jsonXmlSpecialElem ( jsonObj, it) ) + continue; + elementsCnt++; + } + } + return elementsCnt; + } + + function checkJsonObjPropertiesFilter(jsonObj, propertyName, jsonObjPath) { + return config.jsonPropertiesFilter.length == 0 + || jsonObjPath=="" + || checkInStdFiltersArrayForm(config.jsonPropertiesFilter, jsonObj, propertyName, jsonObjPath); + } + + function parseJSONAttributes ( jsonObj ) { + var attrList = []; + if(jsonObj instanceof Object ) { + for( var ait in jsonObj ) { + if(ait.toString().indexOf("__")== -1 && ait.toString().indexOf(config.attributePrefix)==0) { + attrList.push(ait); + } + } + } + return attrList; + } + + function parseJSONTextAttrs ( jsonTxtObj ) { + var result =""; + + if(jsonTxtObj.__cdata!=null) { + result+=""; + } + + if(jsonTxtObj.__text!=null) { + if(config.escapeMode) + result+=escapeXmlChars(jsonTxtObj.__text); + else + result+=jsonTxtObj.__text; + } + return result; + } + + function parseJSONTextObject ( jsonTxtObj ) { + var result =""; + + if( jsonTxtObj instanceof Object ) { + result+=parseJSONTextAttrs ( jsonTxtObj ); + } + else + if(jsonTxtObj!=null) { + if(config.escapeMode) + result+=escapeXmlChars(jsonTxtObj); + else + result+=jsonTxtObj; + } + + return result; + } + + function getJsonPropertyPath(jsonObjPath, jsonPropName) { + if (jsonObjPath==="") { + return jsonPropName; + } + else + return jsonObjPath+"."+jsonPropName; + } + + function parseJSONArray ( jsonArrRoot, jsonArrObj, attrList, jsonObjPath ) { + var result = ""; + if(jsonArrRoot.length == 0) { + result+=startTag(jsonArrRoot, jsonArrObj, attrList, true); + } + else { + for(var arIdx = 0; arIdx < jsonArrRoot.length; arIdx++) { + result+=startTag(jsonArrRoot[arIdx], jsonArrObj, parseJSONAttributes(jsonArrRoot[arIdx]), false); + result+=parseJSONObject(jsonArrRoot[arIdx], getJsonPropertyPath(jsonObjPath,jsonArrObj)); + result+=endTag(jsonArrRoot[arIdx],jsonArrObj); + } + } + return result; + } + + function parseJSONObject ( jsonObj, jsonObjPath ) { + var result = ""; + + var elementsCnt = jsonXmlElemCount ( jsonObj ); + + if(elementsCnt > 0) { + for( var it in jsonObj ) { + + if(jsonXmlSpecialElem ( jsonObj, it) || (jsonObjPath!="" && !checkJsonObjPropertiesFilter(jsonObj, it, getJsonPropertyPath(jsonObjPath,it))) ) + continue; + + var subObj = jsonObj[it]; + + var attrList = parseJSONAttributes( subObj ) + + if(subObj == null || subObj == undefined) { + result+=startTag(subObj, it, attrList, true); + } + else + if(subObj instanceof Object) { + + if(subObj instanceof Array) { + result+=parseJSONArray( subObj, it, attrList, jsonObjPath ); + } + else if(subObj instanceof Date) { + result+=startTag(subObj, it, attrList, false); + result+=subObj.toISOString(); + result+=endTag(subObj,it); + } + else { + var subObjElementsCnt = jsonXmlElemCount ( subObj ); + if(subObjElementsCnt > 0 || subObj.__text!=null || subObj.__cdata!=null) { + result+=startTag(subObj, it, attrList, false); + result+=parseJSONObject(subObj, getJsonPropertyPath(jsonObjPath,it)); + result+=endTag(subObj,it); + } + else { + result+=startTag(subObj, it, attrList, true); + } + } + } + else { + result+=startTag(subObj, it, attrList, false); + result+=parseJSONTextObject(subObj); + result+=endTag(subObj,it); + } + } + } + result+=parseJSONTextObject(jsonObj); + + return result; + } + + this.parseXmlString = function(xmlDocStr) { + // var isIEParser = window.ActiveXObject || "ActiveXObject" in window; + var isIEParser = false; + if (xmlDocStr === undefined) { + return null; + } + var xmlDoc; + if (DOMParser) { + var parser=new DOMParser(); + var parsererrorNS = null; + // IE9+ now is here + if(!isIEParser) { + try { + parsererrorNS = parser.parseFromString("INVALID", "text/xml").getElementsByTagName("parsererror")[0].namespaceURI; + } + catch(err) { + parsererrorNS = null; + } + } + try { + xmlDoc = parser.parseFromString( xmlDocStr, "text/xml" ); + if( parsererrorNS!= null && xmlDoc.getElementsByTagNameNS(parsererrorNS, "parsererror").length > 0) { + //throw new Error('Error parsing XML: '+xmlDocStr); + xmlDoc = null; + } + } + catch(err) { + xmlDoc = null; + } + } + else { + // IE :( + if(xmlDocStr.indexOf("") + 2 ); + } + xmlDoc=new ActiveXObject("Microsoft.XMLDOM"); + xmlDoc.async="false"; + xmlDoc.loadXML(xmlDocStr); + } + return xmlDoc; + }; + + this.asArray = function(prop) { + if (prop === undefined || prop == null) + return []; + else + if(prop instanceof Array) + return prop; + else + return [prop]; + }; + + this.toXmlDateTime = function(dt) { + if(dt instanceof Date) + return dt.toISOString(); + else + if(typeof(dt) === 'number' ) + return new Date(dt).toISOString(); + else + return null; + }; + + this.asDateTime = function(prop) { + if(typeof(prop) == "string") { + return fromXmlDateTime(prop); + } + else + return prop; + }; + + this.xml2json = function (xmlDoc) { + return parseDOMChildren ( xmlDoc ); + }; + + this.xml_str2json = function (xmlDocStr) { + var xmlDoc = this.parseXmlString(xmlDocStr); + if(xmlDoc!=null) + return this.xml2json(xmlDoc); + else + return null; + }; + + this.json2xml_str = function (jsonObj) { + return parseJSONObject ( jsonObj, "" ); + }; + + this.json2xml = function (jsonObj) { + var xmlDocStr = this.json2xml_str (jsonObj); + return this.parseXmlString(xmlDocStr); + }; + + this.getVersion = function () { + return VERSION; + }; +}; + +var xml2json = function (str) { + if (!str) return null; + var parser = new DOMParser(); + var xmlDoc = parser.parseFromString(str, "text/xml"); + var x2jsObj = new x2js(); + var data = x2jsObj.xml2json(xmlDoc); + if (data.html && data.getElementsByTagName('parsererror').length) { + return null; + } else { + return data; + } +}; + +var json2xml = function (data) { + var x2jsObj = new x2js(); + return x2jsObj.json2xml(data); +}; + +module.exports = xml2json; /***/ }), @@ -4858,5432 +4858,5486 @@ exports.XMLReader = XMLReader; /* 15 */ /***/ (function(module, exports) { -//copyright Ryan Day 2010 , Joscha Feth 2013 [MIT Licensed] - -var element_start_char = - "a-zA-Z_\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FFF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD"; -var element_non_start_char = "\-.0-9\u00B7\u0300-\u036F\u203F\u2040"; -var element_replace = new RegExp("^([^" + element_start_char + "])|^((x|X)(m|M)(l|L))|([^" + element_start_char + element_non_start_char + "])", "g"); -var not_safe_in_xml = /[^\x09\x0A\x0D\x20-\xFF\x85\xA0-\uD7FF\uE000-\uFDCF\uFDE0-\uFFFD]/gm; - -var objKeys = function (obj) { - var l = []; - if (obj instanceof Object) { - for (var k in obj) { - if (obj.hasOwnProperty(k)) { - l.push(k); - } - } - } - return l; -}; -var process_to_xml = function (node_data, options) { - - var makeNode = function (name, content, attributes, level, hasSubNodes) { - var indent_value = options.indent !== undefined ? options.indent : "\t"; - var indent = options.prettyPrint ? '\n' + new Array(level).join(indent_value) : ''; - if (options.removeIllegalNameCharacters) { - name = name.replace(element_replace, '_'); - } - - var node = [indent, '<', name, (attributes || '')]; - if (content && content.length > 0) { - node.push('>') - node.push(content); - hasSubNodes && node.push(indent); - node.push(''); - } else { - node.push('/>'); - } - return node.join(''); - }; - - return (function fn(node_data, node_descriptor, level) { - var type = typeof node_data; - if ((Array.isArray) ? Array.isArray(node_data) : node_data instanceof Array) { - type = 'array'; - } else if (node_data instanceof Date) { - type = 'date'; - } - - switch (type) { - //if value is an array create child nodes from values - case 'array': - var ret = []; - node_data.map(function (v) { - ret.push(fn(v, 1, level + 1)); - //entries that are values of an array are the only ones that can be special node descriptors - }); - options.prettyPrint && ret.push('\n'); - return ret.join(''); - break; - - case 'date': - // cast dates to ISO 8601 date (soap likes it) - return node_data.toJSON ? node_data.toJSON() : node_data + ''; - break; - - case 'object': - var nodes = []; - for (var name in node_data) { - if (node_data.hasOwnProperty(name)) { - if (node_data[name] instanceof Array) { - for (var j in node_data[name]) { - if (node_data[name].hasOwnProperty(j)) - nodes.push(makeNode(name, fn(node_data[name][j], 0, level + 1), null, level + 1, objKeys(node_data[name][j]).length)); - } - } else { - nodes.push(makeNode(name, fn(node_data[name], 0, level + 1), null, level + 1)); - } - } - } - options.prettyPrint && nodes.length > 0 && nodes.push('\n'); - return nodes.join(''); - break; - - case 'function': - return node_data(); - break; - - default: - return options.escape ? esc(node_data) : '' + node_data; - } - - }(node_data, 0, 0)) -}; - - -var xml_header = function (standalone) { - var ret = [''); - - return ret.join(''); -}; - -function esc(str) { - return ('' + str).replace(/&/g, '&') - .replace(//g, '>') - .replace(/'/g, ''') - .replace(/"/g, '"') - .replace(not_safe_in_xml, ''); -} - -var json2xml = function (obj, options) { - - if (!options) { - options = { - xmlHeader: { - standalone: true - }, - prettyPrint: true, - indent: " " - }; - } - - if (typeof obj == 'string') { - try { - obj = JSON.parse(obj.toString()); - } catch (e) { - return false; - } - } - - var xmlheader = ''; - var docType = ''; - if (options) { - if (typeof options == 'object') { - // our config is an object - - if (options.xmlHeader) { - // the user wants an xml header - xmlheader = xml_header(!!options.xmlHeader.standalone); - } - - if (typeof options.docType != 'undefined') { - docType = '' - } - } else { - // our config is a boolean value, so just add xml header - xmlheader = xml_header(); - } - } - options = options || {} - - var ret = [ - xmlheader, - (options.prettyPrint && docType ? '\n' : ''), - docType, - process_to_xml(obj, options) - ]; - return ret.join('').replace(/\n{2,}/g, '\n').replace(/\s+$/g, ''); -}; - -module.exports = json2xml; +//copyright Ryan Day 2010 , Joscha Feth 2013 [MIT Licensed] +var element_start_char = + "a-zA-Z_\u00C0-\u00D6\u00D8-\u00F6\u00F8-\u00FF\u0370-\u037D\u037F-\u1FFF\u200C-\u200D\u2070-\u218F\u2C00-\u2FFF\u3001-\uD7FF\uF900-\uFDCF\uFDF0-\uFFFD"; +var element_non_start_char = "\-.0-9\u00B7\u0300-\u036F\u203F\u2040"; +var element_replace = new RegExp("^([^" + element_start_char + "])|^((x|X)(m|M)(l|L))|([^" + element_start_char + element_non_start_char + "])", "g"); +var not_safe_in_xml = /[^\x09\x0A\x0D\x20-\xFF\x85\xA0-\uD7FF\uE000-\uFDCF\uFDE0-\uFFFD]/gm; -/***/ }), -/* 16 */ -/***/ (function(module, exports, __webpack_require__) { +var objKeys = function (obj) { + var l = []; + if (obj instanceof Object) { + for (var k in obj) { + if (obj.hasOwnProperty(k)) { + l.push(k); + } + } + } + return l; +}; +var process_to_xml = function (node_data, options) { -var session = __webpack_require__(5); -var util = __webpack_require__(0); - -var originApiMap = {}; -var transferToTaskMethod = function (apiMap, apiName) { - originApiMap[apiName] = apiMap[apiName]; - apiMap[apiName] = function (params, callback) { - if (params.SkipTask) { - originApiMap[apiName].call(this, params, callback); - } else { - this._addTask(apiName, params, callback); - } - }; -}; - -var initTask = function (cos) { - - var queue = []; - var tasks = {}; - var uploadingFileCount = 0; - var nextUploadIndex = 0; - - // 接口返回简略的任务信息 - var formatTask = function (task) { - var t = { - id: task.id, - Bucket: task.Bucket, - Region: task.Region, - Key: task.Key, - FilePath: task.FilePath, - state: task.state, - loaded: task.loaded, - size: task.size, - speed: task.speed, - percent: task.percent, - hashPercent: task.hashPercent, - error: task.error, - }; - if (task.FilePath) t.FilePath = task.FilePath; - return t; - }; - - var emitListUpdate = (function () { - var timer; - var emit = function () { - timer = 0; - cos.emit('task-list-update', {list: util.map(queue, formatTask)}); - cos.emit('list-update', {list: util.map(queue, formatTask)}); - }; - return function () { - if (!timer) timer = setTimeout(emit); - } - })(); - - var clearQueue = function () { - if (queue.length <= cos.options.UploadQueueSize) return; - for (var i = 0; - i < nextUploadIndex && // 小于当前操作的 index 才清理 - i < queue.length && // 大于队列才清理 - queue.length > cos.options.UploadQueueSize // 如果还太多,才继续清理 - ;) { - var isActive = queue[i].state === 'waiting' || queue[i].state === 'checking' || queue[i].state === 'uploading'; - if (!queue[i] || !isActive) { - tasks[queue[i].id] && (delete tasks[queue[i].id]); - queue.splice(i, 1); - nextUploadIndex--; - } else { - i++; - } - } - emitListUpdate(); - }; - - var startNextTask = function () { - // 检查是否允许增加执行进程 - if (uploadingFileCount >= cos.options.FileParallelLimit) return; - // 跳过不可执行的任务 - while (queue[nextUploadIndex] && queue[nextUploadIndex].state !== 'waiting') nextUploadIndex++; - // 检查是否已遍历结束 - if (nextUploadIndex >= queue.length) return; - // 上传该遍历到的任务 - var task = queue[nextUploadIndex]; - nextUploadIndex++; - uploadingFileCount++; - task.state = 'checking'; - task.params.onTaskStart && task.params.onTaskStart(formatTask(task)); - !task.params.UploadData && (task.params.UploadData = {}); - var apiParams = util.formatParams(task.api, task.params); - originApiMap[task.api].call(cos, apiParams, function (err, data) { - if (!cos._isRunningTask(task.id)) return; - if (task.state === 'checking' || task.state === 'uploading') { - task.state = err ? 'error' : 'success'; - err && (task.error = err); - uploadingFileCount--; - emitListUpdate(); - startNextTask(); - task.callback && task.callback(err, data); - if (task.state === 'success') { - if (task.params) { - delete task.params.UploadData; - delete task.params.Body; - delete task.params; - } - delete task.callback; - } - } - clearQueue(); - }); - emitListUpdate(); - // 异步执行下一个任务 - setTimeout(startNextTask); - }; - - var killTask = function (id, switchToState) { - var task = tasks[id]; - if (!task) return; - var waiting = task && task.state === 'waiting'; - var running = task && (task.state === 'checking' || task.state === 'uploading'); - if (switchToState === 'canceled' && task.state !== 'canceled' || - switchToState === 'paused' && waiting || - switchToState === 'paused' && running) { - if (switchToState === 'paused' && task.params.Body && typeof task.params.Body.pipe === 'function') { - console.error('stream not support pause'); - return; - } - task.state = switchToState; - cos.emit('inner-kill-task', {TaskId: id, toState: switchToState}); - try { - var UploadId = task && task.params && task.params.UploadData.UploadId - } catch(e) {} - if (switchToState === 'canceled' && UploadId) session.removeUsing(UploadId) - emitListUpdate(); - if (running) { - uploadingFileCount--; - startNextTask(); - } - if (switchToState === 'canceled') { - if (task.params) { - delete task.params.UploadData; - delete task.params.Body; - delete task.params; - } - delete task.callback; - } - } - clearQueue(); - }; - - cos._addTasks = function (taskList) { - util.each(taskList, function (task) { - cos._addTask(task.api, task.params, task.callback, true); - }); - emitListUpdate(); - }; - - cos._addTask = function (api, params, callback, ignoreAddEvent) { - - // 如果小程序版本不支持获取文件分片内容,统一转到 postObject 接口上传 - if (api === 'sliceUploadFile' && !util.canFileSlice()) api = 'postObject'; - - // 复制参数对象 - params = util.formatParams(api, params); - - // 生成 id - var id = util.uuid(); - params.TaskId = id; - params.onTaskReady && params.onTaskReady(id); - - var task = { - // env - params: params, - callback: callback, - api: api, - index: queue.length, - // task - id: id, - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - FilePath: params.FilePath || '', - state: 'waiting', - loaded: 0, - size: 0, - speed: 0, - percent: 0, - hashPercent: 0, - error: null, - }; - var onHashProgress = params.onHashProgress; - params.onHashProgress = function (info) { - if (!cos._isRunningTask(task.id)) return; - task.hashPercent = info.percent; - onHashProgress && onHashProgress(info); - emitListUpdate(); - }; - var onProgress = params.onProgress; - params.onProgress = function (info) { - if (!cos._isRunningTask(task.id)) return; - task.state === 'checking' && (task.state = 'uploading'); - task.loaded = info.loaded; - task.size = info.total; - task.speed = info.speed; - task.percent = info.percent; - onProgress && onProgress(info); - emitListUpdate(); - }; - - // 异步获取 filesize - util.getFileSize(api, params, function (err, size) { - // 开始处理上传 - if (err) { // 如果获取大小出错,不加入队列 - callback(err); - return; - } - // 获取完文件大小再把任务加入队列 - tasks[id] = task; - queue.push(task); - task.size = size; - !ignoreAddEvent && emitListUpdate(); - startNextTask(); - clearQueue(); - }); - return id; - }; - cos._isRunningTask = function (id) { - var task = tasks[id]; - return !!(task && (task.state === 'checking' || task.state === 'uploading')); - }; - cos.getTaskList = function () { - return util.map(queue, formatTask); - }; - cos.cancelTask = function (id) { - killTask(id, 'canceled'); - }; - cos.pauseTask = function (id) { - killTask(id, 'paused'); - }; - cos.restartTask = function (id) { - var task = tasks[id]; - if (task && (task.state === 'paused' || task.state === 'error')) { - task.state = 'waiting'; - emitListUpdate(); - nextUploadIndex = Math.min(nextUploadIndex, task.index); - startNextTask(); - } - }; - cos.isUploadRunning = function () { - return uploadingFileCount || nextUploadIndex < queue.length; - }; - -}; - -module.exports.transferToTaskMethod = transferToTaskMethod; -module.exports.init = initTask; + var makeNode = function (name, content, attributes, level, hasSubNodes) { + var indent_value = options.indent !== undefined ? options.indent : "\t"; + var indent = options.prettyPrint ? '\n' + new Array(level).join(indent_value) : ''; + if (options.removeIllegalNameCharacters) { + name = name.replace(element_replace, '_'); + } + + var node = [indent, '<', name, (attributes || '')]; + if (content && content.length > 0) { + node.push('>') + node.push(content); + hasSubNodes && node.push(indent); + node.push(''); + } else { + node.push('/>'); + } + return node.join(''); + }; + + return (function fn(node_data, node_descriptor, level) { + var type = typeof node_data; + if ((Array.isArray) ? Array.isArray(node_data) : node_data instanceof Array) { + type = 'array'; + } else if (node_data instanceof Date) { + type = 'date'; + } + + switch (type) { + //if value is an array create child nodes from values + case 'array': + var ret = []; + node_data.map(function (v) { + ret.push(fn(v, 1, level + 1)); + //entries that are values of an array are the only ones that can be special node descriptors + }); + options.prettyPrint && ret.push('\n'); + return ret.join(''); + break; + + case 'date': + // cast dates to ISO 8601 date (soap likes it) + return node_data.toJSON ? node_data.toJSON() : node_data + ''; + break; + + case 'object': + var nodes = []; + for (var name in node_data) { + if (node_data.hasOwnProperty(name)) { + if (node_data[name] instanceof Array) { + for (var j in node_data[name]) { + if (node_data[name].hasOwnProperty(j)) + nodes.push(makeNode(name, fn(node_data[name][j], 0, level + 1), null, level + 1, objKeys(node_data[name][j]).length)); + } + } else { + nodes.push(makeNode(name, fn(node_data[name], 0, level + 1), null, level + 1)); + } + } + } + options.prettyPrint && nodes.length > 0 && nodes.push('\n'); + return nodes.join(''); + break; + + case 'function': + return node_data(); + break; + + default: + return options.escape ? esc(node_data) : '' + node_data; + } + + }(node_data, 0, 0)) +}; + + +var xml_header = function (standalone) { + var ret = [''); + + return ret.join(''); +}; + +function esc(str) { + return ('' + str).replace(/&/g, '&') + .replace(//g, '>') + .replace(/'/g, ''') + .replace(/"/g, '"') + .replace(not_safe_in_xml, ''); +} + +var json2xml = function (obj, options) { + + if (!options) { + options = { + xmlHeader: { + standalone: true + }, + prettyPrint: true, + indent: " " + }; + } + + if (typeof obj == 'string') { + try { + obj = JSON.parse(obj.toString()); + } catch (e) { + return false; + } + } + + var xmlheader = ''; + var docType = ''; + if (options) { + if (typeof options == 'object') { + // our config is an object + + if (options.xmlHeader) { + // the user wants an xml header + xmlheader = xml_header(!!options.xmlHeader.standalone); + } + + if (typeof options.docType != 'undefined') { + docType = '' + } + } else { + // our config is a boolean value, so just add xml header + xmlheader = xml_header(); + } + } + options = options || {} + + var ret = [ + xmlheader, + (options.prettyPrint && docType ? '\n' : ''), + docType, + process_to_xml(obj, options) + ]; + return ret.join('').replace(/\n{2,}/g, '\n').replace(/\s+$/g, ''); +}; + +module.exports = json2xml; /***/ }), -/* 17 */ +/* 16 */ /***/ (function(module, exports, __webpack_require__) { -"use strict"; - -var REQUEST = __webpack_require__(18); -var base64 = __webpack_require__(3); -var util = __webpack_require__(0); -var mime = __webpack_require__(19); - - -// Bucket 相关 - -/** - * 获取用户的 bucket 列表 - * @param {Object} params 回调函数,必须,下面为参数列表 - * 无特殊参数 - * @param {Function} callback 回调函数,必须 - */ -function getService(params, callback) { - - if (typeof params === 'function') { - callback = params; - params = {}; - } - var protocol = 'https:'; - var domain = this.options.ServiceDomain; - var region = params.Region; - if (domain) { - domain = domain.replace(/\{\{Region\}\}/ig, region || '').replace(/\{\{.*?\}\}/ig, ''); - if (!/^[a-zA-Z]+:\/\//.test(domain)) { - domain = protocol + '//' + domain; - } - if (domain.slice(-1) === '/') { - domain = domain.slice(0, -1); - } - } else if (region) { - domain = protocol + '//cos.' + region + '.myqcloud.com'; - } else { - domain = protocol + '//service.cos.myqcloud.com'; - } - - submitRequest.call(this, { - Action: 'name/cos:GetService', - url: domain, - method: 'GET', - headers: params.Headers, - }, function (err, data) { - if (err) return callback(err); - var buckets = (data && data.ListAllMyBucketsResult && data.ListAllMyBucketsResult.Buckets - && data.ListAllMyBucketsResult.Buckets.Bucket) || []; - buckets = util.isArray(buckets) ? buckets : [buckets]; - var owner = (data && data.ListAllMyBucketsResult && data.ListAllMyBucketsResult.Owner) || {}; - callback(null, { - Buckets: buckets, - Owner: owner, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 创建 Bucket,并初始化访问权限 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.ACL 用户自定义文件权限,可以设置:private,public-read;默认值:private,非必须 - * @param {String} params.GrantRead 赋予被授权者读的权限,格式x-cos-grant-read: uin=" ",uin=" ",非必须 - * @param {String} params.GrantWrite 赋予被授权者写的权限,格式x-cos-grant-write: uin=" ",uin=" ",非必须 - * @param {String} params.GrantFullControl 赋予被授权者读写权限,格式x-cos-grant-full-control: uin=" ",uin=" ",非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {String} data.Location 操作地址 - */ -function putBucket(params, callback) { - - var self = this; - - var xml = ''; - if(params['BucketAZConfig']){ - var CreateBucketConfiguration = { - BucketAZConfig: params.BucketAZConfig - }; - xml = util.json2xml({CreateBucketConfiguration: CreateBucketConfiguration}); - } - - submitRequest.call(this, { - Action: 'name/cos:PutBucket', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - body: xml, - }, function (err, data) { - if (err) return callback(err); - var url = getUrl({ - protocol: self.options.Protocol, - domain: self.options.Domain, - bucket: params.Bucket, - region: params.Region, - isLocation: true, - }); - callback(null, { - Location: url, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 查看是否存在该Bucket,是否有权限访问 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {Boolean} data.BucketExist Bucket是否存在 - * @return {Boolean} data.BucketAuth 是否有 Bucket 的访问权限 - */ -function headBucket(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:HeadBucket', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - method: 'HEAD', - }, function (err, data) { - callback(err, data); - }); -} - -/** - * 获取 Bucket 下的 object 列表 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Prefix 前缀匹配,用来规定返回的文件前缀地址,非必须 - * @param {String} params.Delimiter 定界符为一个符号,如果有Prefix,则将Prefix到delimiter之间的相同路径归为一类,非必须 - * @param {String} params.Marker 默认以UTF-8二进制顺序列出条目,所有列出条目从marker开始,非必须 - * @param {String} params.MaxKeys 单次返回最大的条目数量,默认1000,非必须 - * @param {String} params.EncodingType 规定返回值的编码方式,非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {Object} data.ListBucketResult 返回的 object 列表信息 - */ -function getBucket(params, callback) { - var reqParams = {}; - reqParams['prefix'] = params['Prefix'] || ''; - reqParams['delimiter'] = params['Delimiter']; - reqParams['marker'] = params['Marker']; - reqParams['max-keys'] = params['MaxKeys']; - reqParams['encoding-type'] = params['EncodingType']; - - submitRequest.call(this, { - Action: 'name/cos:GetBucket', - ResourceKey: reqParams['prefix'], - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - qs: reqParams, - }, function (err, data) { - if (err) return callback(err); - var ListBucketResult = data.ListBucketResult || {}; - var Contents = ListBucketResult.Contents || []; - var CommonPrefixes = ListBucketResult.CommonPrefixes || []; - - Contents = util.isArray(Contents) ? Contents : [Contents]; - CommonPrefixes = util.isArray(CommonPrefixes) ? CommonPrefixes : [CommonPrefixes]; - - var result = util.clone(ListBucketResult); - util.extend(result, { - Contents: Contents, - CommonPrefixes: CommonPrefixes, - statusCode: data.statusCode, - headers: data.headers, - }); - - callback(null, result); - }); -} - -/** - * 删除 Bucket - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {String} data.Location 操作地址 - */ -function deleteBucket(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucket', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - method: 'DELETE', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 设置 Bucket 的 权限列表 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.ACL 用户自定义文件权限,可以设置:private,public-read;默认值:private,非必须 - * @param {String} params.GrantRead 赋予被授权者读的权限,格式x-cos-grant-read: uin=" ",uin=" ",非必须 - * @param {String} params.GrantWrite 赋予被授权者写的权限,格式x-cos-grant-write: uin=" ",uin=" ",非必须 - * @param {String} params.GrantFullControl 赋予被授权者读写权限,格式x-cos-grant-full-control: uin=" ",uin=" ",非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ -function putBucketAcl(params, callback) { - var headers = params.Headers; - - var xml = ''; - if (params['AccessControlPolicy']) { - var AccessControlPolicy = util.clone(params['AccessControlPolicy'] || {}); - var Grants = AccessControlPolicy.Grants || AccessControlPolicy.Grant; - Grants = util.isArray(Grants) ? Grants : [Grants]; - delete AccessControlPolicy.Grant; - delete AccessControlPolicy.Grants; - AccessControlPolicy.AccessControlList = {Grant: Grants}; - xml = util.json2xml({AccessControlPolicy: AccessControlPolicy}); - - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - } - - // Grant Header 去重 - util.each(headers, function (val, key) { - if (key.indexOf('x-cos-grant-') === 0) { - headers[key] = uniqGrant(headers[key]); - } - }); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketACL', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - headers: headers, - action: 'acl', - body: xml, - }, function (err, data) { - if (err) return callback(err); - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的 权限列表 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {Object} data.AccessControlPolicy 访问权限信息 - */ -function getBucketAcl(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:GetBucketACL', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'acl', - }, function (err, data) { - if (err) return callback(err); - var AccessControlPolicy = data.AccessControlPolicy || {}; - var Owner = AccessControlPolicy.Owner || {}; - var Grant = AccessControlPolicy.AccessControlList.Grant || []; - Grant = util.isArray(Grant) ? Grant : [Grant]; - var result = decodeAcl(AccessControlPolicy); - if (data.headers && data.headers['x-cos-acl']) { - result.ACL = data.headers['x-cos-acl']; - } - result = util.extend(result, { - Owner: Owner, - Grants: Grant, - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); -} - -/** - * 设置 Bucket 的 跨域设置 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Object} params.CORSConfiguration 相关的跨域设置,必须 - * @param {Array} params.CORSConfiguration.CORSRules 对应的跨域规则 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ -function putBucketCors(params, callback) { - - var CORSConfiguration = params['CORSConfiguration'] || {}; - var CORSRules = CORSConfiguration['CORSRules'] || params['CORSRules'] || []; - CORSRules = util.clone(util.isArray(CORSRules) ? CORSRules : [CORSRules]); - util.each(CORSRules, function (rule) { - util.each(['AllowedOrigin', 'AllowedHeader', 'AllowedMethod', 'ExposeHeader'], function (key) { - var sKey = key + 's'; - var val = rule[sKey] || rule[key] || []; - delete rule[sKey]; - rule[key] = util.isArray(val) ? val : [val]; - }); - }); - - var xml = util.json2xml({CORSConfiguration: {CORSRule: CORSRules}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketCORS', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'cors', - headers: headers, - }, function (err, data) { - if (err) return callback(err); - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的 跨域设置 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {Object} data.CORSRules Bucket的跨域设置 - */ -function getBucketCors(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketCORS', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'cors', - }, function (err, data) { - if (err) { - if (err.statusCode === 404 && err.error && err.error.Code === 'NoSuchCORSConfiguration') { - var result = { - CORSRules: [], - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; - } - var CORSConfiguration = data.CORSConfiguration || {}; - var CORSRules = CORSConfiguration.CORSRules || CORSConfiguration.CORSRule || []; - CORSRules = util.clone(util.isArray(CORSRules) ? CORSRules : [CORSRules]); - - util.each(CORSRules, function (rule) { - util.each(['AllowedOrigin', 'AllowedHeader', 'AllowedMethod', 'ExposeHeader'], function (key) { - var sKey = key + 's'; - var val = rule[sKey] || rule[key] || []; - delete rule[key]; - rule[sKey] = util.isArray(val) ? val : [val]; - }); - }); - - callback(null, { - CORSRules: CORSRules, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 删除 Bucket 的 跨域设置 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ -function deleteBucketCors(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketCORS', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'cors', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode || err.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的 地域信息 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据,包含地域信息 LocationConstraint - */ -function getBucketLocation(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketLocation', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'location', - }, function (err, data) { - if (err) return callback(err); - callback(null, data); - }); -} - -function putBucketPolicy(params, callback) { - var Policy = params['Policy']; - var PolicyStr = Policy; - try { - if (typeof Policy === 'string') { - Policy = JSON.parse(PolicyStr); - } else { - PolicyStr = JSON.stringify(Policy); - } - } catch (e) { - callback({error: 'Policy format error'}); - } - - var headers = params.Headers; - headers['Content-Type'] = 'application/json'; - headers['Content-MD5'] = util.binaryBase64(util.md5(PolicyStr)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketPolicy', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - action: 'policy', - body: PolicyStr, - headers: headers, - json: true, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的读取权限策略 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function getBucketPolicy(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketPolicy', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'policy', - rawBody: true, - }, function (err, data) { - if (err) { - if (err.statusCode && err.statusCode === 403) { - return callback({ErrorStatus: 'Access Denied'}); - } - if (err.statusCode && err.statusCode === 405) { - return callback({ErrorStatus: 'Method Not Allowed'}); - } - if (err.statusCode && err.statusCode === 404) { - return callback({ErrorStatus: 'Policy Not Found'}); - } - return callback(err); - } - var Policy = {}; - try { - Policy = JSON.parse(data.body); - } catch (e) { - } - callback(null, { - Policy: Policy, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 删除 Bucket 的 跨域设置 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ -function deleteBucketPolicy(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketPolicy', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'policy', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode || err.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 设置 Bucket 的标签 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Array} params.TagSet 标签设置,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function putBucketTagging(params, callback) { - - var Tagging = params['Tagging'] || {}; - var Tags = Tagging.TagSet || Tagging.Tags || params['Tags'] || []; - Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); - var xml = util.json2xml({Tagging: {TagSet: {Tag: Tags}}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketTagging', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'tagging', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的标签设置 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function getBucketTagging(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:GetBucketTagging', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'tagging', - }, function (err, data) { - if (err) { - if (err.statusCode === 404 && err.error && (err.error === "Not Found" || err.error.Code === 'NoSuchTagSet')) { - var result = { - Tags: [], - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; - } - var Tags = []; - try { - Tags = data.Tagging.TagSet.Tag || []; - } catch (e) { - } - Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); - callback(null, { - Tags: Tags, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 删除 Bucket 的 标签设置 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ -function deleteBucketTagging(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketTagging', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'tagging', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -function putBucketLifecycle(params, callback) { - - var LifecycleConfiguration = params['LifecycleConfiguration'] || {}; - var Rules = LifecycleConfiguration.Rules || params.Rules || []; - Rules = util.clone(Rules); - var xml = util.json2xml({LifecycleConfiguration: {Rule: Rules}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketLifecycle', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'lifecycle', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -function getBucketLifecycle(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketLifecycle', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'lifecycle', - }, function (err, data) { - if (err) { - if (err.statusCode === 404 && err.error && err.error.Code === 'NoSuchLifecycleConfiguration') { - var result = { - Rules: [], - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; - } - var Rules = []; - try { - Rules = data.LifecycleConfiguration.Rule || []; - } catch (e) { - } - Rules = util.clone(util.isArray(Rules) ? Rules : [Rules]); - callback(null, { - Rules: Rules, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -function deleteBucketLifecycle(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketLifecycle', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'lifecycle', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -function putBucketVersioning(params, callback) { - - if (!params['VersioningConfiguration']) { - callback({error: 'missing param VersioningConfiguration'}); - return; - } - var VersioningConfiguration = params['VersioningConfiguration'] || {}; - var xml = util.json2xml({VersioningConfiguration: VersioningConfiguration}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketVersioning', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'versioning', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -function getBucketVersioning(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketVersioning', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'versioning', - }, function (err, data) { - if (!err) { - !data.VersioningConfiguration && (data.VersioningConfiguration = {}); - } - callback(err, data); - }); -} - -function putBucketReplication(params, callback) { - var ReplicationConfiguration = util.clone(params.ReplicationConfiguration); - var xml = util.json2xml({ReplicationConfiguration: ReplicationConfiguration}); - xml = xml.replace(/<(\/?)Rules>/ig, '<$1Rule>'); - xml = xml.replace(/<(\/?)Tags>/ig, '<$1Tag>'); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketReplication', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'replication', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -function getBucketReplication(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketReplication', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'replication', - }, function (err, data) { - if (err) { - if (err.statusCode === 404 && err.error && (err.error === 'Not Found' || err.error.Code === 'ReplicationConfigurationnotFoundError')) { - var result = { - ReplicationConfiguration: {Rules: []}, - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; - } - if (!err) { - !data.ReplicationConfiguration && (data.ReplicationConfiguration = {}); - } - if (data.ReplicationConfiguration.Rule) { - data.ReplicationConfiguration.Rules = data.ReplicationConfiguration.Rule; - delete data.ReplicationConfiguration.Rule; - } - callback(err, data); - }); -} - -function deleteBucketReplication(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketReplication', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'replication', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 设置 Bucket 静态网站配置信息 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Object} params.WebsiteConfiguration 地域名称,必须 - * @param {Object} WebsiteConfiguration.IndexDocument 索引文档,必须 - * @param {Object} WebsiteConfiguration.ErrorDocument 错误文档,非必须 - * @param {Object} WebsiteConfiguration.RedirectAllRequestsTo 重定向所有请求,非必须 - * @param {Array} params.RoutingRules 重定向规则,非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function putBucketWebsite(params, callback) { - - if (!params['WebsiteConfiguration']) { - callback({ error: 'missing param WebsiteConfiguration' }); - return; - } - - var WebsiteConfiguration = util.clone(params['WebsiteConfiguration'] || {}); - var RoutingRules = WebsiteConfiguration['RoutingRules'] || WebsiteConfiguration['RoutingRule'] || []; - RoutingRules = util.isArray(RoutingRules) ? RoutingRules : [RoutingRules]; - delete WebsiteConfiguration.RoutingRule; - delete WebsiteConfiguration.RoutingRules; - if (RoutingRules.length) WebsiteConfiguration.RoutingRules = { RoutingRule: RoutingRules }; - var xml = util.json2xml({ WebsiteConfiguration: WebsiteConfiguration }); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketWebsite', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'website', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的静态网站配置信息 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function getBucketWebsite(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:GetBucketWebsite', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - action: 'website', - }, function (err, data) { - if (err) { - if(err.statusCode === 404 && err.error.Code === 'NoSuchWebsiteConfiguration'){ - var result = { - WebsiteConfiguration: {}, - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; - } - - var WebsiteConfiguration = data.WebsiteConfiguration || {}; - if (WebsiteConfiguration['RoutingRules']) { - var RoutingRules = util.clone(WebsiteConfiguration['RoutingRules'].RoutingRule || []); - RoutingRules = util.makeArray(RoutingRules); - WebsiteConfiguration.RoutingRules = RoutingRules; - } - - callback(null, { - WebsiteConfiguration: WebsiteConfiguration, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 删除 Bucket 的静态网站配置 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function deleteBucketWebsite(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketWebsite', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'website', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 设置 Bucket 的防盗链白名单或者黑名单 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Object} params.RefererConfiguration 地域名称,必须 - * @param {String} RefererConfiguration.Status 是否开启防盗链,枚举值:Enabled、Disabled - * @param {String} RefererConfiguration.RefererType 防盗链类型,枚举值:Black-List、White-List,必须 - * @param {Array} RefererConfiguration.DomianList.Domain 生效域名,必须 - * @param {String} RefererConfiguration.EmptyReferConfiguration ,非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function putBucketReferer(params, callback) { - - if (!params['RefererConfiguration']) { - callback({ error: 'missing param RefererConfiguration' }); - return; - } - - var RefererConfiguration = util.clone(params['RefererConfiguration'] || {}); - var DomainList = RefererConfiguration['DomainList'] || {}; - var Domains = DomainList['Domains'] || DomainList['Domain'] || []; - Domains = util.isArray(Domains) ? Domains : [Domains]; - if (Domains.length) RefererConfiguration.DomainList = {Domain: Domains}; - var xml = util.json2xml({ RefererConfiguration: RefererConfiguration }); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketReferer', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'referer', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的防盗链白名单或者黑名单 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function getBucketReferer(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:GetBucketReferer', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - action: 'referer', - }, function (err, data) { - if (err) { - if(err.statusCode === 404 && err.error.Code === 'NoSuchRefererConfiguration'){ - var result = { - WebsiteConfiguration: {}, - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; - } - - var RefererConfiguration = data.RefererConfiguration || {}; - if (RefererConfiguration['DomainList']) { - var Domains = util.clone(RefererConfiguration['DomainList'].Domain || []); - Domains = util.makeArray(Domains); - RefererConfiguration.DomainList = {Domains: Domains}; - } - - callback(null, { - RefererConfiguration: RefererConfiguration, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 设置 Bucket 自定义域名 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function putBucketDomain(params, callback) { - - var DomainConfiguration = params['DomainConfiguration'] || {}; - var DomainRule = DomainConfiguration.DomainRule || params.DomainRule || []; - DomainRule = util.clone(DomainRule); - var xml = util.json2xml({DomainConfiguration: {DomainRule: DomainRule}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketDomain', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'domain', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的自定义域名 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function getBucketDomain(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:GetBucketDomain', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'domain', - }, function (err, data) { - if (err) return callback(err); - - var DomainRule = []; - try { - DomainRule = data.DomainConfiguration.DomainRule || []; - } catch (e) { - } - DomainRule = util.clone(util.isArray(DomainRule) ? DomainRule : [DomainRule]); - callback(null, { - DomainRule: DomainRule, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 删除 Bucket 自定义域名 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function deleteBucketDomain(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketDomain', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'domain', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 设置 Bucket 的回源 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function putBucketOrigin(params, callback){ - var OriginConfiguration = params['OriginConfiguration'] || {}; - var OriginRule = OriginConfiguration.OriginRule || params.OriginRule || []; - OriginRule = util.clone(OriginRule); - var xml = util.json2xml({OriginConfiguration: {OriginRule: OriginRule}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketOrigin', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'origin', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的回源 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function getBucketOrigin(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:GetBucketOrigin', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'origin', - }, function (err, data) { - if (err) return callback(err); - - var OriginRule = []; - try { - OriginRule = data.OriginConfiguration.OriginRule || []; - } catch (e) { - } - OriginRule = util.clone(util.isArray(OriginRule) ? OriginRule : [OriginRule]); - callback(null, { - OriginRule: OriginRule, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 删除 Bucket 的回源 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function deleteBucketOrigin(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketOrigin', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'origin', - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 设置 Bucket 的日志记录 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {(Object|String)} params.BucketLoggingStatus 说明日志记录配置的状态,如果无子节点信息则意为关闭日志记录,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function putBucketLogging(params, callback) { - var xml = util.json2xml({ - BucketLoggingStatus: params['BucketLoggingStatus'] || '' - }); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketLogging', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'logging', - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的日志记录 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function getBucketLogging(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketLogging', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'logging', - }, function (err, data) { - if (err) return callback(err); - delete data.BucketLoggingStatus._xmlns; - callback(null, { - BucketLoggingStatus: data.BucketLoggingStatus, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 创建/编辑 Bucket 的清单任务 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Id 清单任务的名称,必须 - * @param {Object} params.InventoryConfiguration 包含清单的配置参数,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function putBucketInventory(params, callback) { - var InventoryConfiguration = util.clone(params['InventoryConfiguration']); - - if (InventoryConfiguration.OptionalFields) { - var Field = InventoryConfiguration.OptionalFields || []; - InventoryConfiguration.OptionalFields = { - Field: Field - }; - } - - if (InventoryConfiguration.Destination - && InventoryConfiguration.Destination.COSBucketDestination - && InventoryConfiguration.Destination.COSBucketDestination.Encryption - ) { - var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption; - if (Object.keys(Encryption).indexOf('SSECOS') > -1) { - Encryption['SSE-COS'] = Encryption['SSECOS']; - delete Encryption['SSECOS']; - } - } - - var xml = util.json2xml({ - InventoryConfiguration: InventoryConfiguration - }); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:PutBucketInventory', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'inventory', - qs: { - id: params['Id'] - }, - headers: headers, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的清单任务信息 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Id 清单任务的名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function getBucketInventory(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:GetBucketInventory', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'inventory', - qs: { - id: params['Id'] - } - }, function (err, data) { - if (err) return callback(err); - - var InventoryConfiguration = data['InventoryConfiguration']; - if (InventoryConfiguration && InventoryConfiguration.OptionalFields && InventoryConfiguration.OptionalFields.Field) { - var Field = InventoryConfiguration.OptionalFields.Field; - if (!util.isArray(Field)) { - Field = [Field]; - } - InventoryConfiguration.OptionalFields = Field; - } - if (InventoryConfiguration.Destination - && InventoryConfiguration.Destination.COSBucketDestination - && InventoryConfiguration.Destination.COSBucketDestination.Encryption - ) { - var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption; - if (Object.keys(Encryption).indexOf('SSE-COS') > -1) { - Encryption['SSECOS'] = Encryption['SSE-COS']; - delete Encryption['SSE-COS']; - } - } - - callback(null, { - InventoryConfiguration: InventoryConfiguration, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Bucket 的清单任务信息 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.ContinuationToken 当 COS 响应体中 IsTruncated 为 true,且 NextContinuationToken 节点中存在参数值时,您可以将这个参数作为 continuation-token 参数值,以获取下一页的清单任务信息,非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function listBucketInventory(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:ListBucketInventory', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'inventory', - qs: { - 'continuation-token': params['ContinuationToken'] - } - }, function (err, data) { - if (err) return callback(err); - var ListInventoryConfigurationResult = data['ListInventoryConfigurationResult']; - var InventoryConfigurations = ListInventoryConfigurationResult.InventoryConfiguration || []; - InventoryConfigurations = util.isArray(InventoryConfigurations) ? InventoryConfigurations : [InventoryConfigurations]; - delete ListInventoryConfigurationResult['InventoryConfiguration']; - util.each(InventoryConfigurations, function (InventoryConfiguration) { - if (InventoryConfiguration && InventoryConfiguration.OptionalFields && InventoryConfiguration.OptionalFields.Field) { - var Field = InventoryConfiguration.OptionalFields.Field; - if (!util.isArray(Field)) { - Field = [Field]; - } - InventoryConfiguration.OptionalFields = Field; - } - - if (InventoryConfiguration.Destination - && InventoryConfiguration.Destination.COSBucketDestination - && InventoryConfiguration.Destination.COSBucketDestination.Encryption - ) { - var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption; - if (Object.keys(Encryption).indexOf('SSE-COS') > -1) { - Encryption['SSECOS'] = Encryption['SSE-COS']; - delete Encryption['SSE-COS']; - } - } - }); - ListInventoryConfigurationResult.InventoryConfigurations = InventoryConfigurations; - util.extend(ListInventoryConfigurationResult, { - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, ListInventoryConfigurationResult); - }); -} - -/** - * 删除 Bucket 的清单任务 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Id 清单任务的名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回数据 - */ -function deleteBucketInventory(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteBucketInventory', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'inventory', - qs: { - id: params['Id'] - } - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/* 全球加速 */ -function putBucketAccelerate(params, callback) { - - if (!params['AccelerateConfiguration']) { - callback({error: 'missing param AccelerateConfiguration'}); - return; - } - - var configuration = { AccelerateConfiguration: params.AccelerateConfiguration || {} }; - - var xml = util.json2xml(configuration); - - var headers = {}; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Interface: 'putBucketAccelerate', - Action: 'name/cos:PutBucketAccelerate', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'accelerate', - headers: headers, - }, function (err, data) { - if (err) return callback(err); - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -function getBucketAccelerate(params, callback) { - submitRequest.call(this, { - Interface: 'getBucketAccelerate', - Action: 'name/cos:GetBucketAccelerate', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - action: 'accelerate', - }, function (err, data) { - if (!err) { - !data.AccelerateConfiguration && (data.AccelerateConfiguration = {}); - } - callback(err, data); - }); -} - -// Object 相关 - -/** - * 取回对应Object的元数据,Head的权限与Get的权限一致 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key 文件名称,必须 - * @param {String} params.IfModifiedSince 当Object在指定时间后被修改,则返回对应Object元信息,否则返回304,非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 为指定 object 的元数据,如果设置了 IfModifiedSince ,且文件未修改,则返回一个对象,NotModified 属性为 true - * @return {Boolean} data.NotModified 是否在 IfModifiedSince 时间点之后未修改该 object,则为 true - */ -function headObject(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:HeadObject', - method: 'HEAD', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - VersionId: params.VersionId, - headers: params.Headers, - }, function (err, data) { - if (err) { - var statusCode = err.statusCode; - if (params.Headers['If-Modified-Since'] && statusCode && statusCode === 304) { - return callback(null, { - NotModified: true, - statusCode: statusCode, - }); - } - return callback(err); - } - data.ETag = util.attr(data.headers, 'etag', ''); - callback(null, data); - }); -} - - -function listObjectVersions(params, callback) { - var reqParams = {}; - reqParams['prefix'] = params['Prefix'] || ''; - reqParams['delimiter'] = params['Delimiter']; - reqParams['key-marker'] = params['KeyMarker']; - reqParams['version-id-marker'] = params['VersionIdMarker']; - reqParams['max-keys'] = params['MaxKeys']; - reqParams['encoding-type'] = params['EncodingType']; - - submitRequest.call(this, { - Action: 'name/cos:GetBucketObjectVersions', - ResourceKey: reqParams['prefix'], - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - qs: reqParams, - action: 'versions', - }, function (err, data) { - if (err) return callback(err); - var ListVersionsResult = data.ListVersionsResult || {}; - var DeleteMarkers = ListVersionsResult.DeleteMarker || []; - DeleteMarkers = util.isArray(DeleteMarkers) ? DeleteMarkers : [DeleteMarkers]; - var Versions = ListVersionsResult.Version || []; - Versions = util.isArray(Versions) ? Versions : [Versions]; - - var result = util.clone(ListVersionsResult); - delete result.DeleteMarker; - delete result.Version; - util.extend(result, { - DeleteMarkers: DeleteMarkers, - Versions: Versions, - statusCode: data.statusCode, - headers: data.headers, - }); - - callback(null, result); - }); -} - -/** - * 下载 object - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key 文件名称,必须 - * @param {WriteStream} params.Output 文件写入流,非必须 - * @param {String} params.IfModifiedSince 当Object在指定时间后被修改,则返回对应Object元信息,否则返回304,非必须 - * @param {String} params.IfUnmodifiedSince 如果文件修改时间早于或等于指定时间,才返回文件内容。否则返回 412 (precondition failed),非必须 - * @param {String} params.IfMatch 当 ETag 与指定的内容一致,才返回文件。否则返回 412 (precondition failed),非必须 - * @param {String} params.IfNoneMatch 当 ETag 与指定的内容不一致,才返回文件。否则返回304 (not modified),非必须 - * @param {String} params.ResponseContentType 设置返回头部中的 Content-Type 参数,非必须 - * @param {String} params.ResponseContentLanguage 设置返回头部中的 Content-Language 参数,非必须 - * @param {String} params.ResponseExpires 设置返回头部中的 Content-Expires 参数,非必须 - * @param {String} params.ResponseCacheControl 设置返回头部中的 Cache-Control 参数,非必须 - * @param {String} params.ResponseContentDisposition 设置返回头部中的 Content-Disposition 参数,非必须 - * @param {String} params.ResponseContentEncoding 设置返回头部中的 Content-Encoding 参数,非必须 - * @param {Function} callback 回调函数,必须 - * @param {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @param {Object} data 为对应的 object 数据,包括 body 和 headers - */ -function getObject(params, callback) { - var reqParams = params.Query || {}; - var reqParamsStr = params.QueryString || ''; - - reqParams['response-content-type'] = params['ResponseContentType']; - reqParams['response-content-language'] = params['ResponseContentLanguage']; - reqParams['response-expires'] = params['ResponseExpires']; - reqParams['response-cache-control'] = params['ResponseCacheControl']; - reqParams['response-content-disposition'] = params['ResponseContentDisposition']; - reqParams['response-content-encoding'] = params['ResponseContentEncoding']; - - // 如果用户自己传入了 output - submitRequest.call(this, { - Action: 'name/cos:GetObject', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - VersionId: params.VersionId, - headers: params.Headers, - qs: reqParams, - qsStr: reqParamsStr, - rawBody: true, - }, function (err, data) { - if (err) { - var statusCode = err.statusCode; - if (params.Headers['If-Modified-Since'] && statusCode && statusCode === 304) { - return callback(null, { - NotModified: true - }); - } - return callback(err); - } - callback(null, { - Body: data.body, - ETag: util.attr(data.headers, 'etag', ''), - statusCode: data.statusCode, - headers: data.headers, - }); - }); - -} - -/** - * 上传 object - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key 文件名称,必须 - * @param {String} params.Body 上传文件的内容,只支持字符串 - * @param {String} params.CacheControl RFC 2616 中定义的缓存策略,将作为 Object 元数据保存,非必须 - * @param {String} params.ContentDisposition RFC 2616 中定义的文件名称,将作为 Object 元数据保存,非必须 - * @param {String} params.ContentEncoding RFC 2616 中定义的编码格式,将作为 Object 元数据保存,非必须 - * @param {String} params.ContentLength RFC 2616 中定义的 HTTP 请求内容长度(字节),必须 - * @param {String} params.ContentType RFC 2616 中定义的内容类型(MIME),将作为 Object 元数据保存,非必须 - * @param {String} params.Expect 当使用 Expect: 100-continue 时,在收到服务端确认后,才会发送请求内容,非必须 - * @param {String} params.Expires RFC 2616 中定义的过期时间,将作为 Object 元数据保存,非必须 - * @param {String} params.ContentSha1 RFC 3174 中定义的 160-bit 内容 SHA-1 算法校验,非必须 - * @param {String} params.ACL 允许用户自定义文件权限,有效值:private | public-read,非必须 - * @param {String} params.GrantRead 赋予被授权者读的权限,格式 x-cos-grant-read: uin=" ",uin=" ",非必须 - * @param {String} params.GrantWrite 赋予被授权者写的权限,格式 x-cos-grant-write: uin=" ",uin=" ",非必须 - * @param {String} params.GrantFullControl 赋予被授权者读写权限,格式 x-cos-grant-full-control: uin=" ",uin=" ",非必须 - * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须 - * @param {Function} params.onProgress 上传进度回调函数 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 为对应的 object 数据 - * @return {String} data.ETag 为对应上传文件的 ETag 值 - */ -function putObject(params, callback) { - var self = this; - var FileSize = params.ContentLength; - var onProgress = util.throttleOnProgress.call(self, FileSize, params.onProgress); - - // 特殊处理 Cache-Control、Content-Type,避免代理更改这两个字段导致写入到 Object 属性里 - var headers = params.Headers; - if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = ''; - if (!headers['Content-Type'] && !headers['content-type']) headers['Content-Type'] = mime.getType(params.Key) || 'application/octet-stream'; - - util.getBodyMd5(self.options.UploadCheckContentMd5, params.Body, function (md5) { - if (md5) headers['Content-MD5'] = util.binaryBase64(md5); - if (params.ContentLength !== undefined) headers['Content-Length'] = params.ContentLength; - onProgress(null, true); // 任务状态开始 uploading - submitRequest.call(self, { - Action: 'name/cos:PutObject', - TaskId: params.TaskId, - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - qs: params.Query, - body: params.Body, - onProgress: onProgress, - }, function (err, data) { - if (err) { - onProgress(null, true); - return callback(err); - } - onProgress({loaded: FileSize, total: FileSize}, true); - var url = getUrl({ - ForcePathStyle: self.options.ForcePathStyle, - protocol: self.options.Protocol, - domain: self.options.Domain, - bucket: params.Bucket, - region: !self.options.UseAccelerate ? params.Region : 'accelerate', - object: params.Key, - }); - url = url.substr(url.indexOf('://') + 3); - data.Location = url; - data.ETag = util.attr(data.headers, 'etag', ''); - callback(null, data); - }); - }); -} - -/** - * 上传 object - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key 文件名称,必须 - * @param {FilePath} params.FilePath 要上传的文件路径 - * @param {Function} params.onProgress 上传进度回调函数 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 为对应的 object 数据 - * @return {String} data.ETag 为对应上传文件的 ETag 值 - */ -function postObject(params, callback) { - var self = this; - var headers = {}; - var filePath = params.FilePath; - if (!filePath) { - callback({error: 'missing param FilePath'}); - return; - } - - headers['Cache-Control'] = params['CacheControl']; - headers['Content-Disposition'] = params['ContentDisposition']; - headers['Content-Encoding'] = params['ContentEncoding']; - headers['Content-MD5'] = params['ContentMD5']; - headers['Content-Length'] = params['ContentLength']; - headers['Content-Type'] = params['ContentType']; - headers['Expect'] = params['Expect']; - headers['Expires'] = params['Expires']; - headers['x-cos-acl'] = params['ACL']; - headers['x-cos-grant-read'] = params['GrantRead']; - headers['x-cos-grant-write'] = params['GrantWrite']; - headers['x-cos-grant-full-control'] = params['GrantFullControl']; - headers['x-cos-storage-class'] = params['StorageClass']; - - // 删除 Content-Length 避免签名错误 - delete headers['Content-Length']; - delete headers['content-length']; - - for (var key in params) { - if (key.indexOf('x-cos-meta-') > -1) { - headers[key] = params[key]; - } - } - - var onProgress = util.throttleOnProgress.call(self, headers['Content-Length'], params.onProgress); - - submitRequest.call(this, { - Action: 'name/cos:PostObject', - method: 'POST', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: headers, - qs: params.Query, - filePath: filePath, - onProgress: onProgress, - }, function (err, data) { - onProgress(null, true); - if (err) return callback(err); - if (data && data.headers) { - var headers = data.headers; - var ETag = headers.etag || headers.Etag || headers.ETag || ''; - var filename = filePath.substr(filePath.lastIndexOf('/') + 1); - var url = getUrl({ - ForcePathStyle: self.options.ForcePathStyle, - protocol: self.options.Protocol, - domain: self.options.Domain, - bucket: params.Bucket, - region: params.Region, - object: params.Key.replace(/\$\{filename\}/g, filename), - isLocation: true, - }); - - return callback(null, { - Location: url, - statusCode: data.statusCode, - headers: headers, - ETag: ETag, - }); - } - callback(null, data); - }); -} - -/** - * 删除 object - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {Function} callback 回调函数,必须 - * @param {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @param {Object} data 删除操作成功之后返回的数据 - */ -function deleteObject(params, callback) { - submitRequest.call(this, { - Action: 'name/cos:DeleteObject', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - VersionId: params.VersionId, - }, function (err, data) { - if (err) { - var statusCode = err.statusCode; - if (statusCode && statusCode === 204) { - return callback(null, {statusCode: statusCode}); - } else if (statusCode && statusCode === 404) { - return callback(null, {BucketNotFound: true, statusCode: statusCode,}); - } else { - return callback(err); - } - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 object 的 权限列表 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {Object} data.AccessControlPolicy 权限列表 - */ -function getObjectAcl(params, callback) { - - submitRequest.call(this, { - Action: 'name/cos:GetObjectACL', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - action: 'acl', - }, function (err, data) { - if (err) return callback(err); - var AccessControlPolicy = data.AccessControlPolicy || {}; - var Owner = AccessControlPolicy.Owner || {}; - var Grant = AccessControlPolicy.AccessControlList && AccessControlPolicy.AccessControlList.Grant || []; - Grant = util.isArray(Grant) ? Grant : [Grant]; - var result = decodeAcl(AccessControlPolicy); - if (data.headers && data.headers['x-cos-acl']) { - result.ACL = data.headers['x-cos-acl']; - } - result = util.extend(result, { - Owner: Owner, - Grants: Grant, - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); -} - -/** - * 设置 object 的 权限列表 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ -function putObjectAcl(params, callback) { - var headers = params.Headers; - - var xml = ''; - if (params['AccessControlPolicy']) { - var AccessControlPolicy = util.clone(params['AccessControlPolicy'] || {}); - var Grants = AccessControlPolicy.Grants || AccessControlPolicy.Grant; - Grants = util.isArray(Grants) ? Grants : [Grants]; - delete AccessControlPolicy.Grant; - delete AccessControlPolicy.Grants; - AccessControlPolicy.AccessControlList = {Grant: Grants}; - xml = util.json2xml({AccessControlPolicy: AccessControlPolicy}); - - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - } - - // Grant Header 去重 - util.each(headers, function (val, key) { - if (key.indexOf('x-cos-grant-') === 0) { - headers[key] = uniqGrant(headers[key]); - } - }); - - submitRequest.call(this, { - Action: 'name/cos:PutObjectACL', - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - action: 'acl', - headers: headers, - body: xml, - }, function (err, data) { - if (err) return callback(err); - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * Options Object请求实现跨域访问的预请求。即发出一个 OPTIONS 请求给服务器以确认是否可以进行跨域操作。 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ -function optionsObject(params, callback) { - - var headers = params.Headers; - headers['Origin'] = params['Origin']; - headers['Access-Control-Request-Method'] = params['AccessControlRequestMethod']; - headers['Access-Control-Request-Headers'] = params['AccessControlRequestHeaders']; - - submitRequest.call(this, { - Action: 'name/cos:OptionsObject', - method: 'OPTIONS', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: headers, - }, function (err, data) { - if (err) { - if (err.statusCode && err.statusCode === 403) { - return callback(null, { - OptionsForbidden: true, - statusCode: err.statusCode - }); - } - return callback(err); - } - - var headers = data.headers || {}; - callback(null, { - AccessControlAllowOrigin: headers['access-control-allow-origin'], - AccessControlAllowMethods: headers['access-control-allow-methods'], - AccessControlAllowHeaders: headers['access-control-allow-headers'], - AccessControlExposeHeaders: headers['access-control-expose-headers'], - AccessControlMaxAge: headers['access-control-max-age'], - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * @param {Object} 参数列表 - * @param {String} Bucket Bucket 名称 - * @param {String} Region 地域名称 - * @param {String} Key 文件名称 - * @param {String} CopySource 源文件URL绝对路径,可以通过versionid子资源指定历史版本 - * @param {String} ACL 允许用户自定义文件权限。有效值:private,public-read默认值:private。 - * @param {String} GrantRead 赋予被授权者读的权限,格式 x-cos-grant-read: uin=" ",uin=" ",当需要给子账户授权时,uin="RootAcountID/SubAccountID",当需要给根账户授权时,uin="RootAcountID"。 - * @param {String} GrantWrite 赋予被授权者写的权限,格式 x-cos-grant-write: uin=" ",uin=" ",当需要给子账户授权时,uin="RootAcountID/SubAccountID",当需要给根账户授权时,uin="RootAcountID"。 - * @param {String} GrantFullControl 赋予被授权者读写权限,格式 x-cos-grant-full-control: uin=" ",uin=" ",当需要给子账户授权时,uin="RootAcountID/SubAccountID",当需要给根账户授权时,uin="RootAcountID"。 - * @param {String} MetadataDirective 是否拷贝元数据,枚举值:Copy, Replaced,默认值Copy。假如标记为Copy,忽略Header中的用户元数据信息直接复制;假如标记为Replaced,按Header信息修改元数据。当目标路径和原路径一致,即用户试图修改元数据时,必须为Replaced - * @param {String} CopySourceIfModifiedSince 当Object在指定时间后被修改,则执行操作,否则返回412。可与x-cos-copy-source-If-None-Match一起使用,与其他条件联合使用返回冲突。 - * @param {String} CopySourceIfUnmodifiedSince 当Object在指定时间后未被修改,则执行操作,否则返回412。可与x-cos-copy-source-If-Match一起使用,与其他条件联合使用返回冲突。 - * @param {String} CopySourceIfMatch 当Object的ETag和给定一致时,则执行操作,否则返回412。可与x-cos-copy-source-If-Unmodified-Since一起使用,与其他条件联合使用返回冲突。 - * @param {String} CopySourceIfNoneMatch 当Object的ETag和给定不一致时,则执行操作,否则返回412。可与x-cos-copy-source-If-Modified-Since一起使用,与其他条件联合使用返回冲突。 - * @param {String} StorageClass 存储级别,枚举值:存储级别,枚举值:Standard, Standard_IA,Archive;默认值:Standard - * @param {String} CacheControl 指定所有缓存机制在整个请求/响应链中必须服从的指令。 - * @param {String} ContentDisposition MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件 - * @param {String} ContentEncoding HTTP 中用来对「采用何种编码格式传输正文」进行协定的一对头部字段 - * @param {String} ContentLength 设置响应消息的实体内容的大小,单位为字节 - * @param {String} ContentType RFC 2616 中定义的 HTTP 请求内容类型(MIME),例如text/plain - * @param {String} Expect 请求的特定的服务器行为 - * @param {String} Expires 响应过期的日期和时间 - * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须 - * @param {String} ContentLanguage 指定内容语言 - * @param {String} x-cos-meta-* 允许用户自定义的头部信息,将作为 Object 元数据返回。大小限制2K。 - */ -function putObjectCopy(params, callback) { - - // 特殊处理 Cache-Control - var headers = params.Headers; - if (!headers['Cache-Control'] && !!headers['cache-control']) headers['Cache-Control'] = ''; - - var CopySource = params.CopySource || ''; - var m = CopySource.match(/^([^.]+-\d+)\.cos(v6)?\.([^.]+)\.[^/]+\/(.+)$/); - if (!m) { - callback({error: 'CopySource format error'}); - return; - } - - var SourceBucket = m[1]; - var SourceRegion = m[3]; - var SourceKey = decodeURIComponent(m[4]); - - submitRequest.call(this, { - Scope: [{ - action: 'name/cos:GetObject', - bucket: SourceBucket, - region: SourceRegion, - prefix: SourceKey, - }, { - action: 'name/cos:PutObject', - bucket: params.Bucket, - region: params.Region, - prefix: params.Key, - }], - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - VersionId: params.VersionId, - headers: params.Headers, - }, function (err, data) { - if (err) return callback(err); - var result = util.clone(data.CopyObjectResult || {}); - util.extend(result, { - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); -} - -function uploadPartCopy(params, callback) { - - var CopySource = params.CopySource || ''; - var m = CopySource.match(/^([^.]+-\d+)\.cos(v6)?\.([^.]+)\.[^/]+\/(.+)$/); - if (!m) { - callback({error: 'CopySource format error'}); - return; - } - - var SourceBucket = m[1]; - var SourceRegion = m[3]; - var SourceKey = decodeURIComponent(m[4]); - - submitRequest.call(this, { - Scope: [{ - action: 'name/cos:GetObject', - bucket: SourceBucket, - region: SourceRegion, - prefix: SourceKey, - }, { - action: 'name/cos:PutObject', - bucket: params.Bucket, - region: params.Region, - prefix: params.Key, - }], - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - VersionId: params.VersionId, - qs: { - partNumber: params['PartNumber'], - uploadId: params['UploadId'], - }, - headers: params.Headers, - }, function (err, data) { - if (err) return callback(err); - var result = util.clone(data.CopyPartResult || {}); - util.extend(result, { - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); -} - -function deleteMultipleObject(params, callback) { - var Objects = params.Objects || []; - var Quiet = params.Quiet; - Objects = util.isArray(Objects) ? Objects : [Objects]; - - var xml = util.json2xml({Delete: {Object: Objects, Quiet: Quiet || false}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - var Scope = util.map(Objects, function (v) { - return { - action: 'name/cos:DeleteObject', - bucket: params.Bucket, - region: params.Region, - prefix: v.Key, - }; - }); - - submitRequest.call(this, { - Scope: Scope, - method: 'POST', - Bucket: params.Bucket, - Region: params.Region, - body: xml, - action: 'delete', - headers: headers, - }, function (err, data) { - if (err) return callback(err); - var DeleteResult = data.DeleteResult || {}; - var Deleted = DeleteResult.Deleted || []; - var Errors = DeleteResult.Error || []; - - Deleted = util.isArray(Deleted) ? Deleted : [Deleted]; - Errors = util.isArray(Errors) ? Errors : [Errors]; - - var result = util.clone(DeleteResult); - util.extend(result, { - Error: Errors, - Deleted: Deleted, - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); -} - -function restoreObject(params, callback) { - var headers = params.Headers; - if (!params['RestoreRequest']) { - callback({error: 'missing param RestoreRequest'}); - return; - } - - var RestoreRequest = params.RestoreRequest || {}; - var xml = util.json2xml({RestoreRequest: RestoreRequest}); - - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:RestoreObject', - method: 'POST', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - VersionId: params.VersionId, - body: xml, - action: 'restore', - headers: headers, - }, function (err, data) { - callback(err, data); - }); -} - -/** - * 设置 Object 的标签 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Object名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Array} params.TagSet 标签设置,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/42998 - * @return {Object} data 返回数据 - */ -function putObjectTagging(params, callback) { - - var Tagging = params['Tagging'] || {}; - var Tags = Tagging.TagSet || Tagging.Tags || params['Tags'] || []; - Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); - var xml = util.json2xml({Tagging: {TagSet: {Tag: Tags}}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Interface: 'putObjectTagging', - Action: 'name/cos:PutObjectTagging', - method: 'PUT', - Bucket: params.Bucket, - Key: params.Key, - Region: params.Region, - body: xml, - action: 'tagging', - headers: headers, - VersionId: params.VersionId, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 获取 Object 的标签设置 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/42998 - * @return {Object} data 返回数据 - */ -function getObjectTagging(params, callback) { - - submitRequest.call(this, { - Interface: 'getObjectTagging', - Action: 'name/cos:GetObjectTagging', - method: 'GET', - Key: params.Key, - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - action: 'tagging', - VersionId: params.VersionId, - }, function (err, data) { - if (err) { - if (err.statusCode === 404 && err.error && (err.error === "Not Found" || err.error.Code === 'NoSuchTagSet')) { - var result = { - Tags: [], - statusCode: err.statusCode, - }; - err.headers && (result.headers = err.headers); - callback(null, result); - } else { - callback(err); - } - return; - } - var Tags = []; - try { - Tags = data.Tagging.TagSet.Tag || []; - } catch (e) { - } - Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); - callback(null, { - Tags: Tags, - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - -/** - * 删除 Object 的 标签设置 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Object名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/42998 - * @return {Object} data 返回的数据 - */ -function deleteObjectTagging(params, callback) { - submitRequest.call(this, { - Interface: 'deleteObjectTagging', - Action: 'name/cos:DeleteObjectTagging', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - action: 'tagging', - VersionId: params.VersionId, - }, function (err, data) { - if (err && err.statusCode === 204) { - return callback(null, {statusCode: err.statusCode}); - } else if (err) { - return callback(err); - } - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - - -// 分块上传 - - -/** - * 初始化分块上传 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {String} params.UploadId object名称,必须 - * @param {String} params.CacheControl RFC 2616 中定义的缓存策略,将作为 Object 元数据保存,非必须 - * @param {String} params.ContentDisposition RFC 2616 中定义的文件名称,将作为 Object 元数据保存 ,非必须 - * @param {String} params.ContentEncoding RFC 2616 中定义的编码格式,将作为 Object 元数据保存,非必须 - * @param {String} params.ContentType RFC 2616 中定义的内容类型(MIME),将作为 Object 元数据保存,非必须 - * @param {String} params.Expires RFC 2616 中定义的过期时间,将作为 Object 元数据保存,非必须 - * @param {String} params.ACL 允许用户自定义文件权限,非必须 - * @param {String} params.GrantRead 赋予被授权者读的权限 ,非必须 - * @param {String} params.GrantWrite 赋予被授权者写的权限 ,非必须 - * @param {String} params.GrantFullControl 赋予被授权者读写权限 ,非必须 - * @param {String} params.StorageClass 设置Object的存储级别,枚举值:Standard,Standard_IA,Archive,非必须 - * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ -function multipartInit(params, callback) { - - var self = this; - var headers = params.Headers; - - // 特殊处理 Cache-Control、Content-Type - if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = ''; - if (!headers['Content-Type'] && !headers['content-type']) headers['Content-Type'] = mime.getType(params.Key) || 'application/octet-stream'; - - submitRequest.call(self, { - Action: 'name/cos:InitiateMultipartUpload', - method: 'POST', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - action: 'uploads', - headers: params.Headers, - qs: params.Query, - }, function (err, data) { - if (err) return callback(err); - data = util.clone(data || {}); - if (data && data.InitiateMultipartUploadResult) { - return callback(null, util.extend(data.InitiateMultipartUploadResult, { - statusCode: data.statusCode, - headers: data.headers, - })); - } - callback(null, data); - }); -} - -/** - * 分块上传 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {String} params.Body 上传文件对象或字符串 - * @param {String} params.ContentLength RFC 2616 中定义的 HTTP 请求内容长度(字节),非必须 - * @param {String} params.Expect 当使用 Expect: 100-continue 时,在收到服务端确认后,才会发送请求内容,非必须 - * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须 - * @param {String} params.ContentSha1 RFC 3174 中定义的 160-bit 内容 SHA-1 算法校验值,非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {Object} data.ETag 返回的文件分块 sha1 值 - */ -function multipartUpload(params, callback) { - - var self = this; - util.getFileSize('multipartUpload', params, function () { - util.getBodyMd5(self.options.UploadCheckContentMd5, params.Body, function (md5) { - if (md5) params.Headers['Content-MD5'] = util.binaryBase64(md5); - submitRequest.call(self, { - Action: 'name/cos:UploadPart', - TaskId: params.TaskId, - method: 'PUT', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - qs: { - partNumber: params['PartNumber'], - uploadId: params['UploadId'], - }, - headers: params.Headers, - onProgress: params.onProgress, - body: params.Body || null - }, function (err, data) { - if (err) return callback(err); - callback(null, { - ETag: util.attr(data.headers, 'etag', {}), - statusCode: data.statusCode, - headers: data.headers, - }); - }); - }); - }); - -} - -/** - * 完成分块上传 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {Array} params.Parts 分块信息列表,必须 - * @param {String} params.Parts[i].PartNumber 块编号,必须 - * @param {String} params.Parts[i].ETag 分块的 sha1 校验值 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {Object} data.CompleteMultipartUpload 完成分块上传后的文件信息,包括Location, Bucket, Key 和 ETag - */ -function multipartComplete(params, callback) { - var self = this; - - var UploadId = params.UploadId; - - var Parts = params['Parts']; - - for (var i = 0, len = Parts.length; i < len; i++) { - if (Parts[i]['ETag'].indexOf('"') === 0) { - continue; - } - Parts[i]['ETag'] = '"' + Parts[i]['ETag'] + '"'; - } - - var xml = util.json2xml({CompleteMultipartUpload: {Part: Parts}}); - - var headers = params.Headers; - headers['Content-Type'] = 'application/xml'; - headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); - - submitRequest.call(this, { - Action: 'name/cos:CompleteMultipartUpload', - method: 'POST', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - qs: { - uploadId: UploadId - }, - body: xml, - headers: headers, - }, function (err, data) { - if (err) return callback(err); - var url = getUrl({ - ForcePathStyle: self.options.ForcePathStyle, - protocol: self.options.Protocol, - domain: self.options.Domain, - bucket: params.Bucket, - region: params.Region, - object: params.Key, - isLocation: true, - }); - var CompleteMultipartUploadResult = data.CompleteMultipartUploadResult || {}; - var result = util.extend(CompleteMultipartUploadResult, { - Location: url, - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); -} - -/** - * 分块上传任务列表查询 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Delimiter 定界符为一个符号,如果有Prefix,则将Prefix到delimiter之间的相同路径归为一类,定义为Common Prefix,然后列出所有Common Prefix。如果没有Prefix,则从路径起点开始,非必须 - * @param {String} params.EncodingType 规定返回值的编码方式,非必须 - * @param {String} params.Prefix 前缀匹配,用来规定返回的文件前缀地址,非必须 - * @param {String} params.MaxUploads 单次返回最大的条目数量,默认1000,非必须 - * @param {String} params.KeyMarker 与upload-id-marker一起使用
当upload-id-marker未被指定时,ObjectName字母顺序大于key-marker的条目将被列出
当upload-id-marker被指定时,ObjectName字母顺序大于key-marker的条目被列出,ObjectName字母顺序等于key-marker同时UploadId大于upload-id-marker的条目将被列出,非必须 - * @param {String} params.UploadIdMarker 与key-marker一起使用
当key-marker未被指定时,upload-id-marker将被忽略
当key-marker被指定时,ObjectName字母顺序大于key-marker的条目被列出,ObjectName字母顺序等于key-marker同时UploadId大于upload-id-marker的条目将被列出,非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {Object} data.ListMultipartUploadsResult 分块上传任务信息 - */ -function multipartList(params, callback) { - var reqParams = {}; - - reqParams['delimiter'] = params['Delimiter']; - reqParams['encoding-type'] = params['EncodingType']; - reqParams['prefix'] = params['Prefix'] || ''; - - reqParams['max-uploads'] = params['MaxUploads']; - - reqParams['key-marker'] = params['KeyMarker']; - reqParams['upload-id-marker'] = params['UploadIdMarker']; - - reqParams = util.clearKey(reqParams); - - submitRequest.call(this, { - Action: 'name/cos:ListMultipartUploads', - ResourceKey: reqParams['prefix'], - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - headers: params.Headers, - qs: reqParams, - action: 'uploads', - }, function (err, data) { - if (err) return callback(err); - - if (data && data.ListMultipartUploadsResult) { - var Upload = data.ListMultipartUploadsResult.Upload || []; - - var CommonPrefixes = data.ListMultipartUploadsResult.CommonPrefixes || []; - - CommonPrefixes = util.isArray(CommonPrefixes) ? CommonPrefixes : [CommonPrefixes]; - Upload = util.isArray(Upload) ? Upload : [Upload]; - - data.ListMultipartUploadsResult.Upload = Upload; - data.ListMultipartUploadsResult.CommonPrefixes = CommonPrefixes; - } - var result = util.clone(data.ListMultipartUploadsResult || {}); - util.extend(result, { - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); -} - -/** - * 上传的分块列表查询 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {String} params.UploadId 标示本次分块上传的ID,必须 - * @param {String} params.EncodingType 规定返回值的编码方式,非必须 - * @param {String} params.MaxParts 单次返回最大的条目数量,默认1000,非必须 - * @param {String} params.PartNumberMarker 默认以UTF-8二进制顺序列出条目,所有列出条目从marker开始,非必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - * @return {Object} data.ListMultipartUploadsResult 分块信息 - */ -function multipartListPart(params, callback) { - var reqParams = {}; - - reqParams['uploadId'] = params['UploadId']; - reqParams['encoding-type'] = params['EncodingType']; - reqParams['max-parts'] = params['MaxParts']; - reqParams['part-number-marker'] = params['PartNumberMarker']; - - submitRequest.call(this, { - Action: 'name/cos:ListParts', - method: 'GET', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - qs: reqParams, - }, function (err, data) { - if (err) return callback(err); - var ListPartsResult = data.ListPartsResult || {}; - var Part = ListPartsResult.Part || []; - Part = util.isArray(Part) ? Part : [Part]; - - ListPartsResult.Part = Part; - var result = util.clone(ListPartsResult); - util.extend(result, { - statusCode: data.statusCode, - headers: data.headers, - }); - callback(null, result); - }); -} - -/** - * 抛弃分块上传 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {String} params.UploadId 标示本次分块上传的ID,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ -function multipartAbort(params, callback) { - var reqParams = {}; - - reqParams['uploadId'] = params['UploadId']; - submitRequest.call(this, { - Action: 'name/cos:AbortMultipartUpload', - method: 'DELETE', - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - headers: params.Headers, - qs: reqParams, - }, function (err, data) { - if (err) return callback(err); - callback(null, { - statusCode: data.statusCode, - headers: data.headers, - }); - }); -} - - -/** - * cos 内置请求 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ - function request(params, callback) { - submitRequest.call(this, { - method: params.Method, - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - action: params.Action, - headers: params.Headers, - qs: params.Query, - body: params.Body, - }, function (err, data) { - if (err) return callback(err); - if (data && data.body) { - data.Body = data.body; - delete data.body; - } - callback(err, data); - }); -} - -/** - * 获取签名 - * @param {Object} params 参数对象,必须 - * @param {String} params.Method 请求方法,必须 - * @param {String} params.Key object名称,必须 - * @param {String} params.Expires 名超时时间,单位秒,可选 - * @return {String} data 返回签名字符串 - */ -function getAuth(params) { - var self = this; - return util.getAuth({ - SecretId: params.SecretId || this.options.SecretId || '', - SecretKey: params.SecretKey || this.options.SecretKey || '', - Method: params.Method, - Key: params.Key, - Query: params.Query, - Headers: params.Headers, - Expires: params.Expires, - SystemClockOffset: self.options.SystemClockOffset, - }); -} - -/** - * 获取文件下载链接 - * @param {Object} params 参数对象,必须 - * @param {String} params.Bucket Bucket名称,必须 - * @param {String} params.Region 地域名称,必须 - * @param {String} params.Key object名称,必须 - * @param {String} params.Method 请求的方法,可选 - * @param {String} params.Expires 签名超时时间,单位秒,可选 - * @param {Function} callback 回调函数,必须 - * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 - * @return {Object} data 返回的数据 - */ -function getObjectUrl(params, callback) { - var self = this; - var url = getUrl({ - ForcePathStyle: self.options.ForcePathStyle, - protocol: params.Protocol || self.options.Protocol, - domain: params.Domain || self.options.Domain, - bucket: params.Bucket, - region: params.Region, - object: params.Key, - }); - - var queryParamsStr = ''; - if(params.Query){ - queryParamsStr += util.obj2str(params.Query); - } - if(params.QueryString){ - queryParamsStr += (queryParamsStr ? '&' : '') + params.QueryString; - } - - var syncUrl = url; - if (params.Sign !== undefined && !params.Sign) { - queryParamsStr && (syncUrl += '?' + queryParamsStr); - callback(null, {Url: syncUrl}); - return syncUrl; - } - var AuthData = getAuthorizationAsync.call(this, { - Action: ((params.Method || '').toUpperCase() === 'PUT' ? 'name/cos:PutObject' : 'name/cos:GetObject'), - Bucket: params.Bucket || '', - Region: params.Region || '', - Method: params.Method || 'get', - Key: params.Key, - Expires: params.Expires, - }, function (err, AuthData) { - if (!callback) return; - if (err) { - callback(err); - return; - } - var signUrl = url; - signUrl += '?' + (AuthData.Authorization.indexOf('q-signature') > -1 ? - AuthData.Authorization : 'sign=' + encodeURIComponent(AuthData.Authorization)); - AuthData.XCosSecurityToken && (signUrl += '&x-cos-security-token=' + AuthData.XCosSecurityToken); - AuthData.ClientIP && (signUrl += '&clientIP=' + AuthData.ClientIP); - AuthData.ClientUA && (signUrl += '&clientUA=' + AuthData.ClientUA); - AuthData.Token && (signUrl += '&token=' + AuthData.Token); - queryParamsStr && (signUrl += '&' + queryParamsStr); - setTimeout(function () { - callback(null, {Url: signUrl}); - }); - }); - - if (AuthData) { - signUrl += '?' + AuthData.Authorization + - (AuthData.XCosSecurityToken ? '&x-cos-security-token=' + AuthData.XCosSecurityToken : ''); - queryParamsStr && (syncUrl += '&' + queryParamsStr); - } else { - queryParamsStr && (syncUrl += '?' + queryParamsStr); - } - return syncUrl; -} - - -/** - * 私有方法 - */ -function decodeAcl(AccessControlPolicy) { - var result = { - GrantFullControl: [], - GrantWrite: [], - GrantRead: [], - GrantReadAcp: [], - GrantWriteAcp: [], - ACL: '', - }; - var GrantMap = { - 'FULL_CONTROL': 'GrantFullControl', - 'WRITE': 'GrantWrite', - 'READ': 'GrantRead', - 'READ_ACP': 'GrantReadAcp', - 'WRITE_ACP': 'GrantWriteAcp', - }; - var AccessControlList = AccessControlPolicy && AccessControlPolicy.AccessControlList || {}; - var Grant = AccessControlList.Grant; - if (Grant) { - Grant = util.isArray(Grant) ? Grant : [Grant]; - } - var PublicAcl = {READ: 0, WRITE: 0, FULL_CONTROL: 0}; - Grant && Grant.length && util.each(Grant, function (item) { - if (item.Grantee.ID === 'qcs::cam::anyone:anyone' || item.Grantee.URI === 'http://cam.qcloud.com/groups/global/AllUsers') { - PublicAcl[item.Permission] = 1; - } else if (item.Grantee.ID !== AccessControlPolicy.Owner.ID) { - result[GrantMap[item.Permission]].push('id="' + item.Grantee.ID + '"'); - } - }); - if (PublicAcl.FULL_CONTROL || (PublicAcl.WRITE && PublicAcl.READ)) { - result.ACL = 'public-read-write'; - } else if (PublicAcl.READ) { - result.ACL = 'public-read'; - } else { - result.ACL = 'private'; - } - util.each(GrantMap, function (item) { - result[item] = uniqGrant(result[item].join(',')); - }); - return result; -} - -// Grant 去重 -function uniqGrant(str) { - var arr = str.split(','); - var exist = {}; - var i, item; - for (i = 0; i < arr.length; ) { - item = arr[i].trim(); - if (exist[item]) { - arr.splice(i, 1); - } else { - exist[item] = true; - arr[i] = item; - i++; - } - } - return arr.join(','); -} - -// 生成操作 url -function getUrl(params) { - var longBucket = params.bucket; - var shortBucket = longBucket.substr(0, longBucket.lastIndexOf('-')); - var appId = longBucket.substr(longBucket.lastIndexOf('-') + 1); - var domain = params.domain; - var region = params.region; - var object = params.object; - var protocol = 'https:'; - if (!domain) { - if (['cn-south', 'cn-south-2', 'cn-north', 'cn-east', 'cn-southwest', 'sg'].indexOf(region) > -1) { - domain = '{Region}.myqcloud.com'; - } else { - domain = 'cos.{Region}.myqcloud.com'; - } - if (!params.ForcePathStyle) { - domain = '{Bucket}.' + domain; - } - } - domain = domain.replace(/\{\{AppId\}\}/ig, appId) - .replace(/\{\{Bucket\}\}/ig, shortBucket) - .replace(/\{\{Region\}\}/ig, region) - .replace(/\{\{.*?\}\}/ig, ''); - domain = domain.replace(/\{AppId\}/ig, appId) - .replace(/\{BucketName\}/ig, shortBucket) - .replace(/\{Bucket\}/ig, longBucket) - .replace(/\{Region\}/ig, region) - .replace(/\{.*?\}/ig, ''); - if (!/^[a-zA-Z]+:\/\//.test(domain)) { - domain = protocol + '//' + domain; - } - - // 去掉域名最后的斜杆 - if (domain.slice(-1) === '/') { - domain = domain.slice(0, -1); - } - var url = domain; - - if (params.ForcePathStyle) { - url += '/' + longBucket; - } - url += '/'; - if (object) { - url += util.camSafeUrlEncode(object).replace(/%2F/g, '/'); - } - - if (params.isLocation) { - url = url.replace(/^https?:\/\//, ''); - } - return url; -} - -// 异步获取签名 -function getAuthorizationAsync(params, callback) { - - var headers = util.clone(params.Headers); - delete headers['Content-Type']; - delete headers['Cache-Control']; - util.each(headers, function (v, k) { - v === '' && delete headers[k]; - }); - - var cb = function (AuthData) { - - // 检查签名格式 - var formatAllow = false; - var auth = AuthData.Authorization; - if (auth) { - if (auth.indexOf(' ') > -1) { - formatAllow = false; - } else if (auth.indexOf('q-sign-algorithm=') > -1 && - auth.indexOf('q-ak=') > -1 && - auth.indexOf('q-sign-time=') > -1 && - auth.indexOf('q-key-time=') > -1 && - auth.indexOf('q-url-param-list=') > -1) { - formatAllow = true; - } else { - try { - auth = base64.atob(auth); - if (auth.indexOf('a=') > -1 && - auth.indexOf('k=') > -1 && - auth.indexOf('t=') > -1 && - auth.indexOf('r=') > -1 && - auth.indexOf('b=') > -1) { - formatAllow = true; - } - } catch (e) {} - } - } - if (formatAllow) { - callback && callback(null, AuthData); - } else { - callback && callback('authorization error'); - } - }; - - var self = this; - var Bucket = params.Bucket || ''; - var Region = params.Region || ''; - - // PathName - var KeyName = params.Action === 'name/cos:PostObject' || !params.Key ? '' : params.Key; - if (self.options.ForcePathStyle && Bucket) { - KeyName = Bucket + '/' + KeyName; - } - var Pathname = '/' + KeyName; - - // Action、ResourceKey - var StsData = {}; - var Scope = params.Scope; - if (!Scope) { - var Action = params.Action || ''; - var ResourceKey = params.ResourceKey || params.Key || ''; - Scope = params.Scope || [{ - action: Action, - bucket: Bucket, - region: Region, - prefix: ResourceKey, - }]; - } - var ScopeKey = util.md5(JSON.stringify(Scope)); - - // STS - self._StsCache = self._StsCache ||[]; - (function () { - var i, AuthData; - for (i = self._StsCache.length - 1; i >= 0; i--) { - AuthData = self._StsCache[i]; - var compareTime = Math.round(util.getSkewTime(self.options.SystemClockOffset) / 1000) + 30; - if (AuthData.StartTime && compareTime < AuthData.StartTime || compareTime >= AuthData.ExpiredTime) { - self._StsCache.splice(i, 1); - continue; - } - if (!AuthData.ScopeLimit || AuthData.ScopeLimit && AuthData.ScopeKey === ScopeKey) { - StsData = AuthData; - break; - } - } - })(); - - var calcAuthByTmpKey = function () { - var KeyTime = StsData.StartTime && StsData.ExpiredTime ? StsData.StartTime + ';' + StsData.ExpiredTime : ''; - var Authorization = util.getAuth({ - SecretId: StsData.TmpSecretId, - SecretKey: StsData.TmpSecretKey, - Method: params.Method, - Pathname: Pathname, - Query: params.Query, - Headers: headers, - Expires: params.Expires, - SystemClockOffset: self.options.SystemClockOffset, - KeyTime: KeyTime - }); - var AuthData = { - Authorization: Authorization, - XCosSecurityToken: StsData.XCosSecurityToken || '', - Token: StsData.Token || '', - ClientIP: StsData.ClientIP || '', - ClientUA: StsData.ClientUA || '', - }; - cb(AuthData); - }; - - // 先判断是否有临时密钥 - if (StsData.ExpiredTime && StsData.ExpiredTime - (util.getSkewTime(self.options.SystemClockOffset) / 1000) > 60) { // 如果缓存的临时密钥有效,并还有超过60秒有效期就直接使用 - calcAuthByTmpKey(); - } else if (self.options.getAuthorization) { // 外部计算签名或获取临时密钥 - self.options.getAuthorization.call(self, { - Bucket: Bucket, - Region: Region, - Method: params.Method, - Key: KeyName, - Pathname: Pathname, - Query: params.Query, - Headers: headers, - Scope: Scope, - SystemClockOffset: self.options.SystemClockOffset, - }, function (AuthData) { - if (typeof AuthData === 'string') { - AuthData = {Authorization: AuthData}; - } - if (AuthData.TmpSecretId && - AuthData.TmpSecretKey && - AuthData.XCosSecurityToken && - AuthData.ExpiredTime) { - StsData = AuthData || {}; - StsData.Scope = Scope; - StsData.ScopeKey = ScopeKey; - self._StsCache.push(StsData); - calcAuthByTmpKey(); - } else { - cb(AuthData); - } - }); - } else if (self.options.getSTS) { // 外部获取临时密钥 - self.options.getSTS.call(self, { - Bucket: Bucket, - Region: Region, - }, function (data) { - StsData = data || {}; - StsData.Scope = Scope; - StsData.ScopeKey = ScopeKey; - StsData.TmpSecretId = StsData.SecretId; - StsData.TmpSecretKey = StsData.SecretKey; - self._StsCache.push(StsData); - calcAuthByTmpKey(); - }); - } else { // 内部计算获取签名 - return (function () { - var Authorization = util.getAuth({ - SecretId: params.SecretId || self.options.SecretId, - SecretKey: params.SecretKey || self.options.SecretKey, - Method: params.Method, - Pathname: Pathname, - Query: params.Query, - Headers: headers, - Expires: params.Expires, - SystemClockOffset: self.options.SystemClockOffset, - }); - var AuthData = { - Authorization: Authorization, - XCosSecurityToken: self.options.XCosSecurityToken, - }; - cb(AuthData); - return AuthData; - })(); - } - return ''; -} - -// 调整时间偏差 -function allowRetry(err) { - var allowRetry = false; - var isTimeError = false; - var serverDate = (err.headers && (err.headers.date || err.headers.Date)) || (err.error && err.error.ServerTime); - try { - var errorCode = err.error.Code; - var errorMessage = err.error.Message; - if (errorCode === 'RequestTimeTooSkewed' || - (errorCode === 'AccessDenied' && errorMessage === 'Request has expired')) { - isTimeError = true; - } - } catch (e) { - } - if (err) { - if (isTimeError && serverDate) { - var serverTime = Date.parse(serverDate); - if (this.options.CorrectClockSkew && Math.abs(util.getSkewTime(this.options.SystemClockOffset) - serverTime) >= 30000) { - console.error('error: Local time is too skewed.'); - this.options.SystemClockOffset = serverTime - Date.now(); - allowRetry = true; - } - } else if (Math.floor(err.statusCode / 100) === 5) { - allowRetry = true; - } - } - return allowRetry; -} - -// 获取签名并发起请求 -function submitRequest(params, callback) { - var self = this; - - // 处理 headers - !params.headers && (params.headers = {}); - - // 处理 query - !params.qs && (params.qs = {}); - params.VersionId && (params.qs.versionId = params.VersionId); - params.qs = util.clearKey(params.qs); - - // 清理 undefined 和 null 字段 - params.headers && (params.headers = util.clearKey(params.headers)); - params.qs && (params.qs = util.clearKey(params.qs)); - - var Query = util.clone(params.qs); - params.action && (Query[params.action] = ''); - - var next = function (tryTimes) { - var oldClockOffset = self.options.SystemClockOffset; - getAuthorizationAsync.call(self, { - Bucket: params.Bucket || '', - Region: params.Region || '', - Method: params.method, - Key: params.Key, - Query: Query, - Headers: params.headers, - Action: params.Action, - ResourceKey: params.ResourceKey, - Scope: params.Scope, - }, function (err, AuthData) { - if (err) { - callback(err); - return; - } - params.AuthData = AuthData; - _submitRequest.call(self, params, function (err, data) { - if (err && tryTimes < 2 && (oldClockOffset !== self.options.SystemClockOffset || allowRetry.call(self, err))) { - if (params.headers) { - delete params.headers.Authorization; - delete params.headers['token']; - delete params.headers['clientIP']; - delete params.headers['clientUA']; - delete params.headers['x-cos-security-token']; - } - next(tryTimes + 1); - } else { - callback(err, data); - } - }); - }); - }; - next(1); - -} - -// 发起请求 -function _submitRequest(params, callback) { - var self = this; - var TaskId = params.TaskId; - if (TaskId && !self._isRunningTask(TaskId)) return; - - var bucket = params.Bucket; - var region = params.Region; - var object = params.Key; - var method = params.method || 'GET'; - var url = params.url; - var body = params.body; - var json = params.json; - var rawBody = params.rawBody; - - // url - if (self.options.UseAccelerate) { - region = 'accelerate'; - } - url = url || getUrl({ - ForcePathStyle: self.options.ForcePathStyle, - protocol: self.options.Protocol, - domain: self.options.Domain, - bucket: bucket, - region: region, - object: object, - }); - if (params.action) { - url = url + '?' + params.action; - } - if (params.qsStr) { - if(url.indexOf('?') > -1){ - url = url + '&' + params.qsStr; - }else{ - url = url + '?' + params.qsStr; - } - } - - var opt = { - method: method, - url: url, - headers: params.headers, - qs: params.qs, - filePath: params.filePath, - body: body, - json: json, - }; - - // 获取签名 - opt.headers.Authorization = params.AuthData.Authorization; - params.AuthData.Token && (opt.headers['token'] = params.AuthData.Token); - params.AuthData.ClientIP && (opt.headers['clientIP'] = params.AuthData.ClientIP); - params.AuthData.ClientUA && (opt.headers['clientUA'] = params.AuthData.ClientUA); - params.AuthData.XCosSecurityToken && (opt.headers['x-cos-security-token'] = params.AuthData.XCosSecurityToken); - - // 清理 undefined 和 null 字段 - opt.headers && (opt.headers = util.clearKey(opt.headers)); - opt = util.clearKey(opt); - - // progress - if (params.onProgress && typeof params.onProgress === 'function') { - opt.onProgress = function (e) { - if (TaskId && !self._isRunningTask(TaskId)) return; - var loaded = e ? e.loaded : 0; - params.onProgress({loaded: loaded, total: e.total}); - }; - } - if (this.options.Timeout) { - opt.timeout = this.options.Timeout; - } - - self.options.ForcePathStyle && (opt.pathStyle = self.options.ForcePathStyle); - self.emit('before-send', opt); - var sender = REQUEST(opt, function (err, response, body) { - if (err === 'abort') return; - - // 返回内容添加 状态码 和 headers - var hasReturned; - var cb = function (err, data) { - TaskId && self.off('inner-kill-task', killTask); - if (hasReturned) return; - hasReturned = true; - var attrs = {}; - response && response.statusCode && (attrs.statusCode = response.statusCode); - response && response.headers && (attrs.headers = response.headers); - - if (err) { - err = util.extend(err || {}, attrs); - callback(err, null); - } else { - data = util.extend(data || {}, attrs); - callback(null, data); - } - sender = null; - }; - - // 请求错误,发生网络错误 - if (err) { - cb({error: err}); - return; - } - - // 不对 body 进行转换,body 直接挂载返回 - var jsonRes; - if (rawBody) { - jsonRes = {}; - jsonRes.body = body; - } else { - try { - jsonRes = body && body.indexOf('<') > -1 && body.indexOf('>') > -1 && util.xml2json(body) || {}; - } catch (e) { - jsonRes = body || {}; - } - } - - // 请求返回码不为 200 - var statusCode = response.statusCode; - var statusSuccess = Math.floor(statusCode / 100) === 2; // 200 202 204 206 - if (!statusSuccess) { - cb({error: jsonRes.Error || jsonRes}); - return; - } - - if (jsonRes.Error) { - cb({error: jsonRes.Error}); - return; - } - cb(null, jsonRes); - }); - - // kill task - var killTask = function (data) { - if (data.TaskId === TaskId) { - sender && sender.abort && sender.abort(); - self.off('inner-kill-task', killTask); - } - }; - TaskId && self.on('inner-kill-task', killTask); - -} - - -var API_MAP = { - // Bucket 相关方法 - getService: getService, // Bucket - putBucket: putBucket, - headBucket: headBucket, // Bucket - getBucket: getBucket, - deleteBucket: deleteBucket, - putBucketAcl: putBucketAcl, // BucketACL - getBucketAcl: getBucketAcl, - putBucketCors: putBucketCors, // BucketCors - getBucketCors: getBucketCors, - deleteBucketCors: deleteBucketCors, - getBucketLocation: getBucketLocation, // BucketLocation - getBucketPolicy: getBucketPolicy, // BucketPolicy - putBucketPolicy: putBucketPolicy, - deleteBucketPolicy: deleteBucketPolicy, - putBucketTagging: putBucketTagging, // BucketTagging - getBucketTagging: getBucketTagging, - deleteBucketTagging: deleteBucketTagging, - putBucketLifecycle: putBucketLifecycle, // BucketLifecycle - getBucketLifecycle: getBucketLifecycle, - deleteBucketLifecycle: deleteBucketLifecycle, - putBucketVersioning: putBucketVersioning, // BucketVersioning - getBucketVersioning: getBucketVersioning, - putBucketReplication: putBucketReplication, // BucketReplication - getBucketReplication: getBucketReplication, - deleteBucketReplication: deleteBucketReplication, - putBucketWebsite: putBucketWebsite, // BucketWebsite - getBucketWebsite: getBucketWebsite, - deleteBucketWebsite: deleteBucketWebsite, - putBucketReferer: putBucketReferer, // BucketReferer - getBucketReferer: getBucketReferer, - putBucketDomain: putBucketDomain, // BucketDomain - getBucketDomain: getBucketDomain, - deleteBucketDomain: deleteBucketDomain, - putBucketOrigin: putBucketOrigin, // BucketOrigin - getBucketOrigin: getBucketOrigin, - deleteBucketOrigin: deleteBucketOrigin, - putBucketLogging: putBucketLogging, // BucketLogging - getBucketLogging: getBucketLogging, - putBucketInventory: putBucketInventory, // BucketInventory - getBucketInventory: getBucketInventory, - listBucketInventory: listBucketInventory, - deleteBucketInventory: deleteBucketInventory, - putBucketAccelerate: putBucketAccelerate, - getBucketAccelerate: getBucketAccelerate, - - // Object 相关方法 - getObject: getObject, - headObject: headObject, - listObjectVersions: listObjectVersions, - putObject: putObject, - postObject: postObject, - deleteObject: deleteObject, - getObjectAcl: getObjectAcl, - putObjectAcl: putObjectAcl, - optionsObject: optionsObject, - putObjectCopy: putObjectCopy, - deleteMultipleObject: deleteMultipleObject, - restoreObject: restoreObject, - putObjectTagging: putObjectTagging, - getObjectTagging: getObjectTagging, - deleteObjectTagging: deleteObjectTagging, - - // 分块上传相关方法 - uploadPartCopy: uploadPartCopy, - multipartInit: multipartInit, - multipartUpload: multipartUpload, - multipartComplete: multipartComplete, - multipartList: multipartList, - multipartListPart: multipartListPart, - multipartAbort: multipartAbort, - - // 工具方法 - request: request, - getObjectUrl: getObjectUrl, - getAuth: getAuth, -}; - -module.exports.init = function (COS, task) { - task.transferToTaskMethod(API_MAP, 'postObject'); - task.transferToTaskMethod(API_MAP, 'putObject'); - util.each(API_MAP, function (fn, apiName) { - COS.prototype[apiName] = util.apiWrapper(apiName, fn); - }); -}; +var session = __webpack_require__(5); +var util = __webpack_require__(0); + +var originApiMap = {}; +var transferToTaskMethod = function (apiMap, apiName) { + originApiMap[apiName] = apiMap[apiName]; + apiMap[apiName] = function (params, callback) { + if (params.SkipTask) { + originApiMap[apiName].call(this, params, callback); + } else { + this._addTask(apiName, params, callback); + } + }; +}; + +var initTask = function (cos) { + + var queue = []; + var tasks = {}; + var uploadingFileCount = 0; + var nextUploadIndex = 0; + + // 接口返回简略的任务信息 + var formatTask = function (task) { + var t = { + id: task.id, + Bucket: task.Bucket, + Region: task.Region, + Key: task.Key, + FilePath: task.FilePath, + state: task.state, + loaded: task.loaded, + size: task.size, + speed: task.speed, + percent: task.percent, + hashPercent: task.hashPercent, + error: task.error, + }; + if (task.FilePath) t.FilePath = task.FilePath; + return t; + }; + + var emitListUpdate = (function () { + var timer; + var emit = function () { + timer = 0; + cos.emit('task-list-update', {list: util.map(queue, formatTask)}); + cos.emit('list-update', {list: util.map(queue, formatTask)}); + }; + return function () { + if (!timer) timer = setTimeout(emit); + } + })(); + + var clearQueue = function () { + if (queue.length <= cos.options.UploadQueueSize) return; + for (var i = 0; + i < nextUploadIndex && // 小于当前操作的 index 才清理 + i < queue.length && // 大于队列才清理 + queue.length > cos.options.UploadQueueSize // 如果还太多,才继续清理 + ;) { + var isActive = queue[i].state === 'waiting' || queue[i].state === 'checking' || queue[i].state === 'uploading'; + if (!queue[i] || !isActive) { + tasks[queue[i].id] && (delete tasks[queue[i].id]); + queue.splice(i, 1); + nextUploadIndex--; + } else { + i++; + } + } + emitListUpdate(); + }; + + var startNextTask = function () { + // 检查是否允许增加执行进程 + if (uploadingFileCount >= cos.options.FileParallelLimit) return; + // 跳过不可执行的任务 + while (queue[nextUploadIndex] && queue[nextUploadIndex].state !== 'waiting') nextUploadIndex++; + // 检查是否已遍历结束 + if (nextUploadIndex >= queue.length) return; + // 上传该遍历到的任务 + var task = queue[nextUploadIndex]; + nextUploadIndex++; + uploadingFileCount++; + task.state = 'checking'; + task.params.onTaskStart && task.params.onTaskStart(formatTask(task)); + !task.params.UploadData && (task.params.UploadData = {}); + var apiParams = util.formatParams(task.api, task.params); + originApiMap[task.api].call(cos, apiParams, function (err, data) { + if (!cos._isRunningTask(task.id)) return; + if (task.state === 'checking' || task.state === 'uploading') { + task.state = err ? 'error' : 'success'; + err && (task.error = err); + uploadingFileCount--; + emitListUpdate(); + startNextTask(); + task.callback && task.callback(err, data); + if (task.state === 'success') { + if (task.params) { + delete task.params.UploadData; + delete task.params.Body; + delete task.params; + } + delete task.callback; + } + } + clearQueue(); + }); + emitListUpdate(); + // 异步执行下一个任务 + setTimeout(startNextTask); + }; + + var killTask = function (id, switchToState) { + var task = tasks[id]; + if (!task) return; + var waiting = task && task.state === 'waiting'; + var running = task && (task.state === 'checking' || task.state === 'uploading'); + if (switchToState === 'canceled' && task.state !== 'canceled' || + switchToState === 'paused' && waiting || + switchToState === 'paused' && running) { + if (switchToState === 'paused' && task.params.Body && typeof task.params.Body.pipe === 'function') { + console.error('stream not support pause'); + return; + } + task.state = switchToState; + cos.emit('inner-kill-task', {TaskId: id, toState: switchToState}); + try { + var UploadId = task && task.params && task.params.UploadData.UploadId + } catch(e) {} + if (switchToState === 'canceled' && UploadId) session.removeUsing(UploadId) + emitListUpdate(); + if (running) { + uploadingFileCount--; + startNextTask(); + } + if (switchToState === 'canceled') { + if (task.params) { + delete task.params.UploadData; + delete task.params.Body; + delete task.params; + } + delete task.callback; + } + } + clearQueue(); + }; + + cos._addTasks = function (taskList) { + util.each(taskList, function (task) { + cos._addTask(task.api, task.params, task.callback, true); + }); + emitListUpdate(); + }; + + cos._addTask = function (api, params, callback, ignoreAddEvent) { + + // 如果小程序版本不支持获取文件分片内容,统一转到 postObject 接口上传 + if (api === 'sliceUploadFile' && !util.canFileSlice()) api = 'postObject'; + + // 复制参数对象 + params = util.formatParams(api, params); + + // 生成 id + var id = util.uuid(); + params.TaskId = id; + params.onTaskReady && params.onTaskReady(id); + + var task = { + // env + params: params, + callback: callback, + api: api, + index: queue.length, + // task + id: id, + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + FilePath: params.FilePath || '', + state: 'waiting', + loaded: 0, + size: 0, + speed: 0, + percent: 0, + hashPercent: 0, + error: null, + }; + var onHashProgress = params.onHashProgress; + params.onHashProgress = function (info) { + if (!cos._isRunningTask(task.id)) return; + task.hashPercent = info.percent; + onHashProgress && onHashProgress(info); + emitListUpdate(); + }; + var onProgress = params.onProgress; + params.onProgress = function (info) { + if (!cos._isRunningTask(task.id)) return; + task.state === 'checking' && (task.state = 'uploading'); + task.loaded = info.loaded; + task.size = info.total; + task.speed = info.speed; + task.percent = info.percent; + onProgress && onProgress(info); + emitListUpdate(); + }; + + // 异步获取 filesize + util.getFileSize(api, params, function (err, size) { + // 开始处理上传 + if (err) { // 如果获取大小出错,不加入队列 + callback(err); + return; + } + // 获取完文件大小再把任务加入队列 + tasks[id] = task; + queue.push(task); + task.size = size; + !ignoreAddEvent && emitListUpdate(); + startNextTask(); + clearQueue(); + }); + return id; + }; + cos._isRunningTask = function (id) { + var task = tasks[id]; + return !!(task && (task.state === 'checking' || task.state === 'uploading')); + }; + cos.getTaskList = function () { + return util.map(queue, formatTask); + }; + cos.cancelTask = function (id) { + killTask(id, 'canceled'); + }; + cos.pauseTask = function (id) { + killTask(id, 'paused'); + }; + cos.restartTask = function (id) { + var task = tasks[id]; + if (task && (task.state === 'paused' || task.state === 'error')) { + task.state = 'waiting'; + emitListUpdate(); + nextUploadIndex = Math.min(nextUploadIndex, task.index); + startNextTask(); + } + }; + cos.isUploadRunning = function () { + return uploadingFileCount || nextUploadIndex < queue.length; + }; + +}; + +module.exports.transferToTaskMethod = transferToTaskMethod; +module.exports.init = initTask; + + +/***/ }), +/* 17 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + +var REQUEST = __webpack_require__(18); +var base64 = __webpack_require__(3); +var util = __webpack_require__(0); +var mime = __webpack_require__(19); + + +// Bucket 相关 + +/** + * 获取用户的 bucket 列表 + * @param {Object} params 回调函数,必须,下面为参数列表 + * 无特殊参数 + * @param {Function} callback 回调函数,必须 + */ +function getService(params, callback) { + + if (typeof params === 'function') { + callback = params; + params = {}; + } + var protocol = 'https:'; + var domain = this.options.ServiceDomain; + var region = params.Region; + if (domain) { + domain = domain.replace(/\{\{Region\}\}/ig, region || '').replace(/\{\{.*?\}\}/ig, ''); + if (!/^[a-zA-Z]+:\/\//.test(domain)) { + domain = protocol + '//' + domain; + } + if (domain.slice(-1) === '/') { + domain = domain.slice(0, -1); + } + } else if (region) { + domain = protocol + '//cos.' + region + '.myqcloud.com'; + } else { + domain = protocol + '//service.cos.myqcloud.com'; + } + + submitRequest.call(this, { + Action: 'name/cos:GetService', + url: domain, + method: 'GET', + headers: params.Headers, + }, function (err, data) { + if (err) return callback(err); + var buckets = (data && data.ListAllMyBucketsResult && data.ListAllMyBucketsResult.Buckets + && data.ListAllMyBucketsResult.Buckets.Bucket) || []; + buckets = util.isArray(buckets) ? buckets : [buckets]; + var owner = (data && data.ListAllMyBucketsResult && data.ListAllMyBucketsResult.Owner) || {}; + callback(null, { + Buckets: buckets, + Owner: owner, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 创建 Bucket,并初始化访问权限 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.ACL 用户自定义文件权限,可以设置:private,public-read;默认值:private,非必须 + * @param {String} params.GrantRead 赋予被授权者读的权限,格式x-cos-grant-read: uin=" ",uin=" ",非必须 + * @param {String} params.GrantWrite 赋予被授权者写的权限,格式x-cos-grant-write: uin=" ",uin=" ",非必须 + * @param {String} params.GrantFullControl 赋予被授权者读写权限,格式x-cos-grant-full-control: uin=" ",uin=" ",非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {String} data.Location 操作地址 + */ +function putBucket(params, callback) { + + var self = this; + + var xml = ''; + if(params['BucketAZConfig']){ + var CreateBucketConfiguration = { + BucketAZConfig: params.BucketAZConfig + }; + xml = util.json2xml({CreateBucketConfiguration: CreateBucketConfiguration}); + } + + submitRequest.call(this, { + Action: 'name/cos:PutBucket', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + body: xml, + }, function (err, data) { + if (err) return callback(err); + var url = getUrl({ + protocol: self.options.Protocol, + domain: self.options.Domain, + bucket: params.Bucket, + region: params.Region, + isLocation: true, + }); + callback(null, { + Location: url, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 查看是否存在该Bucket,是否有权限访问 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {Boolean} data.BucketExist Bucket是否存在 + * @return {Boolean} data.BucketAuth 是否有 Bucket 的访问权限 + */ +function headBucket(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:HeadBucket', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + method: 'HEAD', + }, function (err, data) { + callback(err, data); + }); +} + +/** + * 获取 Bucket 下的 object 列表 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Prefix 前缀匹配,用来规定返回的文件前缀地址,非必须 + * @param {String} params.Delimiter 定界符为一个符号,如果有Prefix,则将Prefix到delimiter之间的相同路径归为一类,非必须 + * @param {String} params.Marker 默认以UTF-8二进制顺序列出条目,所有列出条目从marker开始,非必须 + * @param {String} params.MaxKeys 单次返回最大的条目数量,默认1000,非必须 + * @param {String} params.EncodingType 规定返回值的编码方式,非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {Object} data.ListBucketResult 返回的 object 列表信息 + */ +function getBucket(params, callback) { + var reqParams = {}; + reqParams['prefix'] = params['Prefix'] || ''; + reqParams['delimiter'] = params['Delimiter']; + reqParams['marker'] = params['Marker']; + reqParams['max-keys'] = params['MaxKeys']; + reqParams['encoding-type'] = params['EncodingType']; + + submitRequest.call(this, { + Action: 'name/cos:GetBucket', + ResourceKey: reqParams['prefix'], + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + qs: reqParams, + }, function (err, data) { + if (err) return callback(err); + var ListBucketResult = data.ListBucketResult || {}; + var Contents = ListBucketResult.Contents || []; + var CommonPrefixes = ListBucketResult.CommonPrefixes || []; + + Contents = util.isArray(Contents) ? Contents : [Contents]; + CommonPrefixes = util.isArray(CommonPrefixes) ? CommonPrefixes : [CommonPrefixes]; + + var result = util.clone(ListBucketResult); + util.extend(result, { + Contents: Contents, + CommonPrefixes: CommonPrefixes, + statusCode: data.statusCode, + headers: data.headers, + }); + + callback(null, result); + }); +} + +/** + * 删除 Bucket + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {String} data.Location 操作地址 + */ +function deleteBucket(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:DeleteBucket', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + method: 'DELETE', + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 设置 Bucket 的 权限列表 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.ACL 用户自定义文件权限,可以设置:private,public-read;默认值:private,非必须 + * @param {String} params.GrantRead 赋予被授权者读的权限,格式x-cos-grant-read: uin=" ",uin=" ",非必须 + * @param {String} params.GrantWrite 赋予被授权者写的权限,格式x-cos-grant-write: uin=" ",uin=" ",非必须 + * @param {String} params.GrantFullControl 赋予被授权者读写权限,格式x-cos-grant-full-control: uin=" ",uin=" ",非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ +function putBucketAcl(params, callback) { + var headers = params.Headers; + + var xml = ''; + if (params['AccessControlPolicy']) { + var AccessControlPolicy = util.clone(params['AccessControlPolicy'] || {}); + var Grants = AccessControlPolicy.Grants || AccessControlPolicy.Grant; + Grants = util.isArray(Grants) ? Grants : [Grants]; + delete AccessControlPolicy.Grant; + delete AccessControlPolicy.Grants; + AccessControlPolicy.AccessControlList = {Grant: Grants}; + xml = util.json2xml({AccessControlPolicy: AccessControlPolicy}); + + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + } + + // Grant Header 去重 + util.each(headers, function (val, key) { + if (key.indexOf('x-cos-grant-') === 0) { + headers[key] = uniqGrant(headers[key]); + } + }); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketACL', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + headers: headers, + action: 'acl', + body: xml, + }, function (err, data) { + if (err) return callback(err); + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的 权限列表 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {Object} data.AccessControlPolicy 访问权限信息 + */ +function getBucketAcl(params, callback) { + + submitRequest.call(this, { + Action: 'name/cos:GetBucketACL', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'acl', + }, function (err, data) { + if (err) return callback(err); + var AccessControlPolicy = data.AccessControlPolicy || {}; + var Owner = AccessControlPolicy.Owner || {}; + var Grant = AccessControlPolicy.AccessControlList.Grant || []; + Grant = util.isArray(Grant) ? Grant : [Grant]; + var result = decodeAcl(AccessControlPolicy); + if (data.headers && data.headers['x-cos-acl']) { + result.ACL = data.headers['x-cos-acl']; + } + result = util.extend(result, { + Owner: Owner, + Grants: Grant, + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }); +} + +/** + * 设置 Bucket 的 跨域设置 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Object} params.CORSConfiguration 相关的跨域设置,必须 + * @param {Array} params.CORSConfiguration.CORSRules 对应的跨域规则 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ +function putBucketCors(params, callback) { + + var CORSConfiguration = params['CORSConfiguration'] || {}; + var CORSRules = CORSConfiguration['CORSRules'] || params['CORSRules'] || []; + CORSRules = util.clone(util.isArray(CORSRules) ? CORSRules : [CORSRules]); + util.each(CORSRules, function (rule) { + util.each(['AllowedOrigin', 'AllowedHeader', 'AllowedMethod', 'ExposeHeader'], function (key) { + var sKey = key + 's'; + var val = rule[sKey] || rule[key] || []; + delete rule[sKey]; + rule[key] = util.isArray(val) ? val : [val]; + }); + }); + + var xml = util.json2xml({CORSConfiguration: {CORSRule: CORSRules}}); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketCORS', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'cors', + headers: headers, + }, function (err, data) { + if (err) return callback(err); + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的 跨域设置 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {Object} data.CORSRules Bucket的跨域设置 + */ +function getBucketCors(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:GetBucketCORS', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'cors', + }, function (err, data) { + if (err) { + if (err.statusCode === 404 && err.error && err.error.Code === 'NoSuchCORSConfiguration') { + var result = { + CORSRules: [], + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); + } + return; + } + var CORSConfiguration = data.CORSConfiguration || {}; + var CORSRules = CORSConfiguration.CORSRules || CORSConfiguration.CORSRule || []; + CORSRules = util.clone(util.isArray(CORSRules) ? CORSRules : [CORSRules]); + + util.each(CORSRules, function (rule) { + util.each(['AllowedOrigin', 'AllowedHeader', 'AllowedMethod', 'ExposeHeader'], function (key) { + var sKey = key + 's'; + var val = rule[sKey] || rule[key] || []; + delete rule[key]; + rule[sKey] = util.isArray(val) ? val : [val]; + }); + }); + + callback(null, { + CORSRules: CORSRules, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 删除 Bucket 的 跨域设置 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ +function deleteBucketCors(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:DeleteBucketCORS', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'cors', + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode || err.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的 地域信息 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据,包含地域信息 LocationConstraint + */ +function getBucketLocation(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:GetBucketLocation', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'location', + }, function (err, data) { + if (err) return callback(err); + callback(null, data); + }); +} + +function putBucketPolicy(params, callback) { + var Policy = params['Policy']; + var PolicyStr = Policy; + try { + if (typeof Policy === 'string') { + Policy = JSON.parse(PolicyStr); + } else { + PolicyStr = JSON.stringify(Policy); + } + } catch (e) { + callback({error: 'Policy format error'}); + } + + var headers = params.Headers; + headers['Content-Type'] = 'application/json'; + headers['Content-MD5'] = util.binaryBase64(util.md5(PolicyStr)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketPolicy', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + action: 'policy', + body: PolicyStr, + headers: headers, + json: true, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的读取权限策略 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function getBucketPolicy(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:GetBucketPolicy', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'policy', + rawBody: true, + }, function (err, data) { + if (err) { + if (err.statusCode && err.statusCode === 403) { + return callback({ErrorStatus: 'Access Denied'}); + } + if (err.statusCode && err.statusCode === 405) { + return callback({ErrorStatus: 'Method Not Allowed'}); + } + if (err.statusCode && err.statusCode === 404) { + return callback({ErrorStatus: 'Policy Not Found'}); + } + return callback(err); + } + var Policy = {}; + try { + Policy = JSON.parse(data.body); + } catch (e) { + } + callback(null, { + Policy: Policy, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 删除 Bucket 的 跨域设置 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ +function deleteBucketPolicy(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:DeleteBucketPolicy', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'policy', + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode || err.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 设置 Bucket 的标签 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Array} params.TagSet 标签设置,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function putBucketTagging(params, callback) { + + var Tagging = params['Tagging'] || {}; + var Tags = Tagging.TagSet || Tagging.Tags || params['Tags'] || []; + Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); + var xml = util.json2xml({Tagging: {TagSet: {Tag: Tags}}}); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketTagging', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'tagging', + headers: headers, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的标签设置 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function getBucketTagging(params, callback) { + + submitRequest.call(this, { + Action: 'name/cos:GetBucketTagging', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'tagging', + }, function (err, data) { + if (err) { + if (err.statusCode === 404 && err.error && (err.error === "Not Found" || err.error.Code === 'NoSuchTagSet')) { + var result = { + Tags: [], + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); + } + return; + } + var Tags = []; + try { + Tags = data.Tagging.TagSet.Tag || []; + } catch (e) { + } + Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); + callback(null, { + Tags: Tags, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 删除 Bucket 的 标签设置 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ +function deleteBucketTagging(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:DeleteBucketTagging', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'tagging', + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +function putBucketLifecycle(params, callback) { + + var LifecycleConfiguration = params['LifecycleConfiguration'] || {}; + var Rules = LifecycleConfiguration.Rules || params.Rules || []; + Rules = util.clone(Rules); + var xml = util.json2xml({LifecycleConfiguration: {Rule: Rules}}); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketLifecycle', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'lifecycle', + headers: headers, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +function getBucketLifecycle(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:GetBucketLifecycle', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'lifecycle', + }, function (err, data) { + if (err) { + if (err.statusCode === 404 && err.error && err.error.Code === 'NoSuchLifecycleConfiguration') { + var result = { + Rules: [], + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); + } + return; + } + var Rules = []; + try { + Rules = data.LifecycleConfiguration.Rule || []; + } catch (e) { + } + Rules = util.clone(util.isArray(Rules) ? Rules : [Rules]); + callback(null, { + Rules: Rules, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +function deleteBucketLifecycle(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:DeleteBucketLifecycle', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'lifecycle', + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +function putBucketVersioning(params, callback) { + + if (!params['VersioningConfiguration']) { + callback({error: 'missing param VersioningConfiguration'}); + return; + } + var VersioningConfiguration = params['VersioningConfiguration'] || {}; + var xml = util.json2xml({VersioningConfiguration: VersioningConfiguration}); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketVersioning', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'versioning', + headers: headers, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +function getBucketVersioning(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:GetBucketVersioning', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'versioning', + }, function (err, data) { + if (!err) { + !data.VersioningConfiguration && (data.VersioningConfiguration = {}); + } + callback(err, data); + }); +} + +function putBucketReplication(params, callback) { + var ReplicationConfiguration = util.clone(params.ReplicationConfiguration); + var xml = util.json2xml({ReplicationConfiguration: ReplicationConfiguration}); + xml = xml.replace(/<(\/?)Rules>/ig, '<$1Rule>'); + xml = xml.replace(/<(\/?)Tags>/ig, '<$1Tag>'); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketReplication', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'replication', + headers: headers, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +function getBucketReplication(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:GetBucketReplication', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'replication', + }, function (err, data) { + if (err) { + if (err.statusCode === 404 && err.error && (err.error === 'Not Found' || err.error.Code === 'ReplicationConfigurationnotFoundError')) { + var result = { + ReplicationConfiguration: {Rules: []}, + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); + } + return; + } + if (!err) { + !data.ReplicationConfiguration && (data.ReplicationConfiguration = {}); + } + if (data.ReplicationConfiguration.Rule) { + data.ReplicationConfiguration.Rules = data.ReplicationConfiguration.Rule; + delete data.ReplicationConfiguration.Rule; + } + callback(err, data); + }); +} + +function deleteBucketReplication(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:DeleteBucketReplication', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'replication', + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 设置 Bucket 静态网站配置信息 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Object} params.WebsiteConfiguration 地域名称,必须 + * @param {Object} WebsiteConfiguration.IndexDocument 索引文档,必须 + * @param {Object} WebsiteConfiguration.ErrorDocument 错误文档,非必须 + * @param {Object} WebsiteConfiguration.RedirectAllRequestsTo 重定向所有请求,非必须 + * @param {Array} params.RoutingRules 重定向规则,非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function putBucketWebsite(params, callback) { + + if (!params['WebsiteConfiguration']) { + callback({ error: 'missing param WebsiteConfiguration' }); + return; + } + + var WebsiteConfiguration = util.clone(params['WebsiteConfiguration'] || {}); + var RoutingRules = WebsiteConfiguration['RoutingRules'] || WebsiteConfiguration['RoutingRule'] || []; + RoutingRules = util.isArray(RoutingRules) ? RoutingRules : [RoutingRules]; + delete WebsiteConfiguration.RoutingRule; + delete WebsiteConfiguration.RoutingRules; + if (RoutingRules.length) WebsiteConfiguration.RoutingRules = { RoutingRule: RoutingRules }; + var xml = util.json2xml({ WebsiteConfiguration: WebsiteConfiguration }); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketWebsite', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'website', + headers: headers, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的静态网站配置信息 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function getBucketWebsite(params, callback) { + + submitRequest.call(this, { + Action: 'name/cos:GetBucketWebsite', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + action: 'website', + }, function (err, data) { + if (err) { + if(err.statusCode === 404 && err.error.Code === 'NoSuchWebsiteConfiguration'){ + var result = { + WebsiteConfiguration: {}, + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); + } + return; + } + + var WebsiteConfiguration = data.WebsiteConfiguration || {}; + if (WebsiteConfiguration['RoutingRules']) { + var RoutingRules = util.clone(WebsiteConfiguration['RoutingRules'].RoutingRule || []); + RoutingRules = util.makeArray(RoutingRules); + WebsiteConfiguration.RoutingRules = RoutingRules; + } + + callback(null, { + WebsiteConfiguration: WebsiteConfiguration, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 删除 Bucket 的静态网站配置 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function deleteBucketWebsite(params, callback) { + + submitRequest.call(this, { + Action: 'name/cos:DeleteBucketWebsite', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'website', + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 设置 Bucket 的防盗链白名单或者黑名单 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Object} params.RefererConfiguration 地域名称,必须 + * @param {String} RefererConfiguration.Status 是否开启防盗链,枚举值:Enabled、Disabled + * @param {String} RefererConfiguration.RefererType 防盗链类型,枚举值:Black-List、White-List,必须 + * @param {Array} RefererConfiguration.DomianList.Domain 生效域名,必须 + * @param {String} RefererConfiguration.EmptyReferConfiguration ,非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function putBucketReferer(params, callback) { + + if (!params['RefererConfiguration']) { + callback({ error: 'missing param RefererConfiguration' }); + return; + } + + var RefererConfiguration = util.clone(params['RefererConfiguration'] || {}); + var DomainList = RefererConfiguration['DomainList'] || {}; + var Domains = DomainList['Domains'] || DomainList['Domain'] || []; + Domains = util.isArray(Domains) ? Domains : [Domains]; + if (Domains.length) RefererConfiguration.DomainList = {Domain: Domains}; + var xml = util.json2xml({ RefererConfiguration: RefererConfiguration }); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketReferer', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'referer', + headers: headers, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的防盗链白名单或者黑名单 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function getBucketReferer(params, callback) { + + submitRequest.call(this, { + Action: 'name/cos:GetBucketReferer', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + action: 'referer', + }, function (err, data) { + if (err) { + if(err.statusCode === 404 && err.error.Code === 'NoSuchRefererConfiguration'){ + var result = { + WebsiteConfiguration: {}, + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); + } + return; + } + + var RefererConfiguration = data.RefererConfiguration || {}; + if (RefererConfiguration['DomainList']) { + var Domains = util.clone(RefererConfiguration['DomainList'].Domain || []); + Domains = util.makeArray(Domains); + RefererConfiguration.DomainList = {Domains: Domains}; + } + + callback(null, { + RefererConfiguration: RefererConfiguration, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 设置 Bucket 自定义域名 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function putBucketDomain(params, callback) { + + var DomainConfiguration = params['DomainConfiguration'] || {}; + var DomainRule = DomainConfiguration.DomainRule || params.DomainRule || []; + DomainRule = util.clone(DomainRule); + var xml = util.json2xml({DomainConfiguration: {DomainRule: DomainRule}}); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketDomain', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'domain', + headers: headers, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的自定义域名 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function getBucketDomain(params, callback) { + + submitRequest.call(this, { + Action: 'name/cos:GetBucketDomain', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'domain', + }, function (err, data) { + if (err) return callback(err); + + var DomainRule = []; + try { + DomainRule = data.DomainConfiguration.DomainRule || []; + } catch (e) { + } + DomainRule = util.clone(util.isArray(DomainRule) ? DomainRule : [DomainRule]); + callback(null, { + DomainRule: DomainRule, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 删除 Bucket 自定义域名 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function deleteBucketDomain(params, callback) { + + submitRequest.call(this, { + Action: 'name/cos:DeleteBucketDomain', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'domain', + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 设置 Bucket 的回源 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function putBucketOrigin(params, callback){ + var OriginConfiguration = params['OriginConfiguration'] || {}; + var OriginRule = OriginConfiguration.OriginRule || params.OriginRule || []; + OriginRule = util.clone(OriginRule); + var xml = util.json2xml({OriginConfiguration: {OriginRule: OriginRule}}); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketOrigin', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'origin', + headers: headers, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的回源 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function getBucketOrigin(params, callback) { + + submitRequest.call(this, { + Action: 'name/cos:GetBucketOrigin', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'origin', + }, function (err, data) { + if (err) return callback(err); + + var OriginRule = []; + try { + OriginRule = data.OriginConfiguration.OriginRule || []; + } catch (e) { + } + OriginRule = util.clone(util.isArray(OriginRule) ? OriginRule : [OriginRule]); + callback(null, { + OriginRule: OriginRule, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 删除 Bucket 的回源 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function deleteBucketOrigin(params, callback) { + + submitRequest.call(this, { + Action: 'name/cos:DeleteBucketOrigin', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'origin', + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 设置 Bucket 的日志记录 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {(Object|String)} params.BucketLoggingStatus 说明日志记录配置的状态,如果无子节点信息则意为关闭日志记录,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function putBucketLogging(params, callback) { + var xml = util.json2xml({ + BucketLoggingStatus: params['BucketLoggingStatus'] || '' + }); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketLogging', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'logging', + headers: headers, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的日志记录 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function getBucketLogging(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:GetBucketLogging', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'logging', + }, function (err, data) { + if (err) return callback(err); + delete data.BucketLoggingStatus._xmlns; + callback(null, { + BucketLoggingStatus: data.BucketLoggingStatus, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 创建/编辑 Bucket 的清单任务 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Id 清单任务的名称,必须 + * @param {Object} params.InventoryConfiguration 包含清单的配置参数,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function putBucketInventory(params, callback) { + var InventoryConfiguration = util.clone(params['InventoryConfiguration']); + + if (InventoryConfiguration.OptionalFields) { + var Field = InventoryConfiguration.OptionalFields || []; + InventoryConfiguration.OptionalFields = { + Field: Field + }; + } + + if (InventoryConfiguration.Destination + && InventoryConfiguration.Destination.COSBucketDestination + && InventoryConfiguration.Destination.COSBucketDestination.Encryption + ) { + var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption; + if (Object.keys(Encryption).indexOf('SSECOS') > -1) { + Encryption['SSE-COS'] = Encryption['SSECOS']; + delete Encryption['SSECOS']; + } + } + + var xml = util.json2xml({ + InventoryConfiguration: InventoryConfiguration + }); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:PutBucketInventory', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'inventory', + qs: { + id: params['Id'] + }, + headers: headers, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的清单任务信息 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Id 清单任务的名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function getBucketInventory(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:GetBucketInventory', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'inventory', + qs: { + id: params['Id'] + } + }, function (err, data) { + if (err) return callback(err); + + var InventoryConfiguration = data['InventoryConfiguration']; + if (InventoryConfiguration && InventoryConfiguration.OptionalFields && InventoryConfiguration.OptionalFields.Field) { + var Field = InventoryConfiguration.OptionalFields.Field; + if (!util.isArray(Field)) { + Field = [Field]; + } + InventoryConfiguration.OptionalFields = Field; + } + if (InventoryConfiguration.Destination + && InventoryConfiguration.Destination.COSBucketDestination + && InventoryConfiguration.Destination.COSBucketDestination.Encryption + ) { + var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption; + if (Object.keys(Encryption).indexOf('SSE-COS') > -1) { + Encryption['SSECOS'] = Encryption['SSE-COS']; + delete Encryption['SSE-COS']; + } + } + + callback(null, { + InventoryConfiguration: InventoryConfiguration, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Bucket 的清单任务信息 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.ContinuationToken 当 COS 响应体中 IsTruncated 为 true,且 NextContinuationToken 节点中存在参数值时,您可以将这个参数作为 continuation-token 参数值,以获取下一页的清单任务信息,非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function listBucketInventory(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:ListBucketInventory', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'inventory', + qs: { + 'continuation-token': params['ContinuationToken'] + } + }, function (err, data) { + if (err) return callback(err); + var ListInventoryConfigurationResult = data['ListInventoryConfigurationResult']; + var InventoryConfigurations = ListInventoryConfigurationResult.InventoryConfiguration || []; + InventoryConfigurations = util.isArray(InventoryConfigurations) ? InventoryConfigurations : [InventoryConfigurations]; + delete ListInventoryConfigurationResult['InventoryConfiguration']; + util.each(InventoryConfigurations, function (InventoryConfiguration) { + if (InventoryConfiguration && InventoryConfiguration.OptionalFields && InventoryConfiguration.OptionalFields.Field) { + var Field = InventoryConfiguration.OptionalFields.Field; + if (!util.isArray(Field)) { + Field = [Field]; + } + InventoryConfiguration.OptionalFields = Field; + } + + if (InventoryConfiguration.Destination + && InventoryConfiguration.Destination.COSBucketDestination + && InventoryConfiguration.Destination.COSBucketDestination.Encryption + ) { + var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption; + if (Object.keys(Encryption).indexOf('SSE-COS') > -1) { + Encryption['SSECOS'] = Encryption['SSE-COS']; + delete Encryption['SSE-COS']; + } + } + }); + ListInventoryConfigurationResult.InventoryConfigurations = InventoryConfigurations; + util.extend(ListInventoryConfigurationResult, { + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, ListInventoryConfigurationResult); + }); +} + +/** + * 删除 Bucket 的清单任务 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Id 清单任务的名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回数据 + */ +function deleteBucketInventory(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:DeleteBucketInventory', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'inventory', + qs: { + id: params['Id'] + } + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/* 全球加速 */ +function putBucketAccelerate(params, callback) { + + if (!params['AccelerateConfiguration']) { + callback({error: 'missing param AccelerateConfiguration'}); + return; + } + + var configuration = { AccelerateConfiguration: params.AccelerateConfiguration || {} }; + + var xml = util.json2xml(configuration); + + var headers = {}; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Interface: 'putBucketAccelerate', + Action: 'name/cos:PutBucketAccelerate', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'accelerate', + headers: headers, + }, function (err, data) { + if (err) return callback(err); + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +function getBucketAccelerate(params, callback) { + submitRequest.call(this, { + Interface: 'getBucketAccelerate', + Action: 'name/cos:GetBucketAccelerate', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + action: 'accelerate', + }, function (err, data) { + if (!err) { + !data.AccelerateConfiguration && (data.AccelerateConfiguration = {}); + } + callback(err, data); + }); +} + +// Object 相关 + +/** + * 取回对应Object的元数据,Head的权限与Get的权限一致 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key 文件名称,必须 + * @param {String} params.IfModifiedSince 当Object在指定时间后被修改,则返回对应Object元信息,否则返回304,非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 为指定 object 的元数据,如果设置了 IfModifiedSince ,且文件未修改,则返回一个对象,NotModified 属性为 true + * @return {Boolean} data.NotModified 是否在 IfModifiedSince 时间点之后未修改该 object,则为 true + */ +function headObject(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:HeadObject', + method: 'HEAD', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + VersionId: params.VersionId, + headers: params.Headers, + }, function (err, data) { + if (err) { + var statusCode = err.statusCode; + if (params.Headers['If-Modified-Since'] && statusCode && statusCode === 304) { + return callback(null, { + NotModified: true, + statusCode: statusCode, + }); + } + return callback(err); + } + data.ETag = util.attr(data.headers, 'etag', ''); + callback(null, data); + }); +} + + +function listObjectVersions(params, callback) { + var reqParams = {}; + reqParams['prefix'] = params['Prefix'] || ''; + reqParams['delimiter'] = params['Delimiter']; + reqParams['key-marker'] = params['KeyMarker']; + reqParams['version-id-marker'] = params['VersionIdMarker']; + reqParams['max-keys'] = params['MaxKeys']; + reqParams['encoding-type'] = params['EncodingType']; + + submitRequest.call(this, { + Action: 'name/cos:GetBucketObjectVersions', + ResourceKey: reqParams['prefix'], + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + qs: reqParams, + action: 'versions', + }, function (err, data) { + if (err) return callback(err); + var ListVersionsResult = data.ListVersionsResult || {}; + var DeleteMarkers = ListVersionsResult.DeleteMarker || []; + DeleteMarkers = util.isArray(DeleteMarkers) ? DeleteMarkers : [DeleteMarkers]; + var Versions = ListVersionsResult.Version || []; + Versions = util.isArray(Versions) ? Versions : [Versions]; + + var result = util.clone(ListVersionsResult); + delete result.DeleteMarker; + delete result.Version; + util.extend(result, { + DeleteMarkers: DeleteMarkers, + Versions: Versions, + statusCode: data.statusCode, + headers: data.headers, + }); + + callback(null, result); + }); +} + +/** + * 下载 object + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key 文件名称,必须 + * @param {WriteStream} params.Output 文件写入流,非必须 + * @param {String} params.IfModifiedSince 当Object在指定时间后被修改,则返回对应Object元信息,否则返回304,非必须 + * @param {String} params.IfUnmodifiedSince 如果文件修改时间早于或等于指定时间,才返回文件内容。否则返回 412 (precondition failed),非必须 + * @param {String} params.IfMatch 当 ETag 与指定的内容一致,才返回文件。否则返回 412 (precondition failed),非必须 + * @param {String} params.IfNoneMatch 当 ETag 与指定的内容不一致,才返回文件。否则返回304 (not modified),非必须 + * @param {String} params.ResponseContentType 设置返回头部中的 Content-Type 参数,非必须 + * @param {String} params.ResponseContentLanguage 设置返回头部中的 Content-Language 参数,非必须 + * @param {String} params.ResponseExpires 设置返回头部中的 Content-Expires 参数,非必须 + * @param {String} params.ResponseCacheControl 设置返回头部中的 Cache-Control 参数,非必须 + * @param {String} params.ResponseContentDisposition 设置返回头部中的 Content-Disposition 参数,非必须 + * @param {String} params.ResponseContentEncoding 设置返回头部中的 Content-Encoding 参数,非必须 + * @param {Function} callback 回调函数,必须 + * @param {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @param {Object} data 为对应的 object 数据,包括 body 和 headers + */ +function getObject(params, callback) { + var reqParams = params.Query || {}; + var reqParamsStr = params.QueryString || ''; + + reqParams['response-content-type'] = params['ResponseContentType']; + reqParams['response-content-language'] = params['ResponseContentLanguage']; + reqParams['response-expires'] = params['ResponseExpires']; + reqParams['response-cache-control'] = params['ResponseCacheControl']; + reqParams['response-content-disposition'] = params['ResponseContentDisposition']; + reqParams['response-content-encoding'] = params['ResponseContentEncoding']; + + // 如果用户自己传入了 output + submitRequest.call(this, { + Action: 'name/cos:GetObject', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + VersionId: params.VersionId, + headers: params.Headers, + qs: reqParams, + qsStr: reqParamsStr, + rawBody: true, + }, function (err, data) { + if (err) { + var statusCode = err.statusCode; + if (params.Headers['If-Modified-Since'] && statusCode && statusCode === 304) { + return callback(null, { + NotModified: true + }); + } + return callback(err); + } + callback(null, { + Body: data.body, + ETag: util.attr(data.headers, 'etag', ''), + statusCode: data.statusCode, + headers: data.headers, + }); + }); + +} + +/** + * 上传 object + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key 文件名称,必须 + * @param {String} params.Body 上传文件的内容,只支持字符串 + * @param {String} params.CacheControl RFC 2616 中定义的缓存策略,将作为 Object 元数据保存,非必须 + * @param {String} params.ContentDisposition RFC 2616 中定义的文件名称,将作为 Object 元数据保存,非必须 + * @param {String} params.ContentEncoding RFC 2616 中定义的编码格式,将作为 Object 元数据保存,非必须 + * @param {String} params.ContentLength RFC 2616 中定义的 HTTP 请求内容长度(字节),必须 + * @param {String} params.ContentType RFC 2616 中定义的内容类型(MIME),将作为 Object 元数据保存,非必须 + * @param {String} params.Expect 当使用 Expect: 100-continue 时,在收到服务端确认后,才会发送请求内容,非必须 + * @param {String} params.Expires RFC 2616 中定义的过期时间,将作为 Object 元数据保存,非必须 + * @param {String} params.ContentSha1 RFC 3174 中定义的 160-bit 内容 SHA-1 算法校验,非必须 + * @param {String} params.ACL 允许用户自定义文件权限,有效值:private | public-read,非必须 + * @param {String} params.GrantRead 赋予被授权者读的权限,格式 x-cos-grant-read: uin=" ",uin=" ",非必须 + * @param {String} params.GrantWrite 赋予被授权者写的权限,格式 x-cos-grant-write: uin=" ",uin=" ",非必须 + * @param {String} params.GrantFullControl 赋予被授权者读写权限,格式 x-cos-grant-full-control: uin=" ",uin=" ",非必须 + * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须 + * @param {Function} params.onProgress 上传进度回调函数 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 为对应的 object 数据 + * @return {String} data.ETag 为对应上传文件的 ETag 值 + */ +function putObject(params, callback) { + var self = this; + var FileSize = params.ContentLength; + var onProgress = util.throttleOnProgress.call(self, FileSize, params.onProgress); + + // 特殊处理 Cache-Control、Content-Type,避免代理更改这两个字段导致写入到 Object 属性里 + var headers = params.Headers; + if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = ''; + if (!headers['Content-Type'] && !headers['content-type']) headers['Content-Type'] = mime.getType(params.Key) || 'application/octet-stream'; + + util.getBodyMd5(self.options.UploadCheckContentMd5, params.Body, function (md5) { + if (md5) headers['Content-MD5'] = util.binaryBase64(md5); + if (params.ContentLength !== undefined) headers['Content-Length'] = params.ContentLength; + onProgress(null, true); // 任务状态开始 uploading + submitRequest.call(self, { + Action: 'name/cos:PutObject', + TaskId: params.TaskId, + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + qs: params.Query, + body: params.Body, + onProgress: onProgress, + }, function (err, data) { + if (err) { + onProgress(null, true); + return callback(err); + } + onProgress({loaded: FileSize, total: FileSize}, true); + var url = getUrl({ + ForcePathStyle: self.options.ForcePathStyle, + protocol: self.options.Protocol, + domain: self.options.Domain, + bucket: params.Bucket, + region: !self.options.UseAccelerate ? params.Region : 'accelerate', + object: params.Key, + }); + url = url.substr(url.indexOf('://') + 3); + data.Location = url; + data.ETag = util.attr(data.headers, 'etag', ''); + callback(null, data); + }); + }); +} + +/** + * 上传 object + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key 文件名称,必须 + * @param {FilePath} params.FilePath 要上传的文件路径 + * @param {Function} params.onProgress 上传进度回调函数 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 为对应的 object 数据 + * @return {String} data.ETag 为对应上传文件的 ETag 值 + */ +function postObject(params, callback) { + var self = this; + var headers = {}; + var filePath = params.FilePath; + if (!filePath) { + callback({error: 'missing param FilePath'}); + return; + } + + headers['Cache-Control'] = params['CacheControl']; + headers['Content-Disposition'] = params['ContentDisposition']; + headers['Content-Encoding'] = params['ContentEncoding']; + headers['Content-MD5'] = params['ContentMD5']; + headers['Content-Length'] = params['ContentLength']; + headers['Content-Type'] = params['ContentType']; + headers['Expect'] = params['Expect']; + headers['Expires'] = params['Expires']; + headers['x-cos-acl'] = params['ACL']; + headers['x-cos-grant-read'] = params['GrantRead']; + headers['x-cos-grant-write'] = params['GrantWrite']; + headers['x-cos-grant-full-control'] = params['GrantFullControl']; + headers['x-cos-storage-class'] = params['StorageClass']; + + // 删除 Content-Length 避免签名错误 + delete headers['Content-Length']; + delete headers['content-length']; + + for (var key in params) { + if (key.indexOf('x-cos-meta-') > -1) { + headers[key] = params[key]; + } + } + + var onProgress = util.throttleOnProgress.call(self, headers['Content-Length'], params.onProgress); + + submitRequest.call(this, { + Action: 'name/cos:PostObject', + method: 'POST', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: headers, + qs: params.Query, + filePath: filePath, + onProgress: onProgress, + }, function (err, data) { + onProgress(null, true); + if (err) return callback(err); + if (data && data.headers) { + var headers = data.headers; + var ETag = headers.etag || headers.Etag || headers.ETag || ''; + var filename = filePath.substr(filePath.lastIndexOf('/') + 1); + var url = getUrl({ + ForcePathStyle: self.options.ForcePathStyle, + protocol: self.options.Protocol, + domain: self.options.Domain, + bucket: params.Bucket, + region: params.Region, + object: params.Key.replace(/\$\{filename\}/g, filename), + isLocation: true, + }); + + return callback(null, { + Location: url, + statusCode: data.statusCode, + headers: headers, + ETag: ETag, + }); + } + callback(null, data); + }); +} + +/** + * 删除 object + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {Function} callback 回调函数,必须 + * @param {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @param {Object} data 删除操作成功之后返回的数据 + */ +function deleteObject(params, callback) { + submitRequest.call(this, { + Action: 'name/cos:DeleteObject', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + VersionId: params.VersionId, + }, function (err, data) { + if (err) { + var statusCode = err.statusCode; + if (statusCode && statusCode === 204) { + return callback(null, {statusCode: statusCode}); + } else if (statusCode && statusCode === 404) { + return callback(null, {BucketNotFound: true, statusCode: statusCode,}); + } else { + return callback(err); + } + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 object 的 权限列表 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {Object} data.AccessControlPolicy 权限列表 + */ +function getObjectAcl(params, callback) { + + submitRequest.call(this, { + Action: 'name/cos:GetObjectACL', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + action: 'acl', + }, function (err, data) { + if (err) return callback(err); + var AccessControlPolicy = data.AccessControlPolicy || {}; + var Owner = AccessControlPolicy.Owner || {}; + var Grant = AccessControlPolicy.AccessControlList && AccessControlPolicy.AccessControlList.Grant || []; + Grant = util.isArray(Grant) ? Grant : [Grant]; + var result = decodeAcl(AccessControlPolicy); + if (data.headers && data.headers['x-cos-acl']) { + result.ACL = data.headers['x-cos-acl']; + } + result = util.extend(result, { + Owner: Owner, + Grants: Grant, + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }); +} + +/** + * 设置 object 的 权限列表 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ +function putObjectAcl(params, callback) { + var headers = params.Headers; + + var xml = ''; + if (params['AccessControlPolicy']) { + var AccessControlPolicy = util.clone(params['AccessControlPolicy'] || {}); + var Grants = AccessControlPolicy.Grants || AccessControlPolicy.Grant; + Grants = util.isArray(Grants) ? Grants : [Grants]; + delete AccessControlPolicy.Grant; + delete AccessControlPolicy.Grants; + AccessControlPolicy.AccessControlList = {Grant: Grants}; + xml = util.json2xml({AccessControlPolicy: AccessControlPolicy}); + + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + } + + // Grant Header 去重 + util.each(headers, function (val, key) { + if (key.indexOf('x-cos-grant-') === 0) { + headers[key] = uniqGrant(headers[key]); + } + }); + + submitRequest.call(this, { + Action: 'name/cos:PutObjectACL', + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + action: 'acl', + headers: headers, + body: xml, + }, function (err, data) { + if (err) return callback(err); + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * Options Object请求实现跨域访问的预请求。即发出一个 OPTIONS 请求给服务器以确认是否可以进行跨域操作。 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ +function optionsObject(params, callback) { + + var headers = params.Headers; + headers['Origin'] = params['Origin']; + headers['Access-Control-Request-Method'] = params['AccessControlRequestMethod']; + headers['Access-Control-Request-Headers'] = params['AccessControlRequestHeaders']; + + submitRequest.call(this, { + Action: 'name/cos:OptionsObject', + method: 'OPTIONS', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: headers, + }, function (err, data) { + if (err) { + if (err.statusCode && err.statusCode === 403) { + return callback(null, { + OptionsForbidden: true, + statusCode: err.statusCode + }); + } + return callback(err); + } + + var headers = data.headers || {}; + callback(null, { + AccessControlAllowOrigin: headers['access-control-allow-origin'], + AccessControlAllowMethods: headers['access-control-allow-methods'], + AccessControlAllowHeaders: headers['access-control-allow-headers'], + AccessControlExposeHeaders: headers['access-control-expose-headers'], + AccessControlMaxAge: headers['access-control-max-age'], + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * @param {Object} 参数列表 + * @param {String} Bucket Bucket 名称 + * @param {String} Region 地域名称 + * @param {String} Key 文件名称 + * @param {String} CopySource 源文件URL绝对路径,可以通过versionid子资源指定历史版本 + * @param {String} ACL 允许用户自定义文件权限。有效值:private,public-read默认值:private。 + * @param {String} GrantRead 赋予被授权者读的权限,格式 x-cos-grant-read: uin=" ",uin=" ",当需要给子账户授权时,uin="RootAcountID/SubAccountID",当需要给根账户授权时,uin="RootAcountID"。 + * @param {String} GrantWrite 赋予被授权者写的权限,格式 x-cos-grant-write: uin=" ",uin=" ",当需要给子账户授权时,uin="RootAcountID/SubAccountID",当需要给根账户授权时,uin="RootAcountID"。 + * @param {String} GrantFullControl 赋予被授权者读写权限,格式 x-cos-grant-full-control: uin=" ",uin=" ",当需要给子账户授权时,uin="RootAcountID/SubAccountID",当需要给根账户授权时,uin="RootAcountID"。 + * @param {String} MetadataDirective 是否拷贝元数据,枚举值:Copy, Replaced,默认值Copy。假如标记为Copy,忽略Header中的用户元数据信息直接复制;假如标记为Replaced,按Header信息修改元数据。当目标路径和原路径一致,即用户试图修改元数据时,必须为Replaced + * @param {String} CopySourceIfModifiedSince 当Object在指定时间后被修改,则执行操作,否则返回412。可与x-cos-copy-source-If-None-Match一起使用,与其他条件联合使用返回冲突。 + * @param {String} CopySourceIfUnmodifiedSince 当Object在指定时间后未被修改,则执行操作,否则返回412。可与x-cos-copy-source-If-Match一起使用,与其他条件联合使用返回冲突。 + * @param {String} CopySourceIfMatch 当Object的ETag和给定一致时,则执行操作,否则返回412。可与x-cos-copy-source-If-Unmodified-Since一起使用,与其他条件联合使用返回冲突。 + * @param {String} CopySourceIfNoneMatch 当Object的ETag和给定不一致时,则执行操作,否则返回412。可与x-cos-copy-source-If-Modified-Since一起使用,与其他条件联合使用返回冲突。 + * @param {String} StorageClass 存储级别,枚举值:存储级别,枚举值:Standard, Standard_IA,Archive;默认值:Standard + * @param {String} CacheControl 指定所有缓存机制在整个请求/响应链中必须服从的指令。 + * @param {String} ContentDisposition MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件 + * @param {String} ContentEncoding HTTP 中用来对「采用何种编码格式传输正文」进行协定的一对头部字段 + * @param {String} ContentLength 设置响应消息的实体内容的大小,单位为字节 + * @param {String} ContentType RFC 2616 中定义的 HTTP 请求内容类型(MIME),例如text/plain + * @param {String} Expect 请求的特定的服务器行为 + * @param {String} Expires 响应过期的日期和时间 + * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须 + * @param {String} ContentLanguage 指定内容语言 + * @param {String} x-cos-meta-* 允许用户自定义的头部信息,将作为 Object 元数据返回。大小限制2K。 + */ +function putObjectCopy(params, callback) { + + // 特殊处理 Cache-Control + var headers = params.Headers; + if (!headers['Cache-Control'] && !!headers['cache-control']) headers['Cache-Control'] = ''; + + var CopySource = params.CopySource || ''; + var m = CopySource.match(/^([^.]+-\d+)\.cos(v6)?\.([^.]+)\.[^/]+\/(.+)$/); + if (!m) { + callback({error: 'CopySource format error'}); + return; + } + + var SourceBucket = m[1]; + var SourceRegion = m[3]; + var SourceKey = decodeURIComponent(m[4]); + + submitRequest.call(this, { + Scope: [{ + action: 'name/cos:GetObject', + bucket: SourceBucket, + region: SourceRegion, + prefix: SourceKey, + }, { + action: 'name/cos:PutObject', + bucket: params.Bucket, + region: params.Region, + prefix: params.Key, + }], + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + VersionId: params.VersionId, + headers: params.Headers, + }, function (err, data) { + if (err) return callback(err); + var result = util.clone(data.CopyObjectResult || {}); + util.extend(result, { + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }); +} + +function uploadPartCopy(params, callback) { + + var CopySource = params.CopySource || ''; + var m = CopySource.match(/^([^.]+-\d+)\.cos(v6)?\.([^.]+)\.[^/]+\/(.+)$/); + if (!m) { + callback({error: 'CopySource format error'}); + return; + } + + var SourceBucket = m[1]; + var SourceRegion = m[3]; + var SourceKey = decodeURIComponent(m[4]); + + submitRequest.call(this, { + Scope: [{ + action: 'name/cos:GetObject', + bucket: SourceBucket, + region: SourceRegion, + prefix: SourceKey, + }, { + action: 'name/cos:PutObject', + bucket: params.Bucket, + region: params.Region, + prefix: params.Key, + }], + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + VersionId: params.VersionId, + qs: { + partNumber: params['PartNumber'], + uploadId: params['UploadId'], + }, + headers: params.Headers, + }, function (err, data) { + if (err) return callback(err); + var result = util.clone(data.CopyPartResult || {}); + util.extend(result, { + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }); +} + +function deleteMultipleObject(params, callback) { + var Objects = params.Objects || []; + var Quiet = params.Quiet; + Objects = util.isArray(Objects) ? Objects : [Objects]; + + var xml = util.json2xml({Delete: {Object: Objects, Quiet: Quiet || false}}); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + var Scope = util.map(Objects, function (v) { + return { + action: 'name/cos:DeleteObject', + bucket: params.Bucket, + region: params.Region, + prefix: v.Key, + }; + }); + + submitRequest.call(this, { + Scope: Scope, + method: 'POST', + Bucket: params.Bucket, + Region: params.Region, + body: xml, + action: 'delete', + headers: headers, + }, function (err, data) { + if (err) return callback(err); + var DeleteResult = data.DeleteResult || {}; + var Deleted = DeleteResult.Deleted || []; + var Errors = DeleteResult.Error || []; + + Deleted = util.isArray(Deleted) ? Deleted : [Deleted]; + Errors = util.isArray(Errors) ? Errors : [Errors]; + + var result = util.clone(DeleteResult); + util.extend(result, { + Error: Errors, + Deleted: Deleted, + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }); +} + +function restoreObject(params, callback) { + var headers = params.Headers; + if (!params['RestoreRequest']) { + callback({error: 'missing param RestoreRequest'}); + return; + } + + var RestoreRequest = params.RestoreRequest || {}; + var xml = util.json2xml({RestoreRequest: RestoreRequest}); + + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:RestoreObject', + method: 'POST', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + VersionId: params.VersionId, + body: xml, + action: 'restore', + headers: headers, + }, function (err, data) { + callback(err, data); + }); +} + +/** + * 设置 Object 的标签 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Object名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Array} params.TagSet 标签设置,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/42998 + * @return {Object} data 返回数据 + */ +function putObjectTagging(params, callback) { + + var Tagging = params['Tagging'] || {}; + var Tags = Tagging.TagSet || Tagging.Tags || params['Tags'] || []; + Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); + var xml = util.json2xml({Tagging: {TagSet: {Tag: Tags}}}); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Interface: 'putObjectTagging', + Action: 'name/cos:PutObjectTagging', + method: 'PUT', + Bucket: params.Bucket, + Key: params.Key, + Region: params.Region, + body: xml, + action: 'tagging', + headers: headers, + VersionId: params.VersionId, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 获取 Object 的标签设置 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/42998 + * @return {Object} data 返回数据 + */ +function getObjectTagging(params, callback) { + + submitRequest.call(this, { + Interface: 'getObjectTagging', + Action: 'name/cos:GetObjectTagging', + method: 'GET', + Key: params.Key, + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + action: 'tagging', + VersionId: params.VersionId, + }, function (err, data) { + if (err) { + if (err.statusCode === 404 && err.error && (err.error === "Not Found" || err.error.Code === 'NoSuchTagSet')) { + var result = { + Tags: [], + statusCode: err.statusCode, + }; + err.headers && (result.headers = err.headers); + callback(null, result); + } else { + callback(err); + } + return; + } + var Tags = []; + try { + Tags = data.Tagging.TagSet.Tag || []; + } catch (e) { + } + Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]); + callback(null, { + Tags: Tags, + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + +/** + * 删除 Object 的 标签设置 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Object名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/42998 + * @return {Object} data 返回的数据 + */ +function deleteObjectTagging(params, callback) { + submitRequest.call(this, { + Interface: 'deleteObjectTagging', + Action: 'name/cos:DeleteObjectTagging', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + action: 'tagging', + VersionId: params.VersionId, + }, function (err, data) { + if (err && err.statusCode === 204) { + return callback(null, {statusCode: err.statusCode}); + } else if (err) { + return callback(err); + } + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + + +// 分块上传 + + +/** + * 初始化分块上传 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {String} params.UploadId object名称,必须 + * @param {String} params.CacheControl RFC 2616 中定义的缓存策略,将作为 Object 元数据保存,非必须 + * @param {String} params.ContentDisposition RFC 2616 中定义的文件名称,将作为 Object 元数据保存 ,非必须 + * @param {String} params.ContentEncoding RFC 2616 中定义的编码格式,将作为 Object 元数据保存,非必须 + * @param {String} params.ContentType RFC 2616 中定义的内容类型(MIME),将作为 Object 元数据保存,非必须 + * @param {String} params.Expires RFC 2616 中定义的过期时间,将作为 Object 元数据保存,非必须 + * @param {String} params.ACL 允许用户自定义文件权限,非必须 + * @param {String} params.GrantRead 赋予被授权者读的权限 ,非必须 + * @param {String} params.GrantWrite 赋予被授权者写的权限 ,非必须 + * @param {String} params.GrantFullControl 赋予被授权者读写权限 ,非必须 + * @param {String} params.StorageClass 设置Object的存储级别,枚举值:Standard,Standard_IA,Archive,非必须 + * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ +function multipartInit(params, callback) { + + var self = this; + var headers = params.Headers; + + // 特殊处理 Cache-Control、Content-Type + if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = ''; + if (!headers['Content-Type'] && !headers['content-type']) headers['Content-Type'] = mime.getType(params.Key) || 'application/octet-stream'; + + submitRequest.call(self, { + Action: 'name/cos:InitiateMultipartUpload', + method: 'POST', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + action: 'uploads', + headers: params.Headers, + qs: params.Query, + }, function (err, data) { + if (err) return callback(err); + data = util.clone(data || {}); + if (data && data.InitiateMultipartUploadResult) { + return callback(null, util.extend(data.InitiateMultipartUploadResult, { + statusCode: data.statusCode, + headers: data.headers, + })); + } + callback(null, data); + }); +} + +/** + * 分块上传 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {String} params.Body 上传文件对象或字符串 + * @param {String} params.ContentLength RFC 2616 中定义的 HTTP 请求内容长度(字节),非必须 + * @param {String} params.Expect 当使用 Expect: 100-continue 时,在收到服务端确认后,才会发送请求内容,非必须 + * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须 + * @param {String} params.ContentSha1 RFC 3174 中定义的 160-bit 内容 SHA-1 算法校验值,非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {Object} data.ETag 返回的文件分块 sha1 值 + */ +function multipartUpload(params, callback) { + + var self = this; + util.getFileSize('multipartUpload', params, function () { + util.getBodyMd5(self.options.UploadCheckContentMd5, params.Body, function (md5) { + if (md5) params.Headers['Content-MD5'] = util.binaryBase64(md5); + submitRequest.call(self, { + Action: 'name/cos:UploadPart', + TaskId: params.TaskId, + method: 'PUT', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + qs: { + partNumber: params['PartNumber'], + uploadId: params['UploadId'], + }, + headers: params.Headers, + onProgress: params.onProgress, + body: params.Body || null + }, function (err, data) { + if (err) return callback(err); + callback(null, { + ETag: util.attr(data.headers, 'etag', {}), + statusCode: data.statusCode, + headers: data.headers, + }); + }); + }); + }); + +} + +/** + * 完成分块上传 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {Array} params.Parts 分块信息列表,必须 + * @param {String} params.Parts[i].PartNumber 块编号,必须 + * @param {String} params.Parts[i].ETag 分块的 sha1 校验值 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {Object} data.CompleteMultipartUpload 完成分块上传后的文件信息,包括Location, Bucket, Key 和 ETag + */ +function multipartComplete(params, callback) { + var self = this; + + var UploadId = params.UploadId; + + var Parts = params['Parts']; + + for (var i = 0, len = Parts.length; i < len; i++) { + if (Parts[i]['ETag'].indexOf('"') === 0) { + continue; + } + Parts[i]['ETag'] = '"' + Parts[i]['ETag'] + '"'; + } + + var xml = util.json2xml({CompleteMultipartUpload: {Part: Parts}}); + + var headers = params.Headers; + headers['Content-Type'] = 'application/xml'; + headers['Content-MD5'] = util.binaryBase64(util.md5(xml)); + + submitRequest.call(this, { + Action: 'name/cos:CompleteMultipartUpload', + method: 'POST', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + qs: { + uploadId: UploadId + }, + body: xml, + headers: headers, + }, function (err, data) { + if (err) return callback(err); + var url = getUrl({ + ForcePathStyle: self.options.ForcePathStyle, + protocol: self.options.Protocol, + domain: self.options.Domain, + bucket: params.Bucket, + region: params.Region, + object: params.Key, + isLocation: true, + }); + var CompleteMultipartUploadResult = data.CompleteMultipartUploadResult || {}; + var result = util.extend(CompleteMultipartUploadResult, { + Location: url, + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }); +} + +/** + * 分块上传任务列表查询 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Delimiter 定界符为一个符号,如果有Prefix,则将Prefix到delimiter之间的相同路径归为一类,定义为Common Prefix,然后列出所有Common Prefix。如果没有Prefix,则从路径起点开始,非必须 + * @param {String} params.EncodingType 规定返回值的编码方式,非必须 + * @param {String} params.Prefix 前缀匹配,用来规定返回的文件前缀地址,非必须 + * @param {String} params.MaxUploads 单次返回最大的条目数量,默认1000,非必须 + * @param {String} params.KeyMarker 与upload-id-marker一起使用
当upload-id-marker未被指定时,ObjectName字母顺序大于key-marker的条目将被列出
当upload-id-marker被指定时,ObjectName字母顺序大于key-marker的条目被列出,ObjectName字母顺序等于key-marker同时UploadId大于upload-id-marker的条目将被列出,非必须 + * @param {String} params.UploadIdMarker 与key-marker一起使用
当key-marker未被指定时,upload-id-marker将被忽略
当key-marker被指定时,ObjectName字母顺序大于key-marker的条目被列出,ObjectName字母顺序等于key-marker同时UploadId大于upload-id-marker的条目将被列出,非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {Object} data.ListMultipartUploadsResult 分块上传任务信息 + */ +function multipartList(params, callback) { + var reqParams = {}; + + reqParams['delimiter'] = params['Delimiter']; + reqParams['encoding-type'] = params['EncodingType']; + reqParams['prefix'] = params['Prefix'] || ''; + + reqParams['max-uploads'] = params['MaxUploads']; + + reqParams['key-marker'] = params['KeyMarker']; + reqParams['upload-id-marker'] = params['UploadIdMarker']; + + reqParams = util.clearKey(reqParams); + + submitRequest.call(this, { + Action: 'name/cos:ListMultipartUploads', + ResourceKey: reqParams['prefix'], + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + headers: params.Headers, + qs: reqParams, + action: 'uploads', + }, function (err, data) { + if (err) return callback(err); + + if (data && data.ListMultipartUploadsResult) { + var Upload = data.ListMultipartUploadsResult.Upload || []; + + var CommonPrefixes = data.ListMultipartUploadsResult.CommonPrefixes || []; + + CommonPrefixes = util.isArray(CommonPrefixes) ? CommonPrefixes : [CommonPrefixes]; + Upload = util.isArray(Upload) ? Upload : [Upload]; + + data.ListMultipartUploadsResult.Upload = Upload; + data.ListMultipartUploadsResult.CommonPrefixes = CommonPrefixes; + } + var result = util.clone(data.ListMultipartUploadsResult || {}); + util.extend(result, { + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }); +} + +/** + * 上传的分块列表查询 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {String} params.UploadId 标示本次分块上传的ID,必须 + * @param {String} params.EncodingType 规定返回值的编码方式,非必须 + * @param {String} params.MaxParts 单次返回最大的条目数量,默认1000,非必须 + * @param {String} params.PartNumberMarker 默认以UTF-8二进制顺序列出条目,所有列出条目从marker开始,非必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + * @return {Object} data.ListMultipartUploadsResult 分块信息 + */ +function multipartListPart(params, callback) { + var reqParams = {}; + + reqParams['uploadId'] = params['UploadId']; + reqParams['encoding-type'] = params['EncodingType']; + reqParams['max-parts'] = params['MaxParts']; + reqParams['part-number-marker'] = params['PartNumberMarker']; + + submitRequest.call(this, { + Action: 'name/cos:ListParts', + method: 'GET', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + qs: reqParams, + }, function (err, data) { + if (err) return callback(err); + var ListPartsResult = data.ListPartsResult || {}; + var Part = ListPartsResult.Part || []; + Part = util.isArray(Part) ? Part : [Part]; + + ListPartsResult.Part = Part; + var result = util.clone(ListPartsResult); + util.extend(result, { + statusCode: data.statusCode, + headers: data.headers, + }); + callback(null, result); + }); +} + +/** + * 抛弃分块上传 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {String} params.UploadId 标示本次分块上传的ID,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ +function multipartAbort(params, callback) { + var reqParams = {}; + + reqParams['uploadId'] = params['UploadId']; + submitRequest.call(this, { + Action: 'name/cos:AbortMultipartUpload', + method: 'DELETE', + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + headers: params.Headers, + qs: reqParams, + }, function (err, data) { + if (err) return callback(err); + callback(null, { + statusCode: data.statusCode, + headers: data.headers, + }); + }); +} + + +/** + * cos 内置请求 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ + function request(params, callback) { + submitRequest.call(this, { + method: params.Method, + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + action: params.Action, + headers: params.Headers, + qs: params.Query, + body: params.Body, + }, function (err, data) { + if (err) return callback(err); + if (data && data.body) { + data.Body = data.body; + delete data.body; + } + callback(err, data); + }); +} + +/** + * 获取签名 + * @param {Object} params 参数对象,必须 + * @param {String} params.Method 请求方法,必须 + * @param {String} params.Key object名称,必须 + * @param {String} params.Expires 名超时时间,单位秒,可选 + * @return {String} data 返回签名字符串 + */ +function getAuth(params) { + var self = this; + return util.getAuth({ + SecretId: params.SecretId || this.options.SecretId || '', + SecretKey: params.SecretKey || this.options.SecretKey || '', + Method: params.Method, + Key: params.Key, + Query: params.Query, + Headers: params.Headers, + Expires: params.Expires, + SystemClockOffset: self.options.SystemClockOffset, + }); +} + +/** + * 获取文件下载链接 + * @param {Object} params 参数对象,必须 + * @param {String} params.Bucket Bucket名称,必须 + * @param {String} params.Region 地域名称,必须 + * @param {String} params.Key object名称,必须 + * @param {String} params.Method 请求的方法,可选 + * @param {String} params.Expires 签名超时时间,单位秒,可选 + * @param {Function} callback 回调函数,必须 + * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730 + * @return {Object} data 返回的数据 + */ +function getObjectUrl(params, callback) { + var self = this; + var url = getUrl({ + ForcePathStyle: self.options.ForcePathStyle, + protocol: params.Protocol || self.options.Protocol, + domain: params.Domain || self.options.Domain, + bucket: params.Bucket, + region: params.Region, + object: params.Key, + }); + + var queryParamsStr = ''; + if(params.Query){ + queryParamsStr += util.obj2str(params.Query); + } + if(params.QueryString){ + queryParamsStr += (queryParamsStr ? '&' : '') + params.QueryString; + } + + var syncUrl = url; + if (params.Sign !== undefined && !params.Sign) { + queryParamsStr && (syncUrl += '?' + queryParamsStr); + callback(null, {Url: syncUrl}); + return syncUrl; + } + var AuthData = getAuthorizationAsync.call(this, { + Action: ((params.Method || '').toUpperCase() === 'PUT' ? 'name/cos:PutObject' : 'name/cos:GetObject'), + Bucket: params.Bucket || '', + Region: params.Region || '', + Method: params.Method || 'get', + Key: params.Key, + Expires: params.Expires, + Headers: params.Headers, + Query: params.Query + }, function (err, AuthData) { + if (!callback) return; + if (err) { + callback(err); + return; + } + var signUrl = url; + signUrl += '?' + (AuthData.Authorization.indexOf('q-signature') > -1 ? + AuthData.Authorization : 'sign=' + encodeURIComponent(AuthData.Authorization)); + AuthData.XCosSecurityToken && (signUrl += '&x-cos-security-token=' + AuthData.XCosSecurityToken); + AuthData.ClientIP && (signUrl += '&clientIP=' + AuthData.ClientIP); + AuthData.ClientUA && (signUrl += '&clientUA=' + AuthData.ClientUA); + AuthData.Token && (signUrl += '&token=' + AuthData.Token); + queryParamsStr && (signUrl += '&' + queryParamsStr); + setTimeout(function () { + callback(null, {Url: signUrl}); + }); + }); + + if (AuthData) { + syncUrl += '?' + AuthData.Authorization + + (AuthData.XCosSecurityToken ? '&x-cos-security-token=' + AuthData.XCosSecurityToken : ''); + queryParamsStr && (syncUrl += '&' + queryParamsStr); + } else { + queryParamsStr && (syncUrl += '?' + queryParamsStr); + } + return syncUrl; +} + + +/** + * 私有方法 + */ +function decodeAcl(AccessControlPolicy) { + var result = { + GrantFullControl: [], + GrantWrite: [], + GrantRead: [], + GrantReadAcp: [], + GrantWriteAcp: [], + ACL: '', + }; + var GrantMap = { + 'FULL_CONTROL': 'GrantFullControl', + 'WRITE': 'GrantWrite', + 'READ': 'GrantRead', + 'READ_ACP': 'GrantReadAcp', + 'WRITE_ACP': 'GrantWriteAcp', + }; + var AccessControlList = AccessControlPolicy && AccessControlPolicy.AccessControlList || {}; + var Grant = AccessControlList.Grant; + if (Grant) { + Grant = util.isArray(Grant) ? Grant : [Grant]; + } + var PublicAcl = {READ: 0, WRITE: 0, FULL_CONTROL: 0}; + Grant && Grant.length && util.each(Grant, function (item) { + if (item.Grantee.ID === 'qcs::cam::anyone:anyone' || item.Grantee.URI === 'http://cam.qcloud.com/groups/global/AllUsers') { + PublicAcl[item.Permission] = 1; + } else if (item.Grantee.ID !== AccessControlPolicy.Owner.ID) { + result[GrantMap[item.Permission]].push('id="' + item.Grantee.ID + '"'); + } + }); + if (PublicAcl.FULL_CONTROL || (PublicAcl.WRITE && PublicAcl.READ)) { + result.ACL = 'public-read-write'; + } else if (PublicAcl.READ) { + result.ACL = 'public-read'; + } else { + result.ACL = 'private'; + } + util.each(GrantMap, function (item) { + result[item] = uniqGrant(result[item].join(',')); + }); + return result; +} + +// Grant 去重 +function uniqGrant(str) { + var arr = str.split(','); + var exist = {}; + var i, item; + for (i = 0; i < arr.length; ) { + item = arr[i].trim(); + if (exist[item]) { + arr.splice(i, 1); + } else { + exist[item] = true; + arr[i] = item; + i++; + } + } + return arr.join(','); +} + +// 生成操作 url +function getUrl(params) { + var longBucket = params.bucket; + var shortBucket = longBucket.substr(0, longBucket.lastIndexOf('-')); + var appId = longBucket.substr(longBucket.lastIndexOf('-') + 1); + var domain = params.domain; + var region = params.region; + var object = params.object; + var protocol = 'https:'; + if (!domain) { + if (['cn-south', 'cn-south-2', 'cn-north', 'cn-east', 'cn-southwest', 'sg'].indexOf(region) > -1) { + domain = '{Region}.myqcloud.com'; + } else { + domain = 'cos.{Region}.myqcloud.com'; + } + if (!params.ForcePathStyle) { + domain = '{Bucket}.' + domain; + } + } + domain = domain.replace(/\{\{AppId\}\}/ig, appId) + .replace(/\{\{Bucket\}\}/ig, shortBucket) + .replace(/\{\{Region\}\}/ig, region) + .replace(/\{\{.*?\}\}/ig, ''); + domain = domain.replace(/\{AppId\}/ig, appId) + .replace(/\{BucketName\}/ig, shortBucket) + .replace(/\{Bucket\}/ig, longBucket) + .replace(/\{Region\}/ig, region) + .replace(/\{.*?\}/ig, ''); + if (!/^[a-zA-Z]+:\/\//.test(domain)) { + domain = protocol + '//' + domain; + } + + // 去掉域名最后的斜杆 + if (domain.slice(-1) === '/') { + domain = domain.slice(0, -1); + } + var url = domain; + + if (params.ForcePathStyle) { + url += '/' + longBucket; + } + url += '/'; + if (object) { + url += util.camSafeUrlEncode(object).replace(/%2F/g, '/'); + } + + if (params.isLocation) { + url = url.replace(/^https?:\/\//, ''); + } + return url; +} + +// 异步获取签名 +function getAuthorizationAsync(params, callback) { + + var headers = util.clone(params.Headers); + delete headers['Content-Type']; + delete headers['Cache-Control']; + util.each(headers, function (v, k) { + v === '' && delete headers[k]; + }); + + var cb = function (AuthData) { + + // 检查签名格式 + var formatAllow = false; + var auth = AuthData.Authorization; + if (auth) { + if (auth.indexOf(' ') > -1) { + formatAllow = false; + } else if (auth.indexOf('q-sign-algorithm=') > -1 && + auth.indexOf('q-ak=') > -1 && + auth.indexOf('q-sign-time=') > -1 && + auth.indexOf('q-key-time=') > -1 && + auth.indexOf('q-url-param-list=') > -1) { + formatAllow = true; + } else { + try { + auth = base64.atob(auth); + if (auth.indexOf('a=') > -1 && + auth.indexOf('k=') > -1 && + auth.indexOf('t=') > -1 && + auth.indexOf('r=') > -1 && + auth.indexOf('b=') > -1) { + formatAllow = true; + } + } catch (e) {} + } + } + if (formatAllow) { + callback && callback(null, AuthData); + } else { + callback && callback('authorization error'); + } + }; + + var self = this; + var Bucket = params.Bucket || ''; + var Region = params.Region || ''; + + // PathName + var KeyName = params.Action === 'name/cos:PostObject' || !params.Key ? '' : params.Key; + if (self.options.ForcePathStyle && Bucket) { + KeyName = Bucket + '/' + KeyName; + } + var Pathname = '/' + KeyName; + + // Action、ResourceKey + var StsData = {}; + var Scope = params.Scope; + if (!Scope) { + var Action = params.Action || ''; + var ResourceKey = params.ResourceKey || params.Key || ''; + Scope = params.Scope || [{ + action: Action, + bucket: Bucket, + region: Region, + prefix: ResourceKey, + }]; + } + var ScopeKey = util.md5(JSON.stringify(Scope)); + + // STS + self._StsCache = self._StsCache ||[]; + (function () { + var i, AuthData; + for (i = self._StsCache.length - 1; i >= 0; i--) { + AuthData = self._StsCache[i]; + var compareTime = Math.round(util.getSkewTime(self.options.SystemClockOffset) / 1000) + 30; + if (AuthData.StartTime && compareTime < AuthData.StartTime || compareTime >= AuthData.ExpiredTime) { + self._StsCache.splice(i, 1); + continue; + } + if (!AuthData.ScopeLimit || AuthData.ScopeLimit && AuthData.ScopeKey === ScopeKey) { + StsData = AuthData; + break; + } + } + })(); + + var calcAuthByTmpKey = function () { + var KeyTime = StsData.StartTime && StsData.ExpiredTime ? StsData.StartTime + ';' + StsData.ExpiredTime : ''; + var Authorization = util.getAuth({ + SecretId: StsData.TmpSecretId, + SecretKey: StsData.TmpSecretKey, + Method: params.Method, + Pathname: Pathname, + Query: params.Query, + Headers: headers, + Expires: params.Expires, + SystemClockOffset: self.options.SystemClockOffset, + KeyTime: KeyTime + }); + var AuthData = { + Authorization: Authorization, + XCosSecurityToken: StsData.XCosSecurityToken || '', + Token: StsData.Token || '', + ClientIP: StsData.ClientIP || '', + ClientUA: StsData.ClientUA || '', + }; + cb(AuthData); + }; + + // 先判断是否有临时密钥 + if (StsData.ExpiredTime && StsData.ExpiredTime - (util.getSkewTime(self.options.SystemClockOffset) / 1000) > 60) { // 如果缓存的临时密钥有效,并还有超过60秒有效期就直接使用 + calcAuthByTmpKey(); + } else if (self.options.getAuthorization) { // 外部计算签名或获取临时密钥 + self.options.getAuthorization.call(self, { + Bucket: Bucket, + Region: Region, + Method: params.Method, + Key: KeyName, + Pathname: Pathname, + Query: params.Query, + Headers: headers, + Scope: Scope, + SystemClockOffset: self.options.SystemClockOffset, + }, function (AuthData) { + if (typeof AuthData === 'string') { + AuthData = {Authorization: AuthData}; + } + if (AuthData.TmpSecretId && + AuthData.TmpSecretKey && + AuthData.XCosSecurityToken && + AuthData.ExpiredTime) { + StsData = AuthData || {}; + StsData.Scope = Scope; + StsData.ScopeKey = ScopeKey; + self._StsCache.push(StsData); + calcAuthByTmpKey(); + } else { + cb(AuthData); + } + }); + } else if (self.options.getSTS) { // 外部获取临时密钥 + self.options.getSTS.call(self, { + Bucket: Bucket, + Region: Region, + }, function (data) { + StsData = data || {}; + StsData.Scope = Scope; + StsData.ScopeKey = ScopeKey; + StsData.TmpSecretId = StsData.SecretId; + StsData.TmpSecretKey = StsData.SecretKey; + self._StsCache.push(StsData); + calcAuthByTmpKey(); + }); + } else { // 内部计算获取签名 + return (function () { + var Authorization = util.getAuth({ + SecretId: params.SecretId || self.options.SecretId, + SecretKey: params.SecretKey || self.options.SecretKey, + Method: params.Method, + Pathname: Pathname, + Query: params.Query, + Headers: headers, + Expires: params.Expires, + SystemClockOffset: self.options.SystemClockOffset, + }); + var AuthData = { + Authorization: Authorization, + XCosSecurityToken: self.options.XCosSecurityToken, + }; + cb(AuthData); + return AuthData; + })(); + } + return ''; +} + +// 调整时间偏差 +function allowRetry(err) { + var allowRetry = false; + var isTimeError = false; + var serverDate = (err.headers && (err.headers.date || err.headers.Date)) || (err.error && err.error.ServerTime); + try { + var errorCode = err.error.Code; + var errorMessage = err.error.Message; + if (errorCode === 'RequestTimeTooSkewed' || + (errorCode === 'AccessDenied' && errorMessage === 'Request has expired')) { + isTimeError = true; + } + } catch (e) { + } + if (err) { + if (isTimeError && serverDate) { + var serverTime = Date.parse(serverDate); + if (this.options.CorrectClockSkew && Math.abs(util.getSkewTime(this.options.SystemClockOffset) - serverTime) >= 30000) { + console.error('error: Local time is too skewed.'); + this.options.SystemClockOffset = serverTime - Date.now(); + allowRetry = true; + } + } else if (Math.floor(err.statusCode / 100) === 5) { + allowRetry = true; + } + } + return allowRetry; +} + +// 获取签名并发起请求 +function submitRequest(params, callback) { + var self = this; + + // 处理 headers + !params.headers && (params.headers = {}); + + // 处理 query + !params.qs && (params.qs = {}); + params.VersionId && (params.qs.versionId = params.VersionId); + params.qs = util.clearKey(params.qs); + + // 清理 undefined 和 null 字段 + params.headers && (params.headers = util.clearKey(params.headers)); + params.qs && (params.qs = util.clearKey(params.qs)); + + var Query = util.clone(params.qs); + params.action && (Query[params.action] = ''); + + var next = function (tryTimes) { + var oldClockOffset = self.options.SystemClockOffset; + getAuthorizationAsync.call(self, { + Bucket: params.Bucket || '', + Region: params.Region || '', + Method: params.method, + Key: params.Key, + Query: Query, + Headers: params.headers, + Action: params.Action, + ResourceKey: params.ResourceKey, + Scope: params.Scope, + }, function (err, AuthData) { + if (err) { + callback(err); + return; + } + params.AuthData = AuthData; + _submitRequest.call(self, params, function (err, data) { + if (err && tryTimes < 2 && (oldClockOffset !== self.options.SystemClockOffset || allowRetry.call(self, err))) { + if (params.headers) { + delete params.headers.Authorization; + delete params.headers['token']; + delete params.headers['clientIP']; + delete params.headers['clientUA']; + delete params.headers['x-cos-security-token']; + } + next(tryTimes + 1); + } else { + callback(err, data); + } + }); + }); + }; + next(1); + +} + +// 发起请求 +function _submitRequest(params, callback) { + var self = this; + var TaskId = params.TaskId; + if (TaskId && !self._isRunningTask(TaskId)) return; + + var bucket = params.Bucket; + var region = params.Region; + var object = params.Key; + var method = params.method || 'GET'; + var url = params.url; + var body = params.body; + var json = params.json; + var rawBody = params.rawBody; + + // url + if (self.options.UseAccelerate) { + region = 'accelerate'; + } + url = url || getUrl({ + ForcePathStyle: self.options.ForcePathStyle, + protocol: self.options.Protocol, + domain: self.options.Domain, + bucket: bucket, + region: region, + object: object, + }); + if (params.action) { + url = url + '?' + params.action; + } + if (params.qsStr) { + if(url.indexOf('?') > -1){ + url = url + '&' + params.qsStr; + }else{ + url = url + '?' + params.qsStr; + } + } + + var opt = { + method: method, + url: url, + headers: params.headers, + qs: params.qs, + filePath: params.filePath, + body: body, + json: json, + }; + + // 获取签名 + opt.headers.Authorization = params.AuthData.Authorization; + params.AuthData.Token && (opt.headers['token'] = params.AuthData.Token); + params.AuthData.ClientIP && (opt.headers['clientIP'] = params.AuthData.ClientIP); + params.AuthData.ClientUA && (opt.headers['clientUA'] = params.AuthData.ClientUA); + params.AuthData.XCosSecurityToken && (opt.headers['x-cos-security-token'] = params.AuthData.XCosSecurityToken); + + // 清理 undefined 和 null 字段 + opt.headers && (opt.headers = util.clearKey(opt.headers)); + opt = util.clearKey(opt); + + // progress + if (params.onProgress && typeof params.onProgress === 'function') { + opt.onProgress = function (e) { + if (TaskId && !self._isRunningTask(TaskId)) return; + var loaded = e ? e.loaded : 0; + params.onProgress({loaded: loaded, total: e.total}); + }; + } + if (this.options.Timeout) { + opt.timeout = this.options.Timeout; + } + + self.options.ForcePathStyle && (opt.pathStyle = self.options.ForcePathStyle); + self.emit('before-send', opt); + var sender = REQUEST(opt, function (err, response, body) { + if (err === 'abort') return; + + // 返回内容添加 状态码 和 headers + var hasReturned; + var cb = function (err, data) { + TaskId && self.off('inner-kill-task', killTask); + if (hasReturned) return; + hasReturned = true; + var attrs = {}; + response && response.statusCode && (attrs.statusCode = response.statusCode); + response && response.headers && (attrs.headers = response.headers); + + if (err) { + err = util.extend(err || {}, attrs); + callback(err, null); + } else { + data = util.extend(data || {}, attrs); + callback(null, data); + } + sender = null; + }; + + // 请求错误,发生网络错误 + if (err) { + cb({error: err}); + return; + } + + // 不对 body 进行转换,body 直接挂载返回 + var jsonRes; + if (rawBody) { + jsonRes = {}; + jsonRes.body = body; + } else { + try { + jsonRes = body && body.indexOf('<') > -1 && body.indexOf('>') > -1 && util.xml2json(body) || {}; + } catch (e) { + jsonRes = body || {}; + } + } + + // 请求返回码不为 200 + var statusCode = response.statusCode; + var statusSuccess = Math.floor(statusCode / 100) === 2; // 200 202 204 206 + if (!statusSuccess) { + cb({error: jsonRes.Error || jsonRes}); + return; + } + + if (jsonRes.Error) { + cb({error: jsonRes.Error}); + return; + } + cb(null, jsonRes); + }); + + // kill task + var killTask = function (data) { + if (data.TaskId === TaskId) { + sender && sender.abort && sender.abort(); + self.off('inner-kill-task', killTask); + } + }; + TaskId && self.on('inner-kill-task', killTask); + +} + + +var API_MAP = { + // Bucket 相关方法 + getService: getService, // Bucket + putBucket: putBucket, + headBucket: headBucket, // Bucket + getBucket: getBucket, + deleteBucket: deleteBucket, + putBucketAcl: putBucketAcl, // BucketACL + getBucketAcl: getBucketAcl, + putBucketCors: putBucketCors, // BucketCors + getBucketCors: getBucketCors, + deleteBucketCors: deleteBucketCors, + getBucketLocation: getBucketLocation, // BucketLocation + getBucketPolicy: getBucketPolicy, // BucketPolicy + putBucketPolicy: putBucketPolicy, + deleteBucketPolicy: deleteBucketPolicy, + putBucketTagging: putBucketTagging, // BucketTagging + getBucketTagging: getBucketTagging, + deleteBucketTagging: deleteBucketTagging, + putBucketLifecycle: putBucketLifecycle, // BucketLifecycle + getBucketLifecycle: getBucketLifecycle, + deleteBucketLifecycle: deleteBucketLifecycle, + putBucketVersioning: putBucketVersioning, // BucketVersioning + getBucketVersioning: getBucketVersioning, + putBucketReplication: putBucketReplication, // BucketReplication + getBucketReplication: getBucketReplication, + deleteBucketReplication: deleteBucketReplication, + putBucketWebsite: putBucketWebsite, // BucketWebsite + getBucketWebsite: getBucketWebsite, + deleteBucketWebsite: deleteBucketWebsite, + putBucketReferer: putBucketReferer, // BucketReferer + getBucketReferer: getBucketReferer, + putBucketDomain: putBucketDomain, // BucketDomain + getBucketDomain: getBucketDomain, + deleteBucketDomain: deleteBucketDomain, + putBucketOrigin: putBucketOrigin, // BucketOrigin + getBucketOrigin: getBucketOrigin, + deleteBucketOrigin: deleteBucketOrigin, + putBucketLogging: putBucketLogging, // BucketLogging + getBucketLogging: getBucketLogging, + putBucketInventory: putBucketInventory, // BucketInventory + getBucketInventory: getBucketInventory, + listBucketInventory: listBucketInventory, + deleteBucketInventory: deleteBucketInventory, + putBucketAccelerate: putBucketAccelerate, + getBucketAccelerate: getBucketAccelerate, + + // Object 相关方法 + getObject: getObject, + headObject: headObject, + listObjectVersions: listObjectVersions, + putObject: putObject, + postObject: postObject, + deleteObject: deleteObject, + getObjectAcl: getObjectAcl, + putObjectAcl: putObjectAcl, + optionsObject: optionsObject, + putObjectCopy: putObjectCopy, + deleteMultipleObject: deleteMultipleObject, + restoreObject: restoreObject, + putObjectTagging: putObjectTagging, + getObjectTagging: getObjectTagging, + deleteObjectTagging: deleteObjectTagging, + + // 分块上传相关方法 + uploadPartCopy: uploadPartCopy, + multipartInit: multipartInit, + multipartUpload: multipartUpload, + multipartComplete: multipartComplete, + multipartList: multipartList, + multipartListPart: multipartListPart, + multipartAbort: multipartAbort, + + // 工具方法 + request: request, + getObjectUrl: getObjectUrl, + getAuth: getAuth, +}; + +module.exports.init = function (COS, task) { + task.transferToTaskMethod(API_MAP, 'postObject'); + task.transferToTaskMethod(API_MAP, 'putObject'); + util.each(API_MAP, function (fn, apiName) { + COS.prototype[apiName] = util.apiWrapper(apiName, fn); + }); +}; /***/ }), /* 18 */ /***/ (function(module, exports) { -var obj2str = function (obj) { - var i, key, val; - var list = []; - var keyList = Object.keys(obj); - for (i = 0; i < keyList.length; i++) { - key = keyList[i]; - val = obj[key] || ''; - list.push(key + '=' + encodeURIComponent(val)); - } - return list.join('&'); -}; - -var request = function (params, callback) { - var filePath = params.filePath; - var headers = params.headers || {}; - var url = params.url; - var method = params.method; - var onProgress = params.onProgress; - var requestTask; - - var cb = function (err, response) { - var H = response.header - var headers = {}; - if (H) for (var key in H) { - if (H.hasOwnProperty(key)) headers[key.toLowerCase()] = H[key]; - } - callback(err, {statusCode: response.statusCode, headers: headers}, response.data); - }; - - if (filePath) { - var fileKey; - var m = url.match(/^(https?:\/\/[^/]+\/)([^/]*\/?)(.*)$/); - if (params.pathStyle) { - fileKey = decodeURIComponent(m[3] || ''); - url = m[1] + m[2]; - } else { - fileKey = decodeURIComponent(m[2] + m[3] || ''); - url = m[1]; - } - - // 整理 postObject 参数 - var formData = { - 'key': fileKey, - 'success_action_status': 200, - 'Signature': headers.Authorization, - }; - var headerKeys = [ - 'Cache-Control', - 'Content-Type', - 'Content-Disposition', - 'Content-Encoding', - 'Expires', - 'x-cos-storage-class', - 'x-cos-security-token', - ]; - for (var i in params.headers) { - if (params.headers.hasOwnProperty(i) && (i.indexOf('x-cos-meta-') > -1 || headerKeys.indexOf(i) > -1)) { - formData[i] = params.headers[i]; - } - } - headers['x-cos-acl'] && (formData.acl = headers['x-cos-acl']); - !formData['Content-Type'] && (formData['Content-Type'] = ''); - - requestTask = wx.uploadFile({ - url: url, - method: method, - name: 'file', - header: headers, - filePath: filePath, - formData: formData, - timeout: params.timeout, - success: function (response) { - cb(null, response); - }, - fail: function (response) { - cb(response.errMsg, response); - } - }); - requestTask.onProgressUpdate(function (res) { - onProgress && onProgress({ - loaded: res.totalBytesSent, - total: res.totalBytesExpectedToSend, - progress: res.progress / 100 - }); - }); - } else { - var qsStr = params.qs && obj2str(params.qs) || ''; - if (qsStr) { - url += (url.indexOf('?') > -1 ? '&' : '?') + qsStr; - } - headers['Content-Length'] && (delete headers['Content-Length']); - requestTask = wx.request({ - url: url, - method: method, - header: headers, - dataType: 'text', - data: params.body, - timeout: params.timeout, - success: function (response) { - cb(null, response); - }, - fail: function (response) { - cb(response.errMsg, response); - } - }); - } - - return requestTask; -}; - -module.exports = request; +var obj2str = function (obj) { + var i, key, val; + var list = []; + var keyList = Object.keys(obj); + for (i = 0; i < keyList.length; i++) { + key = keyList[i]; + val = obj[key] || ''; + list.push(key + '=' + encodeURIComponent(val)); + } + return list.join('&'); +}; + +var request = function (params, callback) { + var filePath = params.filePath; + var headers = params.headers || {}; + var url = params.url; + var method = params.method; + var onProgress = params.onProgress; + var requestTask; + + var cb = function (err, response) { + var H = response.header + var headers = {}; + if (H) for (var key in H) { + if (H.hasOwnProperty(key)) headers[key.toLowerCase()] = H[key]; + } + callback(err, {statusCode: response.statusCode, headers: headers}, response.data); + }; + + if (filePath) { + var fileKey; + var m = url.match(/^(https?:\/\/[^/]+\/)([^/]*\/?)(.*)$/); + if (params.pathStyle) { + fileKey = decodeURIComponent(m[3] || ''); + url = m[1] + m[2]; + } else { + fileKey = decodeURIComponent(m[2] + m[3] || ''); + url = m[1]; + } + + // 整理 postObject 参数 + var formData = { + 'key': fileKey, + 'success_action_status': 200, + 'Signature': headers.Authorization, + }; + var headerKeys = [ + 'Cache-Control', + 'Content-Type', + 'Content-Disposition', + 'Content-Encoding', + 'Expires', + 'x-cos-storage-class', + 'x-cos-security-token', + ]; + for (var i in params.headers) { + if (params.headers.hasOwnProperty(i) && (i.indexOf('x-cos-meta-') > -1 || headerKeys.indexOf(i) > -1)) { + formData[i] = params.headers[i]; + } + } + headers['x-cos-acl'] && (formData.acl = headers['x-cos-acl']); + !formData['Content-Type'] && (formData['Content-Type'] = ''); + + requestTask = wx.uploadFile({ + url: url, + method: method, + name: 'file', + header: headers, + filePath: filePath, + formData: formData, + timeout: params.timeout, + success: function (response) { + cb(null, response); + }, + fail: function (response) { + cb(response.errMsg, response); + } + }); + requestTask.onProgressUpdate(function (res) { + onProgress && onProgress({ + loaded: res.totalBytesSent, + total: res.totalBytesExpectedToSend, + progress: res.progress / 100 + }); + }); + } else { + var qsStr = params.qs && obj2str(params.qs) || ''; + if (qsStr) { + url += (url.indexOf('?') > -1 ? '&' : '?') + qsStr; + } + headers['Content-Length'] && (delete headers['Content-Length']); + requestTask = wx.request({ + url: url, + method: method, + header: headers, + dataType: 'text', + data: params.body, + timeout: params.timeout, + success: function (response) { + cb(null, response); + }, + fail: function (response) { + cb(response.errMsg, response); + } + }); + } + + return requestTask; +}; + +module.exports = request; + + +/***/ }), +/* 19 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +let Mime = __webpack_require__(20); +module.exports = new Mime(__webpack_require__(21), __webpack_require__(22)); + + +/***/ }), +/* 20 */ +/***/ (function(module, exports, __webpack_require__) { + +"use strict"; + + +/** + * @param typeMap [Object] Map of MIME type -> Array[extensions] + * @param ... + */ +function Mime() { + this._types = Object.create(null); + this._extensions = Object.create(null); + + for (let i = 0; i < arguments.length; i++) { + this.define(arguments[i]); + } + + this.define = this.define.bind(this); + this.getType = this.getType.bind(this); + this.getExtension = this.getExtension.bind(this); +} + +/** + * Define mimetype -> extension mappings. Each key is a mime-type that maps + * to an array of extensions associated with the type. The first extension is + * used as the default extension for the type. + * + * e.g. mime.define({'audio/ogg', ['oga', 'ogg', 'spx']}); + * + * If a type declares an extension that has already been defined, an error will + * be thrown. To suppress this error and force the extension to be associated + * with the new type, pass `force`=true. Alternatively, you may prefix the + * extension with "*" to map the type to extension, without mapping the + * extension to the type. + * + * e.g. mime.define({'audio/wav', ['wav']}, {'audio/x-wav', ['*wav']}); + * + * + * @param map (Object) type definitions + * @param force (Boolean) if true, force overriding of existing definitions + */ +Mime.prototype.define = function(typeMap, force) { + for (let type in typeMap) { + let extensions = typeMap[type].map(function(t) { + return t.toLowerCase(); + }); + type = type.toLowerCase(); + + for (let i = 0; i < extensions.length; i++) { + const ext = extensions[i]; + + // '*' prefix = not the preferred type for this extension. So fixup the + // extension, and skip it. + if (ext[0] === '*') { + continue; + } + + if (!force && (ext in this._types)) { + throw new Error( + 'Attempt to change mapping for "' + ext + + '" extension from "' + this._types[ext] + '" to "' + type + + '". Pass `force=true` to allow this, otherwise remove "' + ext + + '" from the list of extensions for "' + type + '".' + ); + } + + this._types[ext] = type; + } + + // Use first extension as default + if (force || !this._extensions[type]) { + const ext = extensions[0]; + this._extensions[type] = (ext[0] !== '*') ? ext : ext.substr(1); + } + } +}; + +/** + * Lookup a mime type based on extension + */ +Mime.prototype.getType = function(path) { + path = String(path); + let last = path.replace(/^.*[/\\]/, '').toLowerCase(); + let ext = last.replace(/^.*\./, '').toLowerCase(); + + let hasPath = last.length < path.length; + let hasDot = ext.length < last.length - 1; + + return (hasDot || !hasPath) && this._types[ext] || null; +}; + +/** + * Return file extension associated with a mime type + */ +Mime.prototype.getExtension = function(type) { + type = /^\s*([^;\s]*)/.test(type) && RegExp.$1; + return type && this._extensions[type.toLowerCase()] || null; +}; + +module.exports = Mime; + + +/***/ }), +/* 21 */ +/***/ (function(module, exports) { + +module.exports = {"application/andrew-inset":["ez"],"application/applixware":["aw"],"application/atom+xml":["atom"],"application/atomcat+xml":["atomcat"],"application/atomdeleted+xml":["atomdeleted"],"application/atomsvc+xml":["atomsvc"],"application/atsc-dwd+xml":["dwd"],"application/atsc-held+xml":["held"],"application/atsc-rsat+xml":["rsat"],"application/bdoc":["bdoc"],"application/calendar+xml":["xcs"],"application/ccxml+xml":["ccxml"],"application/cdfx+xml":["cdfx"],"application/cdmi-capability":["cdmia"],"application/cdmi-container":["cdmic"],"application/cdmi-domain":["cdmid"],"application/cdmi-object":["cdmio"],"application/cdmi-queue":["cdmiq"],"application/cu-seeme":["cu"],"application/dash+xml":["mpd"],"application/davmount+xml":["davmount"],"application/docbook+xml":["dbk"],"application/dssc+der":["dssc"],"application/dssc+xml":["xdssc"],"application/ecmascript":["ecma","es"],"application/emma+xml":["emma"],"application/emotionml+xml":["emotionml"],"application/epub+zip":["epub"],"application/exi":["exi"],"application/fdt+xml":["fdt"],"application/font-tdpfr":["pfr"],"application/geo+json":["geojson"],"application/gml+xml":["gml"],"application/gpx+xml":["gpx"],"application/gxf":["gxf"],"application/gzip":["gz"],"application/hjson":["hjson"],"application/hyperstudio":["stk"],"application/inkml+xml":["ink","inkml"],"application/ipfix":["ipfix"],"application/its+xml":["its"],"application/java-archive":["jar","war","ear"],"application/java-serialized-object":["ser"],"application/java-vm":["class"],"application/javascript":["js","mjs"],"application/json":["json","map"],"application/json5":["json5"],"application/jsonml+json":["jsonml"],"application/ld+json":["jsonld"],"application/lgr+xml":["lgr"],"application/lost+xml":["lostxml"],"application/mac-binhex40":["hqx"],"application/mac-compactpro":["cpt"],"application/mads+xml":["mads"],"application/manifest+json":["webmanifest"],"application/marc":["mrc"],"application/marcxml+xml":["mrcx"],"application/mathematica":["ma","nb","mb"],"application/mathml+xml":["mathml"],"application/mbox":["mbox"],"application/mediaservercontrol+xml":["mscml"],"application/metalink+xml":["metalink"],"application/metalink4+xml":["meta4"],"application/mets+xml":["mets"],"application/mmt-aei+xml":["maei"],"application/mmt-usd+xml":["musd"],"application/mods+xml":["mods"],"application/mp21":["m21","mp21"],"application/mp4":["mp4s","m4p"],"application/mrb-consumer+xml":["*xdf"],"application/mrb-publish+xml":["*xdf"],"application/msword":["doc","dot"],"application/mxf":["mxf"],"application/n-quads":["nq"],"application/n-triples":["nt"],"application/node":["cjs"],"application/octet-stream":["bin","dms","lrf","mar","so","dist","distz","pkg","bpk","dump","elc","deploy","exe","dll","deb","dmg","iso","img","msi","msp","msm","buffer"],"application/oda":["oda"],"application/oebps-package+xml":["opf"],"application/ogg":["ogx"],"application/omdoc+xml":["omdoc"],"application/onenote":["onetoc","onetoc2","onetmp","onepkg"],"application/oxps":["oxps"],"application/p2p-overlay+xml":["relo"],"application/patch-ops-error+xml":["*xer"],"application/pdf":["pdf"],"application/pgp-encrypted":["pgp"],"application/pgp-signature":["asc","sig"],"application/pics-rules":["prf"],"application/pkcs10":["p10"],"application/pkcs7-mime":["p7m","p7c"],"application/pkcs7-signature":["p7s"],"application/pkcs8":["p8"],"application/pkix-attr-cert":["ac"],"application/pkix-cert":["cer"],"application/pkix-crl":["crl"],"application/pkix-pkipath":["pkipath"],"application/pkixcmp":["pki"],"application/pls+xml":["pls"],"application/postscript":["ai","eps","ps"],"application/provenance+xml":["provx"],"application/pskc+xml":["pskcxml"],"application/raml+yaml":["raml"],"application/rdf+xml":["rdf","owl"],"application/reginfo+xml":["rif"],"application/relax-ng-compact-syntax":["rnc"],"application/resource-lists+xml":["rl"],"application/resource-lists-diff+xml":["rld"],"application/rls-services+xml":["rs"],"application/route-apd+xml":["rapd"],"application/route-s-tsid+xml":["sls"],"application/route-usd+xml":["rusd"],"application/rpki-ghostbusters":["gbr"],"application/rpki-manifest":["mft"],"application/rpki-roa":["roa"],"application/rsd+xml":["rsd"],"application/rss+xml":["rss"],"application/rtf":["rtf"],"application/sbml+xml":["sbml"],"application/scvp-cv-request":["scq"],"application/scvp-cv-response":["scs"],"application/scvp-vp-request":["spq"],"application/scvp-vp-response":["spp"],"application/sdp":["sdp"],"application/senml+xml":["senmlx"],"application/sensml+xml":["sensmlx"],"application/set-payment-initiation":["setpay"],"application/set-registration-initiation":["setreg"],"application/shf+xml":["shf"],"application/sieve":["siv","sieve"],"application/smil+xml":["smi","smil"],"application/sparql-query":["rq"],"application/sparql-results+xml":["srx"],"application/srgs":["gram"],"application/srgs+xml":["grxml"],"application/sru+xml":["sru"],"application/ssdl+xml":["ssdl"],"application/ssml+xml":["ssml"],"application/swid+xml":["swidtag"],"application/tei+xml":["tei","teicorpus"],"application/thraud+xml":["tfi"],"application/timestamped-data":["tsd"],"application/toml":["toml"],"application/ttml+xml":["ttml"],"application/ubjson":["ubj"],"application/urc-ressheet+xml":["rsheet"],"application/urc-targetdesc+xml":["td"],"application/voicexml+xml":["vxml"],"application/wasm":["wasm"],"application/widget":["wgt"],"application/winhlp":["hlp"],"application/wsdl+xml":["wsdl"],"application/wspolicy+xml":["wspolicy"],"application/xaml+xml":["xaml"],"application/xcap-att+xml":["xav"],"application/xcap-caps+xml":["xca"],"application/xcap-diff+xml":["xdf"],"application/xcap-el+xml":["xel"],"application/xcap-error+xml":["xer"],"application/xcap-ns+xml":["xns"],"application/xenc+xml":["xenc"],"application/xhtml+xml":["xhtml","xht"],"application/xliff+xml":["xlf"],"application/xml":["xml","xsl","xsd","rng"],"application/xml-dtd":["dtd"],"application/xop+xml":["xop"],"application/xproc+xml":["xpl"],"application/xslt+xml":["*xsl","xslt"],"application/xspf+xml":["xspf"],"application/xv+xml":["mxml","xhvml","xvml","xvm"],"application/yang":["yang"],"application/yin+xml":["yin"],"application/zip":["zip"],"audio/3gpp":["*3gpp"],"audio/adpcm":["adp"],"audio/amr":["amr"],"audio/basic":["au","snd"],"audio/midi":["mid","midi","kar","rmi"],"audio/mobile-xmf":["mxmf"],"audio/mp3":["*mp3"],"audio/mp4":["m4a","mp4a"],"audio/mpeg":["mpga","mp2","mp2a","mp3","m2a","m3a"],"audio/ogg":["oga","ogg","spx","opus"],"audio/s3m":["s3m"],"audio/silk":["sil"],"audio/wav":["wav"],"audio/wave":["*wav"],"audio/webm":["weba"],"audio/xm":["xm"],"font/collection":["ttc"],"font/otf":["otf"],"font/ttf":["ttf"],"font/woff":["woff"],"font/woff2":["woff2"],"image/aces":["exr"],"image/apng":["apng"],"image/avif":["avif"],"image/bmp":["bmp"],"image/cgm":["cgm"],"image/dicom-rle":["drle"],"image/emf":["emf"],"image/fits":["fits"],"image/g3fax":["g3"],"image/gif":["gif"],"image/heic":["heic"],"image/heic-sequence":["heics"],"image/heif":["heif"],"image/heif-sequence":["heifs"],"image/hej2k":["hej2"],"image/hsj2":["hsj2"],"image/ief":["ief"],"image/jls":["jls"],"image/jp2":["jp2","jpg2"],"image/jpeg":["jpeg","jpg","jpe"],"image/jph":["jph"],"image/jphc":["jhc"],"image/jpm":["jpm"],"image/jpx":["jpx","jpf"],"image/jxr":["jxr"],"image/jxra":["jxra"],"image/jxrs":["jxrs"],"image/jxs":["jxs"],"image/jxsc":["jxsc"],"image/jxsi":["jxsi"],"image/jxss":["jxss"],"image/ktx":["ktx"],"image/ktx2":["ktx2"],"image/png":["png"],"image/sgi":["sgi"],"image/svg+xml":["svg","svgz"],"image/t38":["t38"],"image/tiff":["tif","tiff"],"image/tiff-fx":["tfx"],"image/webp":["webp"],"image/wmf":["wmf"],"message/disposition-notification":["disposition-notification"],"message/global":["u8msg"],"message/global-delivery-status":["u8dsn"],"message/global-disposition-notification":["u8mdn"],"message/global-headers":["u8hdr"],"message/rfc822":["eml","mime"],"model/3mf":["3mf"],"model/gltf+json":["gltf"],"model/gltf-binary":["glb"],"model/iges":["igs","iges"],"model/mesh":["msh","mesh","silo"],"model/mtl":["mtl"],"model/obj":["obj"],"model/stl":["stl"],"model/vrml":["wrl","vrml"],"model/x3d+binary":["*x3db","x3dbz"],"model/x3d+fastinfoset":["x3db"],"model/x3d+vrml":["*x3dv","x3dvz"],"model/x3d+xml":["x3d","x3dz"],"model/x3d-vrml":["x3dv"],"text/cache-manifest":["appcache","manifest"],"text/calendar":["ics","ifb"],"text/coffeescript":["coffee","litcoffee"],"text/css":["css"],"text/csv":["csv"],"text/html":["html","htm","shtml"],"text/jade":["jade"],"text/jsx":["jsx"],"text/less":["less"],"text/markdown":["markdown","md"],"text/mathml":["mml"],"text/mdx":["mdx"],"text/n3":["n3"],"text/plain":["txt","text","conf","def","list","log","in","ini"],"text/richtext":["rtx"],"text/rtf":["*rtf"],"text/sgml":["sgml","sgm"],"text/shex":["shex"],"text/slim":["slim","slm"],"text/spdx":["spdx"],"text/stylus":["stylus","styl"],"text/tab-separated-values":["tsv"],"text/troff":["t","tr","roff","man","me","ms"],"text/turtle":["ttl"],"text/uri-list":["uri","uris","urls"],"text/vcard":["vcard"],"text/vtt":["vtt"],"text/xml":["*xml"],"text/yaml":["yaml","yml"],"video/3gpp":["3gp","3gpp"],"video/3gpp2":["3g2"],"video/h261":["h261"],"video/h263":["h263"],"video/h264":["h264"],"video/iso.segment":["m4s"],"video/jpeg":["jpgv"],"video/jpm":["*jpm","jpgm"],"video/mj2":["mj2","mjp2"],"video/mp2t":["ts"],"video/mp4":["mp4","mp4v","mpg4"],"video/mpeg":["mpeg","mpg","mpe","m1v","m2v"],"video/ogg":["ogv"],"video/quicktime":["qt","mov"],"video/webm":["webm"]}; + +/***/ }), +/* 22 */ +/***/ (function(module, exports) { + +module.exports = {"application/prs.cww":["cww"],"application/vnd.1000minds.decision-model+xml":["1km"],"application/vnd.3gpp.pic-bw-large":["plb"],"application/vnd.3gpp.pic-bw-small":["psb"],"application/vnd.3gpp.pic-bw-var":["pvb"],"application/vnd.3gpp2.tcap":["tcap"],"application/vnd.3m.post-it-notes":["pwn"],"application/vnd.accpac.simply.aso":["aso"],"application/vnd.accpac.simply.imp":["imp"],"application/vnd.acucobol":["acu"],"application/vnd.acucorp":["atc","acutc"],"application/vnd.adobe.air-application-installer-package+zip":["air"],"application/vnd.adobe.formscentral.fcdt":["fcdt"],"application/vnd.adobe.fxp":["fxp","fxpl"],"application/vnd.adobe.xdp+xml":["xdp"],"application/vnd.adobe.xfdf":["xfdf"],"application/vnd.ahead.space":["ahead"],"application/vnd.airzip.filesecure.azf":["azf"],"application/vnd.airzip.filesecure.azs":["azs"],"application/vnd.amazon.ebook":["azw"],"application/vnd.americandynamics.acc":["acc"],"application/vnd.amiga.ami":["ami"],"application/vnd.android.package-archive":["apk"],"application/vnd.anser-web-certificate-issue-initiation":["cii"],"application/vnd.anser-web-funds-transfer-initiation":["fti"],"application/vnd.antix.game-component":["atx"],"application/vnd.apple.installer+xml":["mpkg"],"application/vnd.apple.keynote":["key"],"application/vnd.apple.mpegurl":["m3u8"],"application/vnd.apple.numbers":["numbers"],"application/vnd.apple.pages":["pages"],"application/vnd.apple.pkpass":["pkpass"],"application/vnd.aristanetworks.swi":["swi"],"application/vnd.astraea-software.iota":["iota"],"application/vnd.audiograph":["aep"],"application/vnd.balsamiq.bmml+xml":["bmml"],"application/vnd.blueice.multipass":["mpm"],"application/vnd.bmi":["bmi"],"application/vnd.businessobjects":["rep"],"application/vnd.chemdraw+xml":["cdxml"],"application/vnd.chipnuts.karaoke-mmd":["mmd"],"application/vnd.cinderella":["cdy"],"application/vnd.citationstyles.style+xml":["csl"],"application/vnd.claymore":["cla"],"application/vnd.cloanto.rp9":["rp9"],"application/vnd.clonk.c4group":["c4g","c4d","c4f","c4p","c4u"],"application/vnd.cluetrust.cartomobile-config":["c11amc"],"application/vnd.cluetrust.cartomobile-config-pkg":["c11amz"],"application/vnd.commonspace":["csp"],"application/vnd.contact.cmsg":["cdbcmsg"],"application/vnd.cosmocaller":["cmc"],"application/vnd.crick.clicker":["clkx"],"application/vnd.crick.clicker.keyboard":["clkk"],"application/vnd.crick.clicker.palette":["clkp"],"application/vnd.crick.clicker.template":["clkt"],"application/vnd.crick.clicker.wordbank":["clkw"],"application/vnd.criticaltools.wbs+xml":["wbs"],"application/vnd.ctc-posml":["pml"],"application/vnd.cups-ppd":["ppd"],"application/vnd.curl.car":["car"],"application/vnd.curl.pcurl":["pcurl"],"application/vnd.dart":["dart"],"application/vnd.data-vision.rdz":["rdz"],"application/vnd.dbf":["dbf"],"application/vnd.dece.data":["uvf","uvvf","uvd","uvvd"],"application/vnd.dece.ttml+xml":["uvt","uvvt"],"application/vnd.dece.unspecified":["uvx","uvvx"],"application/vnd.dece.zip":["uvz","uvvz"],"application/vnd.denovo.fcselayout-link":["fe_launch"],"application/vnd.dna":["dna"],"application/vnd.dolby.mlp":["mlp"],"application/vnd.dpgraph":["dpg"],"application/vnd.dreamfactory":["dfac"],"application/vnd.ds-keypoint":["kpxx"],"application/vnd.dvb.ait":["ait"],"application/vnd.dvb.service":["svc"],"application/vnd.dynageo":["geo"],"application/vnd.ecowin.chart":["mag"],"application/vnd.enliven":["nml"],"application/vnd.epson.esf":["esf"],"application/vnd.epson.msf":["msf"],"application/vnd.epson.quickanime":["qam"],"application/vnd.epson.salt":["slt"],"application/vnd.epson.ssf":["ssf"],"application/vnd.eszigno3+xml":["es3","et3"],"application/vnd.ezpix-album":["ez2"],"application/vnd.ezpix-package":["ez3"],"application/vnd.fdf":["fdf"],"application/vnd.fdsn.mseed":["mseed"],"application/vnd.fdsn.seed":["seed","dataless"],"application/vnd.flographit":["gph"],"application/vnd.fluxtime.clip":["ftc"],"application/vnd.framemaker":["fm","frame","maker","book"],"application/vnd.frogans.fnc":["fnc"],"application/vnd.frogans.ltf":["ltf"],"application/vnd.fsc.weblaunch":["fsc"],"application/vnd.fujitsu.oasys":["oas"],"application/vnd.fujitsu.oasys2":["oa2"],"application/vnd.fujitsu.oasys3":["oa3"],"application/vnd.fujitsu.oasysgp":["fg5"],"application/vnd.fujitsu.oasysprs":["bh2"],"application/vnd.fujixerox.ddd":["ddd"],"application/vnd.fujixerox.docuworks":["xdw"],"application/vnd.fujixerox.docuworks.binder":["xbd"],"application/vnd.fuzzysheet":["fzs"],"application/vnd.genomatix.tuxedo":["txd"],"application/vnd.geogebra.file":["ggb"],"application/vnd.geogebra.tool":["ggt"],"application/vnd.geometry-explorer":["gex","gre"],"application/vnd.geonext":["gxt"],"application/vnd.geoplan":["g2w"],"application/vnd.geospace":["g3w"],"application/vnd.gmx":["gmx"],"application/vnd.google-apps.document":["gdoc"],"application/vnd.google-apps.presentation":["gslides"],"application/vnd.google-apps.spreadsheet":["gsheet"],"application/vnd.google-earth.kml+xml":["kml"],"application/vnd.google-earth.kmz":["kmz"],"application/vnd.grafeq":["gqf","gqs"],"application/vnd.groove-account":["gac"],"application/vnd.groove-help":["ghf"],"application/vnd.groove-identity-message":["gim"],"application/vnd.groove-injector":["grv"],"application/vnd.groove-tool-message":["gtm"],"application/vnd.groove-tool-template":["tpl"],"application/vnd.groove-vcard":["vcg"],"application/vnd.hal+xml":["hal"],"application/vnd.handheld-entertainment+xml":["zmm"],"application/vnd.hbci":["hbci"],"application/vnd.hhe.lesson-player":["les"],"application/vnd.hp-hpgl":["hpgl"],"application/vnd.hp-hpid":["hpid"],"application/vnd.hp-hps":["hps"],"application/vnd.hp-jlyt":["jlt"],"application/vnd.hp-pcl":["pcl"],"application/vnd.hp-pclxl":["pclxl"],"application/vnd.hydrostatix.sof-data":["sfd-hdstx"],"application/vnd.ibm.minipay":["mpy"],"application/vnd.ibm.modcap":["afp","listafp","list3820"],"application/vnd.ibm.rights-management":["irm"],"application/vnd.ibm.secure-container":["sc"],"application/vnd.iccprofile":["icc","icm"],"application/vnd.igloader":["igl"],"application/vnd.immervision-ivp":["ivp"],"application/vnd.immervision-ivu":["ivu"],"application/vnd.insors.igm":["igm"],"application/vnd.intercon.formnet":["xpw","xpx"],"application/vnd.intergeo":["i2g"],"application/vnd.intu.qbo":["qbo"],"application/vnd.intu.qfx":["qfx"],"application/vnd.ipunplugged.rcprofile":["rcprofile"],"application/vnd.irepository.package+xml":["irp"],"application/vnd.is-xpr":["xpr"],"application/vnd.isac.fcs":["fcs"],"application/vnd.jam":["jam"],"application/vnd.jcp.javame.midlet-rms":["rms"],"application/vnd.jisp":["jisp"],"application/vnd.joost.joda-archive":["joda"],"application/vnd.kahootz":["ktz","ktr"],"application/vnd.kde.karbon":["karbon"],"application/vnd.kde.kchart":["chrt"],"application/vnd.kde.kformula":["kfo"],"application/vnd.kde.kivio":["flw"],"application/vnd.kde.kontour":["kon"],"application/vnd.kde.kpresenter":["kpr","kpt"],"application/vnd.kde.kspread":["ksp"],"application/vnd.kde.kword":["kwd","kwt"],"application/vnd.kenameaapp":["htke"],"application/vnd.kidspiration":["kia"],"application/vnd.kinar":["kne","knp"],"application/vnd.koan":["skp","skd","skt","skm"],"application/vnd.kodak-descriptor":["sse"],"application/vnd.las.las+xml":["lasxml"],"application/vnd.llamagraphics.life-balance.desktop":["lbd"],"application/vnd.llamagraphics.life-balance.exchange+xml":["lbe"],"application/vnd.lotus-1-2-3":["123"],"application/vnd.lotus-approach":["apr"],"application/vnd.lotus-freelance":["pre"],"application/vnd.lotus-notes":["nsf"],"application/vnd.lotus-organizer":["org"],"application/vnd.lotus-screencam":["scm"],"application/vnd.lotus-wordpro":["lwp"],"application/vnd.macports.portpkg":["portpkg"],"application/vnd.mcd":["mcd"],"application/vnd.medcalcdata":["mc1"],"application/vnd.mediastation.cdkey":["cdkey"],"application/vnd.mfer":["mwf"],"application/vnd.mfmp":["mfm"],"application/vnd.micrografx.flo":["flo"],"application/vnd.micrografx.igx":["igx"],"application/vnd.mif":["mif"],"application/vnd.mobius.daf":["daf"],"application/vnd.mobius.dis":["dis"],"application/vnd.mobius.mbk":["mbk"],"application/vnd.mobius.mqy":["mqy"],"application/vnd.mobius.msl":["msl"],"application/vnd.mobius.plc":["plc"],"application/vnd.mobius.txf":["txf"],"application/vnd.mophun.application":["mpn"],"application/vnd.mophun.certificate":["mpc"],"application/vnd.mozilla.xul+xml":["xul"],"application/vnd.ms-artgalry":["cil"],"application/vnd.ms-cab-compressed":["cab"],"application/vnd.ms-excel":["xls","xlm","xla","xlc","xlt","xlw"],"application/vnd.ms-excel.addin.macroenabled.12":["xlam"],"application/vnd.ms-excel.sheet.binary.macroenabled.12":["xlsb"],"application/vnd.ms-excel.sheet.macroenabled.12":["xlsm"],"application/vnd.ms-excel.template.macroenabled.12":["xltm"],"application/vnd.ms-fontobject":["eot"],"application/vnd.ms-htmlhelp":["chm"],"application/vnd.ms-ims":["ims"],"application/vnd.ms-lrm":["lrm"],"application/vnd.ms-officetheme":["thmx"],"application/vnd.ms-outlook":["msg"],"application/vnd.ms-pki.seccat":["cat"],"application/vnd.ms-pki.stl":["*stl"],"application/vnd.ms-powerpoint":["ppt","pps","pot"],"application/vnd.ms-powerpoint.addin.macroenabled.12":["ppam"],"application/vnd.ms-powerpoint.presentation.macroenabled.12":["pptm"],"application/vnd.ms-powerpoint.slide.macroenabled.12":["sldm"],"application/vnd.ms-powerpoint.slideshow.macroenabled.12":["ppsm"],"application/vnd.ms-powerpoint.template.macroenabled.12":["potm"],"application/vnd.ms-project":["mpp","mpt"],"application/vnd.ms-word.document.macroenabled.12":["docm"],"application/vnd.ms-word.template.macroenabled.12":["dotm"],"application/vnd.ms-works":["wps","wks","wcm","wdb"],"application/vnd.ms-wpl":["wpl"],"application/vnd.ms-xpsdocument":["xps"],"application/vnd.mseq":["mseq"],"application/vnd.musician":["mus"],"application/vnd.muvee.style":["msty"],"application/vnd.mynfc":["taglet"],"application/vnd.neurolanguage.nlu":["nlu"],"application/vnd.nitf":["ntf","nitf"],"application/vnd.noblenet-directory":["nnd"],"application/vnd.noblenet-sealer":["nns"],"application/vnd.noblenet-web":["nnw"],"application/vnd.nokia.n-gage.ac+xml":["*ac"],"application/vnd.nokia.n-gage.data":["ngdat"],"application/vnd.nokia.n-gage.symbian.install":["n-gage"],"application/vnd.nokia.radio-preset":["rpst"],"application/vnd.nokia.radio-presets":["rpss"],"application/vnd.novadigm.edm":["edm"],"application/vnd.novadigm.edx":["edx"],"application/vnd.novadigm.ext":["ext"],"application/vnd.oasis.opendocument.chart":["odc"],"application/vnd.oasis.opendocument.chart-template":["otc"],"application/vnd.oasis.opendocument.database":["odb"],"application/vnd.oasis.opendocument.formula":["odf"],"application/vnd.oasis.opendocument.formula-template":["odft"],"application/vnd.oasis.opendocument.graphics":["odg"],"application/vnd.oasis.opendocument.graphics-template":["otg"],"application/vnd.oasis.opendocument.image":["odi"],"application/vnd.oasis.opendocument.image-template":["oti"],"application/vnd.oasis.opendocument.presentation":["odp"],"application/vnd.oasis.opendocument.presentation-template":["otp"],"application/vnd.oasis.opendocument.spreadsheet":["ods"],"application/vnd.oasis.opendocument.spreadsheet-template":["ots"],"application/vnd.oasis.opendocument.text":["odt"],"application/vnd.oasis.opendocument.text-master":["odm"],"application/vnd.oasis.opendocument.text-template":["ott"],"application/vnd.oasis.opendocument.text-web":["oth"],"application/vnd.olpc-sugar":["xo"],"application/vnd.oma.dd2+xml":["dd2"],"application/vnd.openblox.game+xml":["obgx"],"application/vnd.openofficeorg.extension":["oxt"],"application/vnd.openstreetmap.data+xml":["osm"],"application/vnd.openxmlformats-officedocument.presentationml.presentation":["pptx"],"application/vnd.openxmlformats-officedocument.presentationml.slide":["sldx"],"application/vnd.openxmlformats-officedocument.presentationml.slideshow":["ppsx"],"application/vnd.openxmlformats-officedocument.presentationml.template":["potx"],"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":["xlsx"],"application/vnd.openxmlformats-officedocument.spreadsheetml.template":["xltx"],"application/vnd.openxmlformats-officedocument.wordprocessingml.document":["docx"],"application/vnd.openxmlformats-officedocument.wordprocessingml.template":["dotx"],"application/vnd.osgeo.mapguide.package":["mgp"],"application/vnd.osgi.dp":["dp"],"application/vnd.osgi.subsystem":["esa"],"application/vnd.palm":["pdb","pqa","oprc"],"application/vnd.pawaafile":["paw"],"application/vnd.pg.format":["str"],"application/vnd.pg.osasli":["ei6"],"application/vnd.picsel":["efif"],"application/vnd.pmi.widget":["wg"],"application/vnd.pocketlearn":["plf"],"application/vnd.powerbuilder6":["pbd"],"application/vnd.previewsystems.box":["box"],"application/vnd.proteus.magazine":["mgz"],"application/vnd.publishare-delta-tree":["qps"],"application/vnd.pvi.ptid1":["ptid"],"application/vnd.quark.quarkxpress":["qxd","qxt","qwd","qwt","qxl","qxb"],"application/vnd.rar":["rar"],"application/vnd.realvnc.bed":["bed"],"application/vnd.recordare.musicxml":["mxl"],"application/vnd.recordare.musicxml+xml":["musicxml"],"application/vnd.rig.cryptonote":["cryptonote"],"application/vnd.rim.cod":["cod"],"application/vnd.rn-realmedia":["rm"],"application/vnd.rn-realmedia-vbr":["rmvb"],"application/vnd.route66.link66+xml":["link66"],"application/vnd.sailingtracker.track":["st"],"application/vnd.seemail":["see"],"application/vnd.sema":["sema"],"application/vnd.semd":["semd"],"application/vnd.semf":["semf"],"application/vnd.shana.informed.formdata":["ifm"],"application/vnd.shana.informed.formtemplate":["itp"],"application/vnd.shana.informed.interchange":["iif"],"application/vnd.shana.informed.package":["ipk"],"application/vnd.simtech-mindmapper":["twd","twds"],"application/vnd.smaf":["mmf"],"application/vnd.smart.teacher":["teacher"],"application/vnd.software602.filler.form+xml":["fo"],"application/vnd.solent.sdkm+xml":["sdkm","sdkd"],"application/vnd.spotfire.dxp":["dxp"],"application/vnd.spotfire.sfs":["sfs"],"application/vnd.stardivision.calc":["sdc"],"application/vnd.stardivision.draw":["sda"],"application/vnd.stardivision.impress":["sdd"],"application/vnd.stardivision.math":["smf"],"application/vnd.stardivision.writer":["sdw","vor"],"application/vnd.stardivision.writer-global":["sgl"],"application/vnd.stepmania.package":["smzip"],"application/vnd.stepmania.stepchart":["sm"],"application/vnd.sun.wadl+xml":["wadl"],"application/vnd.sun.xml.calc":["sxc"],"application/vnd.sun.xml.calc.template":["stc"],"application/vnd.sun.xml.draw":["sxd"],"application/vnd.sun.xml.draw.template":["std"],"application/vnd.sun.xml.impress":["sxi"],"application/vnd.sun.xml.impress.template":["sti"],"application/vnd.sun.xml.math":["sxm"],"application/vnd.sun.xml.writer":["sxw"],"application/vnd.sun.xml.writer.global":["sxg"],"application/vnd.sun.xml.writer.template":["stw"],"application/vnd.sus-calendar":["sus","susp"],"application/vnd.svd":["svd"],"application/vnd.symbian.install":["sis","sisx"],"application/vnd.syncml+xml":["xsm"],"application/vnd.syncml.dm+wbxml":["bdm"],"application/vnd.syncml.dm+xml":["xdm"],"application/vnd.syncml.dmddf+xml":["ddf"],"application/vnd.tao.intent-module-archive":["tao"],"application/vnd.tcpdump.pcap":["pcap","cap","dmp"],"application/vnd.tmobile-livetv":["tmo"],"application/vnd.trid.tpt":["tpt"],"application/vnd.triscape.mxs":["mxs"],"application/vnd.trueapp":["tra"],"application/vnd.ufdl":["ufd","ufdl"],"application/vnd.uiq.theme":["utz"],"application/vnd.umajin":["umj"],"application/vnd.unity":["unityweb"],"application/vnd.uoml+xml":["uoml"],"application/vnd.vcx":["vcx"],"application/vnd.visio":["vsd","vst","vss","vsw"],"application/vnd.visionary":["vis"],"application/vnd.vsf":["vsf"],"application/vnd.wap.wbxml":["wbxml"],"application/vnd.wap.wmlc":["wmlc"],"application/vnd.wap.wmlscriptc":["wmlsc"],"application/vnd.webturbo":["wtb"],"application/vnd.wolfram.player":["nbp"],"application/vnd.wordperfect":["wpd"],"application/vnd.wqd":["wqd"],"application/vnd.wt.stf":["stf"],"application/vnd.xara":["xar"],"application/vnd.xfdl":["xfdl"],"application/vnd.yamaha.hv-dic":["hvd"],"application/vnd.yamaha.hv-script":["hvs"],"application/vnd.yamaha.hv-voice":["hvp"],"application/vnd.yamaha.openscoreformat":["osf"],"application/vnd.yamaha.openscoreformat.osfpvg+xml":["osfpvg"],"application/vnd.yamaha.smaf-audio":["saf"],"application/vnd.yamaha.smaf-phrase":["spf"],"application/vnd.yellowriver-custom-menu":["cmp"],"application/vnd.zul":["zir","zirz"],"application/vnd.zzazz.deck+xml":["zaz"],"application/x-7z-compressed":["7z"],"application/x-abiword":["abw"],"application/x-ace-compressed":["ace"],"application/x-apple-diskimage":["*dmg"],"application/x-arj":["arj"],"application/x-authorware-bin":["aab","x32","u32","vox"],"application/x-authorware-map":["aam"],"application/x-authorware-seg":["aas"],"application/x-bcpio":["bcpio"],"application/x-bdoc":["*bdoc"],"application/x-bittorrent":["torrent"],"application/x-blorb":["blb","blorb"],"application/x-bzip":["bz"],"application/x-bzip2":["bz2","boz"],"application/x-cbr":["cbr","cba","cbt","cbz","cb7"],"application/x-cdlink":["vcd"],"application/x-cfs-compressed":["cfs"],"application/x-chat":["chat"],"application/x-chess-pgn":["pgn"],"application/x-chrome-extension":["crx"],"application/x-cocoa":["cco"],"application/x-conference":["nsc"],"application/x-cpio":["cpio"],"application/x-csh":["csh"],"application/x-debian-package":["*deb","udeb"],"application/x-dgc-compressed":["dgc"],"application/x-director":["dir","dcr","dxr","cst","cct","cxt","w3d","fgd","swa"],"application/x-doom":["wad"],"application/x-dtbncx+xml":["ncx"],"application/x-dtbook+xml":["dtb"],"application/x-dtbresource+xml":["res"],"application/x-dvi":["dvi"],"application/x-envoy":["evy"],"application/x-eva":["eva"],"application/x-font-bdf":["bdf"],"application/x-font-ghostscript":["gsf"],"application/x-font-linux-psf":["psf"],"application/x-font-pcf":["pcf"],"application/x-font-snf":["snf"],"application/x-font-type1":["pfa","pfb","pfm","afm"],"application/x-freearc":["arc"],"application/x-futuresplash":["spl"],"application/x-gca-compressed":["gca"],"application/x-glulx":["ulx"],"application/x-gnumeric":["gnumeric"],"application/x-gramps-xml":["gramps"],"application/x-gtar":["gtar"],"application/x-hdf":["hdf"],"application/x-httpd-php":["php"],"application/x-install-instructions":["install"],"application/x-iso9660-image":["*iso"],"application/x-java-archive-diff":["jardiff"],"application/x-java-jnlp-file":["jnlp"],"application/x-keepass2":["kdbx"],"application/x-latex":["latex"],"application/x-lua-bytecode":["luac"],"application/x-lzh-compressed":["lzh","lha"],"application/x-makeself":["run"],"application/x-mie":["mie"],"application/x-mobipocket-ebook":["prc","mobi"],"application/x-ms-application":["application"],"application/x-ms-shortcut":["lnk"],"application/x-ms-wmd":["wmd"],"application/x-ms-wmz":["wmz"],"application/x-ms-xbap":["xbap"],"application/x-msaccess":["mdb"],"application/x-msbinder":["obd"],"application/x-mscardfile":["crd"],"application/x-msclip":["clp"],"application/x-msdos-program":["*exe"],"application/x-msdownload":["*exe","*dll","com","bat","*msi"],"application/x-msmediaview":["mvb","m13","m14"],"application/x-msmetafile":["*wmf","*wmz","*emf","emz"],"application/x-msmoney":["mny"],"application/x-mspublisher":["pub"],"application/x-msschedule":["scd"],"application/x-msterminal":["trm"],"application/x-mswrite":["wri"],"application/x-netcdf":["nc","cdf"],"application/x-ns-proxy-autoconfig":["pac"],"application/x-nzb":["nzb"],"application/x-perl":["pl","pm"],"application/x-pilot":["*prc","*pdb"],"application/x-pkcs12":["p12","pfx"],"application/x-pkcs7-certificates":["p7b","spc"],"application/x-pkcs7-certreqresp":["p7r"],"application/x-rar-compressed":["*rar"],"application/x-redhat-package-manager":["rpm"],"application/x-research-info-systems":["ris"],"application/x-sea":["sea"],"application/x-sh":["sh"],"application/x-shar":["shar"],"application/x-shockwave-flash":["swf"],"application/x-silverlight-app":["xap"],"application/x-sql":["sql"],"application/x-stuffit":["sit"],"application/x-stuffitx":["sitx"],"application/x-subrip":["srt"],"application/x-sv4cpio":["sv4cpio"],"application/x-sv4crc":["sv4crc"],"application/x-t3vm-image":["t3"],"application/x-tads":["gam"],"application/x-tar":["tar"],"application/x-tcl":["tcl","tk"],"application/x-tex":["tex"],"application/x-tex-tfm":["tfm"],"application/x-texinfo":["texinfo","texi"],"application/x-tgif":["*obj"],"application/x-ustar":["ustar"],"application/x-virtualbox-hdd":["hdd"],"application/x-virtualbox-ova":["ova"],"application/x-virtualbox-ovf":["ovf"],"application/x-virtualbox-vbox":["vbox"],"application/x-virtualbox-vbox-extpack":["vbox-extpack"],"application/x-virtualbox-vdi":["vdi"],"application/x-virtualbox-vhd":["vhd"],"application/x-virtualbox-vmdk":["vmdk"],"application/x-wais-source":["src"],"application/x-web-app-manifest+json":["webapp"],"application/x-x509-ca-cert":["der","crt","pem"],"application/x-xfig":["fig"],"application/x-xliff+xml":["*xlf"],"application/x-xpinstall":["xpi"],"application/x-xz":["xz"],"application/x-zmachine":["z1","z2","z3","z4","z5","z6","z7","z8"],"audio/vnd.dece.audio":["uva","uvva"],"audio/vnd.digital-winds":["eol"],"audio/vnd.dra":["dra"],"audio/vnd.dts":["dts"],"audio/vnd.dts.hd":["dtshd"],"audio/vnd.lucent.voice":["lvp"],"audio/vnd.ms-playready.media.pya":["pya"],"audio/vnd.nuera.ecelp4800":["ecelp4800"],"audio/vnd.nuera.ecelp7470":["ecelp7470"],"audio/vnd.nuera.ecelp9600":["ecelp9600"],"audio/vnd.rip":["rip"],"audio/x-aac":["aac"],"audio/x-aiff":["aif","aiff","aifc"],"audio/x-caf":["caf"],"audio/x-flac":["flac"],"audio/x-m4a":["*m4a"],"audio/x-matroska":["mka"],"audio/x-mpegurl":["m3u"],"audio/x-ms-wax":["wax"],"audio/x-ms-wma":["wma"],"audio/x-pn-realaudio":["ram","ra"],"audio/x-pn-realaudio-plugin":["rmp"],"audio/x-realaudio":["*ra"],"audio/x-wav":["*wav"],"chemical/x-cdx":["cdx"],"chemical/x-cif":["cif"],"chemical/x-cmdf":["cmdf"],"chemical/x-cml":["cml"],"chemical/x-csml":["csml"],"chemical/x-xyz":["xyz"],"image/prs.btif":["btif"],"image/prs.pti":["pti"],"image/vnd.adobe.photoshop":["psd"],"image/vnd.airzip.accelerator.azv":["azv"],"image/vnd.dece.graphic":["uvi","uvvi","uvg","uvvg"],"image/vnd.djvu":["djvu","djv"],"image/vnd.dvb.subtitle":["*sub"],"image/vnd.dwg":["dwg"],"image/vnd.dxf":["dxf"],"image/vnd.fastbidsheet":["fbs"],"image/vnd.fpx":["fpx"],"image/vnd.fst":["fst"],"image/vnd.fujixerox.edmics-mmr":["mmr"],"image/vnd.fujixerox.edmics-rlc":["rlc"],"image/vnd.microsoft.icon":["ico"],"image/vnd.ms-dds":["dds"],"image/vnd.ms-modi":["mdi"],"image/vnd.ms-photo":["wdp"],"image/vnd.net-fpx":["npx"],"image/vnd.pco.b16":["b16"],"image/vnd.tencent.tap":["tap"],"image/vnd.valve.source.texture":["vtf"],"image/vnd.wap.wbmp":["wbmp"],"image/vnd.xiff":["xif"],"image/vnd.zbrush.pcx":["pcx"],"image/x-3ds":["3ds"],"image/x-cmu-raster":["ras"],"image/x-cmx":["cmx"],"image/x-freehand":["fh","fhc","fh4","fh5","fh7"],"image/x-icon":["*ico"],"image/x-jng":["jng"],"image/x-mrsid-image":["sid"],"image/x-ms-bmp":["*bmp"],"image/x-pcx":["*pcx"],"image/x-pict":["pic","pct"],"image/x-portable-anymap":["pnm"],"image/x-portable-bitmap":["pbm"],"image/x-portable-graymap":["pgm"],"image/x-portable-pixmap":["ppm"],"image/x-rgb":["rgb"],"image/x-tga":["tga"],"image/x-xbitmap":["xbm"],"image/x-xpixmap":["xpm"],"image/x-xwindowdump":["xwd"],"message/vnd.wfa.wsc":["wsc"],"model/vnd.collada+xml":["dae"],"model/vnd.dwf":["dwf"],"model/vnd.gdl":["gdl"],"model/vnd.gtw":["gtw"],"model/vnd.mts":["mts"],"model/vnd.opengex":["ogex"],"model/vnd.parasolid.transmit.binary":["x_b"],"model/vnd.parasolid.transmit.text":["x_t"],"model/vnd.usdz+zip":["usdz"],"model/vnd.valve.source.compiled-map":["bsp"],"model/vnd.vtu":["vtu"],"text/prs.lines.tag":["dsc"],"text/vnd.curl":["curl"],"text/vnd.curl.dcurl":["dcurl"],"text/vnd.curl.mcurl":["mcurl"],"text/vnd.curl.scurl":["scurl"],"text/vnd.dvb.subtitle":["sub"],"text/vnd.fly":["fly"],"text/vnd.fmi.flexstor":["flx"],"text/vnd.graphviz":["gv"],"text/vnd.in3d.3dml":["3dml"],"text/vnd.in3d.spot":["spot"],"text/vnd.sun.j2me.app-descriptor":["jad"],"text/vnd.wap.wml":["wml"],"text/vnd.wap.wmlscript":["wmls"],"text/x-asm":["s","asm"],"text/x-c":["c","cc","cxx","cpp","h","hh","dic"],"text/x-component":["htc"],"text/x-fortran":["f","for","f77","f90"],"text/x-handlebars-template":["hbs"],"text/x-java-source":["java"],"text/x-lua":["lua"],"text/x-markdown":["mkd"],"text/x-nfo":["nfo"],"text/x-opml":["opml"],"text/x-org":["*org"],"text/x-pascal":["p","pas"],"text/x-processing":["pde"],"text/x-sass":["sass"],"text/x-scss":["scss"],"text/x-setext":["etx"],"text/x-sfv":["sfv"],"text/x-suse-ymp":["ymp"],"text/x-uuencode":["uu"],"text/x-vcalendar":["vcs"],"text/x-vcard":["vcf"],"video/vnd.dece.hd":["uvh","uvvh"],"video/vnd.dece.mobile":["uvm","uvvm"],"video/vnd.dece.pd":["uvp","uvvp"],"video/vnd.dece.sd":["uvs","uvvs"],"video/vnd.dece.video":["uvv","uvvv"],"video/vnd.dvb.file":["dvb"],"video/vnd.fvt":["fvt"],"video/vnd.mpegurl":["mxu","m4u"],"video/vnd.ms-playready.media.pyv":["pyv"],"video/vnd.uvvu.mp4":["uvu","uvvu"],"video/vnd.vivo":["viv"],"video/x-f4v":["f4v"],"video/x-fli":["fli"],"video/x-flv":["flv"],"video/x-m4v":["m4v"],"video/x-matroska":["mkv","mk3d","mks"],"video/x-mng":["mng"],"video/x-ms-asf":["asf","asx"],"video/x-ms-vob":["vob"],"video/x-ms-wm":["wm"],"video/x-ms-wmv":["wmv"],"video/x-ms-wmx":["wmx"],"video/x-ms-wvx":["wvx"],"video/x-msvideo":["avi"],"video/x-sgi-movie":["movie"],"video/x-smv":["smv"],"x-conference/x-cooltalk":["ice"]}; + +/***/ }), +/* 23 */ +/***/ (function(module, exports, __webpack_require__) { + +var session = __webpack_require__(5); +var Async = __webpack_require__(24); +var EventProxy = __webpack_require__(4).EventProxy; +var util = __webpack_require__(0); + +// 文件分块上传全过程,暴露的分块上传接口 +function sliceUploadFile(params, callback) { + var self = this; + + // 如果小程序版本不支持获取文件分片内容,统一转到 postObject 接口上传 + if (!util.canFileSlice()) { + params.SkipTask = true; + self.postObject(params, callback); + return; + } + + var ep = new EventProxy(); + var TaskId = params.TaskId; + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var FilePath = params.FilePath; + var ChunkSize = params.ChunkSize || params.SliceSize || self.options.ChunkSize; + var AsyncLimit = params.AsyncLimit; + var StorageClass = params.StorageClass; + var ServerSideEncryption = params.ServerSideEncryption; + var FileSize; + + var onProgress; + var onHashProgress = params.onHashProgress; + + // 上传过程中出现错误,返回错误 + ep.on('error', function (err) { + if (!self._isRunningTask(TaskId)) return; + var _err = { + UploadId: params.UploadData.UploadId || '', + err: err, + }; + return callback(_err); + }); + + // 上传分块完成,开始 uploadSliceComplete 操作 + ep.on('upload_complete', function (UploadCompleteData) { + var _UploadCompleteData = util.extend({ + UploadId: params.UploadData.UploadId || '' + }, UploadCompleteData); + callback(null, _UploadCompleteData); + }); + + // 上传分块完成,开始 uploadSliceComplete 操作 + ep.on('upload_slice_complete', function (UploadData) { + uploadSliceComplete.call(self, { + Bucket: Bucket, + Region: Region, + Key: Key, + UploadId: UploadData.UploadId, + SliceList: UploadData.SliceList, + }, function (err, data) { + if (!self._isRunningTask(TaskId)) return; + session.removeUsing(UploadData.UploadId); + if (err) { + onProgress(null, true); + return ep.emit('error', err); + } + session.removeUploadId(UploadData.UploadId); + onProgress({loaded: FileSize, total: FileSize}, true); + ep.emit('upload_complete', data); + }); + }); + + // 获取 UploadId 完成,开始上传每个分片 + ep.on('get_upload_data_finish', function (UploadData) { + + // 处理 UploadId 缓存 + var uuid = session.getFileId(params.FileStat, params.ChunkSize, Bucket, Key); + uuid && session.saveUploadId(uuid, UploadData.UploadId, self.options.UploadIdCacheLimit); // 缓存 UploadId + session.setUsing(UploadData.UploadId); // 标记 UploadId 为正在使用 + + // 获取 UploadId + onProgress(null, true); // 任务状态开始 uploading + uploadSliceList.call(self, { + TaskId: TaskId, + Bucket: Bucket, + Region: Region, + Key: Key, + FilePath: FilePath, + FileSize: FileSize, + SliceSize: ChunkSize, + AsyncLimit: AsyncLimit, + ServerSideEncryption: ServerSideEncryption, + UploadData: UploadData, + onProgress: onProgress + }, function (err, data) { + if (!self._isRunningTask(TaskId)) return; + if (err) { + onProgress(null, true); + return ep.emit('error', err); + } + ep.emit('upload_slice_complete', data); + }); + }); + + // 开始获取文件 UploadId,里面会视情况计算 ETag,并比对,保证文件一致性,也优化上传 + ep.on('get_file_size_finish', function () { + + onProgress = util.throttleOnProgress.call(self, FileSize, params.onProgress); + + if (params.UploadData.UploadId) { + ep.emit('get_upload_data_finish', params.UploadData); + } else { + var _params = util.extend({ + TaskId: TaskId, + Bucket: Bucket, + Region: Region, + Key: Key, + Headers: params.Headers, + StorageClass: StorageClass, + FilePath: FilePath, + FileSize: FileSize, + SliceSize: ChunkSize, + onHashProgress: onHashProgress, + }, params); + getUploadIdAndPartList.call(self, _params, function (err, UploadData) { + if (!self._isRunningTask(TaskId)) return; + if (err) return ep.emit('error', err); + params.UploadData.UploadId = UploadData.UploadId; + params.UploadData.PartList = UploadData.PartList; + ep.emit('get_upload_data_finish', params.UploadData); + }); + } + }); + + // 获取上传文件大小 + FileSize = params.ContentLength; + delete params.ContentLength; + !params.Headers && (params.Headers = {}); + util.each(params.Headers, function (item, key) { + if (key.toLowerCase() === 'content-length') { + delete params.Headers[key]; + } + }); + + // 控制分片大小 + (function () { + var SIZE = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 1024 * 2, 1024 * 4, 1024 * 5]; + var AutoChunkSize = 1024 * 1024; + for (var i = 0; i < SIZE.length; i++) { + AutoChunkSize = SIZE[i] * 1024 * 1024; + if (FileSize / AutoChunkSize <= self.options.MaxPartNumber) break; + } + params.ChunkSize = params.SliceSize = ChunkSize = Math.max(ChunkSize, AutoChunkSize); + })(); + + // 开始上传 + if (FileSize === 0) { + params.Body = ''; + params.ContentLength = 0; + params.SkipTask = true; + self.putObject(params, function (err, data) { + if (err) { + return callback(err); + } + callback(null, data); + }); + } else { + ep.emit('get_file_size_finish'); + } + +} + +// 获取上传任务的 UploadId +function getUploadIdAndPartList(params, callback) { + var TaskId = params.TaskId; + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var StorageClass = params.StorageClass; + var self = this; + + // 计算 ETag + var ETagMap = {}; + var FileSize = params.FileSize; + var SliceSize = params.SliceSize; + var SliceCount = Math.ceil(FileSize / SliceSize); + var FinishSliceCount = 0; + var FinishSize = 0; + var onHashProgress = util.throttleOnProgress.call(self, FileSize, params.onHashProgress); + var getChunkETag = function (PartNumber, callback) { + var start = SliceSize * (PartNumber - 1); + var end = Math.min(start + SliceSize, FileSize); + var ChunkSize = end - start; + + if (ETagMap[PartNumber]) { + callback(null, { + PartNumber: PartNumber, + ETag: ETagMap[PartNumber], + Size: ChunkSize + }); + } else { + util.fileSlice(params.FilePath, start, end, function (chunkItem) { + try { + var md5 = util.getFileMd5(chunkItem); + } catch (err) { + return callback(err); + } + var ETag = '"' + md5 + '"'; + ETagMap[PartNumber] = ETag; + FinishSliceCount += 1; + FinishSize += ChunkSize; + callback(null, { + PartNumber: PartNumber, + ETag: ETag, + Size: ChunkSize + }); + onHashProgress({loaded: FinishSize, total: FileSize}); + }); + } + }; + + // 通过和文件的 md5 对比,判断 UploadId 是否可用 + var isAvailableUploadList = function (PartList, callback) { + var PartCount = PartList.length; + // 如果没有分片,通过 + if (PartCount === 0) { + return callback(null, true); + } + // 检查分片数量 + if (PartCount > SliceCount) { + return callback(null, false); + } + // 检查分片大小 + if (PartCount > 1) { + var PartSliceSize = Math.max(PartList[0].Size, PartList[1].Size); + if (PartSliceSize !== SliceSize) { + return callback(null, false); + } + } + // 逐个分片计算并检查 ETag 是否一致 + var next = function (index) { + if (index < PartCount) { + var Part = PartList[index]; + getChunkETag(Part.PartNumber, function (err, chunk) { + if (chunk && chunk.ETag === Part.ETag && chunk.Size === Part.Size) { + next(index + 1); + } else { + callback(null, false); + } + }); + } else { + callback(null, true); + } + }; + next(0); + }; + + var ep = new EventProxy(); + ep.on('error', function (errData) { + if (!self._isRunningTask(TaskId)) return; + return callback(errData); + }); + + // 存在 UploadId + ep.on('upload_id_available', function (UploadData) { + // 转换成 map + var map = {}; + var list = []; + util.each(UploadData.PartList, function (item) { + map[item.PartNumber] = item; + }); + for (var PartNumber = 1; PartNumber <= SliceCount; PartNumber++) { + var item = map[PartNumber]; + if (item) { + item.PartNumber = PartNumber; + item.Uploaded = true; + } else { + item = { + PartNumber: PartNumber, + ETag: null, + Uploaded: false + }; + } + list.push(item); + } + UploadData.PartList = list; + callback(null, UploadData); + }); + + // 不存在 UploadId, 初始化生成 UploadId + ep.on('no_available_upload_id', function () { + if (!self._isRunningTask(TaskId)) return; + var _params = util.extend({ + Bucket: Bucket, + Region: Region, + Key: Key, + Headers: util.clone(params.Headers), + Query: util.clone(params.Query), + StorageClass: StorageClass, + }, params); + self.multipartInit(_params, function (err, data) { + if (!self._isRunningTask(TaskId)) return; + if (err) return ep.emit('error', err); + var UploadId = data.UploadId; + if (!UploadId) { + return callback({Message: 'no upload id'}); + } + ep.emit('upload_id_available', {UploadId: UploadId, PartList: []}); + }); + }); + + // 如果已存在 UploadId,找一个可以用的 UploadId + ep.on('has_and_check_upload_id', function (UploadIdList) { + // 串行地,找一个内容一致的 UploadId + UploadIdList = UploadIdList.reverse(); + Async.eachLimit(UploadIdList, 1, function (UploadId, asyncCallback) { + if (!self._isRunningTask(TaskId)) return; + // 如果正在上传,跳过 + if (session.using[UploadId]) { + asyncCallback(); // 检查下一个 UploadId + return; + } + // 判断 UploadId 是否可用 + wholeMultipartListPart.call(self, { + Bucket: Bucket, + Region: Region, + Key: Key, + UploadId: UploadId, + }, function (err, PartListData) { + if (!self._isRunningTask(TaskId)) return; + if (err) { + session.removeUsing(UploadId); + return ep.emit('error', err); + } + var PartList = PartListData.PartList; + PartList.forEach(function (item) { + item.PartNumber *= 1; + item.Size *= 1; + item.ETag = item.ETag || ''; + }); + isAvailableUploadList(PartList, function (err, isAvailable) { + if (!self._isRunningTask(TaskId)) return; + if (err) return ep.emit('error', err); + if (isAvailable) { + asyncCallback({ + UploadId: UploadId, + PartList: PartList + }); // 马上结束 + } else { + asyncCallback(); // 检查下一个 UploadId + } + }); + }); + }, function (AvailableUploadData) { + if (!self._isRunningTask(TaskId)) return; + onHashProgress(null, true); + if (AvailableUploadData && AvailableUploadData.UploadId) { + ep.emit('upload_id_available', AvailableUploadData); + } else { + ep.emit('no_available_upload_id'); + } + }); + }); + + // 在本地缓存找可用的 UploadId + ep.on('seek_local_avail_upload_id', function (RemoteUploadIdList) { + // 在本地找可用的 UploadId + var uuid = session.getFileId(params.FileStat, params.ChunkSize, Bucket, Key); + var LocalUploadIdList = session.getUploadIdList(uuid); + if (!uuid || !LocalUploadIdList) { + ep.emit('has_and_check_upload_id', RemoteUploadIdList); + return; + } + var next = function (index) { + // 如果本地找不到可用 UploadId,再一个个遍历校验远端 + if (index >= LocalUploadIdList.length) { + ep.emit('has_and_check_upload_id', RemoteUploadIdList); + return; + } + var UploadId = LocalUploadIdList[index]; + // 如果不在远端 UploadId 列表里,跳过并删除 + if (!util.isInArray(RemoteUploadIdList, UploadId)) { + session.removeUploadId(UploadId); + next(index + 1); + return; + } + // 如果正在上传,跳过 + if (session.using[UploadId]) { + next(index + 1); + return; + } + // 判断 UploadId 是否存在线上 + wholeMultipartListPart.call(self, { + Bucket: Bucket, + Region: Region, + Key: Key, + UploadId: UploadId, + }, function (err, PartListData) { + if (!self._isRunningTask(TaskId)) return; + if (err) { + // 如果 UploadId 获取会出错,跳过并删除 + session.removeUploadId(UploadId); + next(index + 1); + } else { + // 找到可用 UploadId + ep.emit('upload_id_available', { + UploadId: UploadId, + PartList: PartListData.PartList, + }); + } + }); + }; + next(0); + }); + + // 获取线上 UploadId 列表 + ep.on('get_remote_upload_id_list', function () { + // 获取符合条件的 UploadId 列表,因为同一个文件可以有多个上传任务。 + wholeMultipartList.call(self, { + Bucket: Bucket, + Region: Region, + Key: Key, + }, function (err, data) { + if (!self._isRunningTask(TaskId)) return; + if (err) { + return ep.emit('error', err); + } + // 整理远端 UploadId 列表 + var RemoteUploadIdList = util.filter(data.UploadList, function (item) { + return item.Key === Key && (!StorageClass || item.StorageClass.toUpperCase() === StorageClass.toUpperCase()); + }).reverse().map(function (item) { + return item.UploadId || item.UploadID; + }); + if (RemoteUploadIdList.length) { + ep.emit('seek_local_avail_upload_id', RemoteUploadIdList); + } else { + // 远端没有 UploadId,清理缓存的 UploadId + var uuid = session.getFileId(params.FileStat, params.ChunkSize, Bucket, Key), LocalUploadIdList; + if (uuid && (LocalUploadIdList = session.getUploadIdList(uuid))) { + util.each(LocalUploadIdList, function (UploadId) { + session.removeUploadId(UploadId); + }); + } + ep.emit('no_available_upload_id'); + } + }); + }); + + // 开始找可用 UploadId + ep.emit('get_remote_upload_id_list'); + +} + +// 获取符合条件的全部上传任务 (条件包括 Bucket, Region, Prefix) +function wholeMultipartList(params, callback) { + var self = this; + var UploadList = []; + var sendParams = { + Bucket: params.Bucket, + Region: params.Region, + Prefix: params.Key + }; + var next = function () { + self.multipartList(sendParams, function (err, data) { + if (err) return callback(err); + UploadList.push.apply(UploadList, data.Upload || []); + if (data.IsTruncated === 'true') { // 列表不完整 + sendParams.KeyMarker = data.NextKeyMarker; + sendParams.UploadIdMarker = data.NextUploadIdMarker; + next(); + } else { + callback(null, {UploadList: UploadList}); + } + }); + }; + next(); +} + +// 获取指定上传任务的分块列表 +function wholeMultipartListPart(params, callback) { + var self = this; + var PartList = []; + var sendParams = { + Bucket: params.Bucket, + Region: params.Region, + Key: params.Key, + UploadId: params.UploadId + }; + var next = function () { + self.multipartListPart(sendParams, function (err, data) { + if (err) return callback(err); + PartList.push.apply(PartList, data.Part || []); + if (data.IsTruncated === 'true') { // 列表不完整 + sendParams.PartNumberMarker = data.NextPartNumberMarker; + next(); + } else { + callback(null, {PartList: PartList}); + } + }); + }; + next(); +} + +// 上传文件分块,包括 +/* + UploadId (上传任务编号) + AsyncLimit (并发量), + SliceList (上传的分块数组), + FilePath (本地文件的位置), + SliceSize (文件分块大小) + FileSize (文件大小) + onProgress (上传成功之后的回调函数) + */ +function uploadSliceList(params, cb) { + var self = this; + var TaskId = params.TaskId; + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var UploadData = params.UploadData; + var FileSize = params.FileSize; + var SliceSize = params.SliceSize; + var ChunkParallel = Math.min(params.AsyncLimit || self.options.ChunkParallelLimit || 1, 256); + var FilePath = params.FilePath; + var SliceCount = Math.ceil(FileSize / SliceSize); + var FinishSize = 0; + var ServerSideEncryption = params.ServerSideEncryption; + var needUploadSlices = util.filter(UploadData.PartList, function (SliceItem) { + if (SliceItem['Uploaded']) { + FinishSize += SliceItem['PartNumber'] >= SliceCount ? (FileSize % SliceSize || SliceSize) : SliceSize; + } + return !SliceItem['Uploaded']; + }); + var onProgress = params.onProgress; + + Async.eachLimit(needUploadSlices, ChunkParallel, function (SliceItem, asyncCallback) { + if (!self._isRunningTask(TaskId)) return; + var PartNumber = SliceItem['PartNumber']; + var currentSize = Math.min(FileSize, SliceItem['PartNumber'] * SliceSize) - (SliceItem['PartNumber'] - 1) * SliceSize; + var preAddSize = 0; + uploadSliceItem.call(self, { + TaskId: TaskId, + Bucket: Bucket, + Region: Region, + Key: Key, + SliceSize: SliceSize, + FileSize: FileSize, + PartNumber: PartNumber, + ServerSideEncryption: ServerSideEncryption, + FilePath: FilePath, + UploadData: UploadData, + onProgress: function (data) { + FinishSize += data.loaded - preAddSize; + preAddSize = data.loaded; + onProgress({loaded: FinishSize, total: FileSize}); + }, + }, function (err, data) { + if (!self._isRunningTask(TaskId)) return; + if (err) { + FinishSize -= preAddSize; + } else { + FinishSize += currentSize - preAddSize; + SliceItem.ETag = data.ETag; + } + onProgress({loaded: FinishSize, total: FileSize}); + asyncCallback(err || null, data); + }); + }, function (err) { + if (!self._isRunningTask(TaskId)) return; + if (err) return cb(err); + cb(null, { + UploadId: UploadData.UploadId, + SliceList: UploadData.PartList + }); + }); +} + +// 上传指定分片 +function uploadSliceItem(params, callback) { + var self = this; + var TaskId = params.TaskId; + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var FileSize = params.FileSize; + var FilePath = params.FilePath; + var PartNumber = params.PartNumber * 1; + var SliceSize = params.SliceSize; + var ServerSideEncryption = params.ServerSideEncryption; + var UploadData = params.UploadData; + var ChunkRetryTimes = self.options.ChunkRetryTimes + 1; + + var start = SliceSize * (PartNumber - 1); + + var ContentLength = SliceSize; + + var end = start + SliceSize; + + if (end > FileSize) { + end = FileSize; + ContentLength = end - start; + } + + util.fileSlice(FilePath, start, end, function (Body) { + var md5 = util.getFileMd5(Body); + var contentMd5 = md5 ? util.binaryBase64(md5) : null; + var PartItem = UploadData.PartList[PartNumber - 1]; + Async.retry(ChunkRetryTimes, function (tryCallback) { + if (!self._isRunningTask(TaskId)) return; + self.multipartUpload({ + TaskId: TaskId, + Bucket: Bucket, + Region: Region, + Key: Key, + ContentLength: ContentLength, + PartNumber: PartNumber, + UploadId: UploadData.UploadId, + ServerSideEncryption: ServerSideEncryption, + Body: Body, + onProgress: params.onProgress, + ContentMD5: contentMd5, + }, function (err, data) { + if (!self._isRunningTask(TaskId)) return; + if (err) { + return tryCallback(err); + } else { + PartItem.Uploaded = true; + return tryCallback(null, data); + } + }); + }, function (err, data) { + if (!self._isRunningTask(TaskId)) return; + return callback(err, data); + }); + }); +} + + +// 完成分块上传 +function uploadSliceComplete(params, callback) { + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var UploadId = params.UploadId; + var SliceList = params.SliceList; + var self = this; + var ChunkRetryTimes = this.options.ChunkRetryTimes + 1; + var Parts = SliceList.map(function (item) { + return { + PartNumber: item.PartNumber, + ETag: item.ETag + }; + }); + // 完成上传的请求也做重试 + Async.retry(ChunkRetryTimes, function (tryCallback) { + self.multipartComplete({ + Bucket: Bucket, + Region: Region, + Key: Key, + UploadId: UploadId, + Parts: Parts + }, tryCallback); + }, function (err, data) { + callback(err, data); + }); +} + +// 抛弃分块上传任务 +/* + AsyncLimit (抛弃上传任务的并发量), + UploadId (上传任务的编号,当 Level 为 task 时候需要) + Level (抛弃分块上传任务的级别,task : 抛弃指定的上传任务,file : 抛弃指定的文件对应的上传任务,其他值 :抛弃指定Bucket 的全部上传任务) + */ +function abortUploadTask(params, callback) { + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var UploadId = params.UploadId; + var Level = params.Level || 'task'; + var AsyncLimit = params.AsyncLimit; + var self = this; + + var ep = new EventProxy(); + + ep.on('error', function (errData) { + return callback(errData); + }); + + // 已经获取到需要抛弃的任务列表 + ep.on('get_abort_array', function (AbortArray) { + abortUploadTaskArray.call(self, { + Bucket: Bucket, + Region: Region, + Key: Key, + Headers: params.Headers, + AsyncLimit: AsyncLimit, + AbortArray: AbortArray + }, function (err, data) { + if (err) { + return callback(err); + } + callback(null, data); + }); + }); + + if (Level === 'bucket') { + // Bucket 级别的任务抛弃,抛弃该 Bucket 下的全部上传任务 + wholeMultipartList.call(self, { + Bucket: Bucket, + Region: Region + }, function (err, data) { + if (err) { + return callback(err); + } + ep.emit('get_abort_array', data.UploadList || []); + }); + } else if (Level === 'file') { + // 文件级别的任务抛弃,抛弃该文件的全部上传任务 + if (!Key) return callback({error: 'abort_upload_task_no_key'}); + wholeMultipartList.call(self, { + Bucket: Bucket, + Region: Region, + Key: Key + }, function (err, data) { + if (err) { + return callback(err); + } + ep.emit('get_abort_array', data.UploadList || []); + }); + } else if (Level === 'task') { + // 单个任务级别的任务抛弃,抛弃指定 UploadId 的上传任务 + if (!UploadId) return callback({error: 'abort_upload_task_no_id'}); + if (!Key) return callback({error: 'abort_upload_task_no_key'}); + ep.emit('get_abort_array', [{ + Key: Key, + UploadId: UploadId + }]); + } else { + return callback({error: 'abort_unknown_level'}); + } +} +// 批量抛弃分块上传任务 +function abortUploadTaskArray(params, callback) { + + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var AbortArray = params.AbortArray; + var AsyncLimit = params.AsyncLimit || 1; + var self = this; + + var index = 0; + var resultList = new Array(AbortArray.length); + Async.eachLimit(AbortArray, AsyncLimit, function (AbortItem, callback) { + var eachIndex = index; + if (Key && Key !== AbortItem.Key) { + resultList[eachIndex] = {error: {KeyNotMatch: true}}; + callback(null); + return; + } + var UploadId = AbortItem.UploadId || AbortItem.UploadID; + + self.multipartAbort({ + Bucket: Bucket, + Region: Region, + Key: AbortItem.Key, + Headers: params.Headers, + UploadId: UploadId + }, function (err) { + var task = { + Bucket: Bucket, + Region: Region, + Key: AbortItem.Key, + UploadId: UploadId + }; + resultList[eachIndex] = {error: err, task: task}; + callback(null); + }); + index++; + + }, function (err) { + if (err) { + return callback(err); + } -/***/ }), -/* 19 */ -/***/ (function(module, exports, __webpack_require__) { + var successList = []; + var errorList = []; + + for (var i = 0, len = resultList.length; i < len; i++) { + var item = resultList[i]; + if (item['task']) { + if (item['error']) { + errorList.push(item['task']); + } else { + successList.push(item['task']); + } + } + } -"use strict"; + return callback(null, { + successList: successList, + errorList: errorList + }); + }); +} +// 高级上传 +function uploadFile(params, callback) { + var self = this; -var Mime = __webpack_require__(20); -module.exports = new Mime(__webpack_require__(21), __webpack_require__(22)); + // 判断多大的文件使用分片上传 + var SliceSize = params.SliceSize === undefined ? self.options.SliceSize : params.SliceSize; + var taskList = []; -/***/ }), -/* 20 */ -/***/ (function(module, exports, __webpack_require__) { + var FileSize = params.FileSize; + var fileInfo = {TaskId: ''}; -"use strict"; + // 整理 option,用于返回给回调 + util.each(params, function (v, k) { + if (typeof v !== 'object' && typeof v !== 'function') { + fileInfo[k] = v; + } + }); + + // 处理文件 TaskReady + var _onTaskReady = params.onTaskReady; + params.onTaskReady = function (tid) { + fileInfo.TaskId = tid; + _onTaskReady && _onTaskReady(tid); + }; + + // 处理文件完成 + var _onFileFinish = params.onFileFinish; + var onFileFinish = function (err, data) { + _onFileFinish && _onFileFinish(err, data, fileInfo); + callback && callback(err, data); + }; + + // 添加上传任务 + var api = FileSize > SliceSize ? 'sliceUploadFile' : 'postObject'; + taskList.push({ + api: api, + params: params, + callback: onFileFinish, + }); + self._addTasks(taskList); +} +// 批量上传文件 +function uploadFiles(params, callback) { + var self = this; + + // 判断多大的文件使用分片上传 + var SliceSize = params.SliceSize === undefined ? self.options.SliceSize : params.SliceSize; + + // 汇总返回进度 + var TotalSize = 0; + var TotalFinish = 0; + var onTotalProgress = util.throttleOnProgress.call(self, TotalFinish, params.onProgress); + + // 汇总返回回调 + var unFinishCount = params.files.length; + var _onTotalFileFinish = params.onFileFinish; + var resultList = Array(unFinishCount); + var onTotalFileFinish = function (err, data, options) { + onTotalProgress(null, true); + _onTotalFileFinish && _onTotalFileFinish(err, data, options); + resultList[options.Index] = { + options: options, + error: err, + data: data + }; + if (--unFinishCount <= 0 && callback) { + callback(null, { + files: resultList, + }); + } + }; -/** - * @param typeMap [Object] Map of MIME type -> Array[extensions] - * @param ... - */ -function Mime() { - this._types = Object.create(null); - this._extensions = Object.create(null); + // 开始处理每个文件 + var taskList = []; + util.each(params.files, function (fileParams, index) { + var FileSize = fileParams.FileSize; + var fileInfo = {Index: index, TaskId: ''}; - for (var i = 0; i < arguments.length; i++) { - this.define(arguments[i]); - } + // 更新文件总大小 + TotalSize += FileSize; - this.define = this.define.bind(this); - this.getType = this.getType.bind(this); - this.getExtension = this.getExtension.bind(this); + // 整理 option,用于返回给回调 + util.each(fileParams, function (v, k) { + if (typeof v !== 'object' && typeof v !== 'function') { + fileInfo[k] = v; + } + }); + + // 处理单个文件 TaskReady + var _onTaskReady = fileParams.onTaskReady; + fileParams.onTaskReady = function (tid) { + fileInfo.TaskId = tid; + _onTaskReady && _onTaskReady(tid); + }; + + // 处理单个文件进度 + var PreAddSize = 0; + var _onProgress = fileParams.onProgress; + fileParams.onProgress = function (info) { + TotalFinish = TotalFinish - PreAddSize + info.loaded; + PreAddSize = info.loaded; + _onProgress && _onProgress(info); + onTotalProgress({loaded: TotalFinish, total: TotalSize}); + }; + + // 处理单个文件完成 + var _onFileFinish = fileParams.onFileFinish; + var onFileFinish = function (err, data) { + _onFileFinish && _onFileFinish(err, data); + onTotalFileFinish && onTotalFileFinish(err, data, fileInfo); + }; + + // 添加上传任务 + var api = FileSize > SliceSize ? 'sliceUploadFile' : 'postObject'; + taskList.push({ + api: api, + params: fileParams, + callback: onFileFinish, + }); + }); + self._addTasks(taskList); } -/** - * Define mimetype -> extension mappings. Each key is a mime-type that maps - * to an array of extensions associated with the type. The first extension is - * used as the default extension for the type. - * - * e.g. mime.define({'audio/ogg', ['oga', 'ogg', 'spx']}); - * - * If a type declares an extension that has already been defined, an error will - * be thrown. To suppress this error and force the extension to be associated - * with the new type, pass `force`=true. Alternatively, you may prefix the - * extension with "*" to map the type to extension, without mapping the - * extension to the type. - * - * e.g. mime.define({'audio/wav', ['wav']}, {'audio/x-wav', ['*wav']}); - * - * - * @param map (Object) type definitions - * @param force (Boolean) if true, force overriding of existing definitions - */ -Mime.prototype.define = function(typeMap, force) { - for (var type in typeMap) { - var extensions = typeMap[type].map(function(t) {return t.toLowerCase()}); - type = type.toLowerCase(); +// 分片复制文件 +function sliceCopyFile(params, callback) { + var ep = new EventProxy(); + + var self = this; + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var CopySource = params.CopySource; + var m = CopySource.match(/^([^.]+-\d+)\.cos(v6)?\.([^.]+)\.[^/]+\/(.+)$/); + if (!m) { + callback({error: 'CopySource format error'}); + return; + } - for (var i = 0; i < extensions.length; i++) { - var ext = extensions[i]; + var SourceBucket = m[1]; + var SourceRegion = m[3]; + var SourceKey = decodeURIComponent(m[4]); + var CopySliceSize = params.CopySliceSize === undefined ? self.options.CopySliceSize : params.CopySliceSize; + CopySliceSize = Math.max(0, CopySliceSize); + + var ChunkSize = params.CopyChunkSize || this.options.CopyChunkSize; + var ChunkParallel = this.options.CopyChunkParallelLimit; + + var FinishSize = 0; + var FileSize; + var onProgress; + + // 分片复制完成,开始 multipartComplete 操作 + ep.on('copy_slice_complete', function (UploadData) { + self.multipartComplete({ + Bucket: Bucket, + Region: Region, + Key: Key, + UploadId: UploadData.UploadId, + Parts: UploadData.PartList, + },function (err, data) { + if (err) { + onProgress(null, true); + return callback(err); + } + onProgress({loaded: FileSize, total: FileSize}, true); + callback(null, data); + }); + }); + + ep.on('get_copy_data_finish',function (UploadData) { + Async.eachLimit(UploadData.PartList, ChunkParallel, function (SliceItem, asyncCallback) { + var PartNumber = SliceItem.PartNumber; + var CopySourceRange = SliceItem.CopySourceRange; + var currentSize = SliceItem.end - SliceItem.start; + var preAddSize = 0; + + copySliceItem.call(self, { + Bucket: Bucket, + Region: Region, + Key: Key, + CopySource: CopySource, + UploadId: UploadData.UploadId, + PartNumber: PartNumber, + CopySourceRange: CopySourceRange, + onProgress: function (data) { + FinishSize += data.loaded - preAddSize; + preAddSize = data.loaded; + onProgress({loaded: FinishSize, total: FileSize}); + } + },function (err,data) { + if (err) { + return asyncCallback(err); + } + onProgress({loaded: FinishSize, total: FileSize}); + + FinishSize += currentSize - preAddSize; + SliceItem.ETag = data.ETag; + asyncCallback(err || null, data); + }); + }, function (err) { + if (err) { + onProgress(null, true); + return callback(err); + } - // '*' prefix = not the preferred type for this extension. So fixup the - // extension, and skip it. - if (ext[0] == '*') { - continue; - } + ep.emit('copy_slice_complete', UploadData); + }); + }); + + ep.on('get_file_size_finish', function (SourceHeaders) { + // 控制分片大小 + (function () { + var SIZE = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 1024 * 2, 1024 * 4, 1024 * 5]; + var AutoChunkSize = 1024 * 1024; + for (var i = 0; i < SIZE.length; i++) { + AutoChunkSize = SIZE[i] * 1024 * 1024; + if (FileSize / AutoChunkSize <= self.options.MaxPartNumber) break; + } + params.ChunkSize = ChunkSize = Math.max(ChunkSize, AutoChunkSize); + + var ChunkCount = Math.ceil(FileSize / ChunkSize); + + var list = []; + for (var partNumber = 1; partNumber <= ChunkCount; partNumber++) { + var start = (partNumber - 1) * ChunkSize; + var end = partNumber * ChunkSize < FileSize ? (partNumber * ChunkSize - 1) : FileSize - 1; + var item = { + PartNumber: partNumber, + start: start, + end: end, + CopySourceRange: "bytes=" + start + "-" + end, + }; + list.push(item); + } + params.PartList = list; + })(); - if (!force && (ext in this._types)) { - throw new Error( - 'Attempt to change mapping for "' + ext + - '" extension from "' + this._types[ext] + '" to "' + type + - '". Pass `force=true` to allow this, otherwise remove "' + ext + - '" from the list of extensions for "' + type + '".' - ); - } + var TargetHeader; + if (params.Headers['x-cos-metadata-directive'] === 'Replaced') { + TargetHeader = params.Headers; + } else { + TargetHeader = SourceHeaders; + } + TargetHeader['x-cos-storage-class'] = params.Headers['x-cos-storage-class'] || SourceHeaders['x-cos-storage-class']; + TargetHeader = util.clearKey(TargetHeader); + /** + * 对于归档存储的对象,如果未恢复副本,则不允许 Copy + */ + if (SourceHeaders['x-cos-storage-class'] === 'ARCHIVE' || SourceHeaders['x-cos-storage-class'] === 'DEEP_ARCHIVE') { + var restoreHeader = SourceHeaders['x-cos-restore']; + if (!restoreHeader || restoreHeader === 'ongoing-request="true"') { + callback({ error: 'Unrestored archive object is not allowed to be copied' }); + return; + } + } + /** + * 去除一些无用的头部,规避 multipartInit 出错 + * 这些头部通常是在 putObjectCopy 时才使用 + */ + delete TargetHeader['x-cos-copy-source']; + delete TargetHeader['x-cos-metadata-directive']; + delete TargetHeader['x-cos-copy-source-If-Modified-Since']; + delete TargetHeader['x-cos-copy-source-If-Unmodified-Since']; + delete TargetHeader['x-cos-copy-source-If-Match']; + delete TargetHeader['x-cos-copy-source-If-None-Match']; + self.multipartInit({ + Bucket: Bucket, + Region: Region, + Key: Key, + Headers: TargetHeader, + },function (err,data) { + if (err) { + return callback(err); + } + params.UploadId = data.UploadId; + ep.emit('get_copy_data_finish', params); + }); + }); + + // 获取远端复制源文件的大小 + self.headObject({ + Bucket: SourceBucket, + Region: SourceRegion, + Key: SourceKey, + },function(err, data) { + if (err) { + if (err.statusCode && err.statusCode === 404) { + callback({ErrorStatus: SourceKey + ' Not Exist'}); + } else { + callback(err); + } + return; + } - this._types[ext] = type; - } + FileSize = params.FileSize = data.headers['content-length']; + if (FileSize === undefined || !FileSize) { + callback({error: 'get Content-Length error, please add "Content-Length" to CORS ExposeHeader setting.'}); + return; + } - // Use first extension as default - if (force || !this._extensions[type]) { - var ext = extensions[0]; - this._extensions[type] = (ext[0] != '*') ? ext : ext.substr(1) - } - } -}; + onProgress = util.throttleOnProgress.call(self, FileSize, params.onProgress); -/** - * Lookup a mime type based on extension - */ -Mime.prototype.getType = function(path) { - path = String(path); - var last = path.replace(/^.*[/\\]/, '').toLowerCase(); - var ext = last.replace(/^.*\./, '').toLowerCase(); + // 开始上传 + if (FileSize <= CopySliceSize) { + if (!params.Headers['x-cos-metadata-directive']) { + params.Headers['x-cos-metadata-directive'] = 'Copy'; + } + self.putObjectCopy(params, function (err, data) { + if (err) { + onProgress(null, true); + return callback(err); + } + onProgress({loaded: FileSize, total: FileSize}, true); + callback(err, data); + }); + } else { + var resHeaders = data.headers; + var SourceHeaders = { + 'Cache-Control': resHeaders['cache-control'], + 'Content-Disposition': resHeaders['content-disposition'], + 'Content-Encoding': resHeaders['content-encoding'], + 'Content-Type': resHeaders['content-type'], + 'Expires': resHeaders['expires'], + 'x-cos-storage-class': resHeaders['x-cos-storage-class'], + }; + util.each(resHeaders, function (v, k) { + var metaPrefix = 'x-cos-meta-'; + if (k.indexOf(metaPrefix) === 0 && k.length > metaPrefix.length) { + SourceHeaders[k] = v; + } + }); + ep.emit('get_file_size_finish', SourceHeaders); + } + }); +} - var hasPath = last.length < path.length; - var hasDot = ext.length < last.length - 1; +// 复制指定分片 +function copySliceItem(params, callback) { + var TaskId = params.TaskId; + var Bucket = params.Bucket; + var Region = params.Region; + var Key = params.Key; + var CopySource = params.CopySource; + var UploadId = params.UploadId; + var PartNumber = params.PartNumber * 1; + var CopySourceRange = params.CopySourceRange; + + var ChunkRetryTimes = this.options.ChunkRetryTimes + 1; + var self = this; + + Async.retry(ChunkRetryTimes, function (tryCallback) { + self.uploadPartCopy({ + TaskId: TaskId, + Bucket: Bucket, + Region: Region, + Key: Key, + CopySource: CopySource, + UploadId: UploadId, + PartNumber:PartNumber, + CopySourceRange:CopySourceRange, + onProgress:params.onProgress, + },function (err,data) { + tryCallback(err || null, data); + }) + }, function (err, data) { + return callback(err, data); + }); +} - return (hasDot || !hasPath) && this._types[ext] || null; -}; -/** - * Return file extension associated with a mime type - */ -Mime.prototype.getExtension = function(type) { - type = /^\s*([^;\s]*)/.test(type) && RegExp.$1; - return type && this._extensions[type.toLowerCase()] || null; +var API_MAP = { + sliceUploadFile: sliceUploadFile, + abortUploadTask: abortUploadTask, + uploadFile: uploadFile, + uploadFiles: uploadFiles, + sliceCopyFile: sliceCopyFile, }; -module.exports = Mime; +module.exports.init = function (COS, task) { + task.transferToTaskMethod(API_MAP, 'sliceUploadFile'); + util.each(API_MAP, function (fn, apiName) { + COS.prototype[apiName] = util.apiWrapper(apiName, fn); + }); +}; /***/ }), -/* 21 */ +/* 24 */ /***/ (function(module, exports) { -module.exports = {"application/andrew-inset":["ez"],"application/applixware":["aw"],"application/atom+xml":["atom"],"application/atomcat+xml":["atomcat"],"application/atomdeleted+xml":["atomdeleted"],"application/atomsvc+xml":["atomsvc"],"application/atsc-dwd+xml":["dwd"],"application/atsc-held+xml":["held"],"application/atsc-rsat+xml":["rsat"],"application/bdoc":["bdoc"],"application/calendar+xml":["xcs"],"application/ccxml+xml":["ccxml"],"application/cdfx+xml":["cdfx"],"application/cdmi-capability":["cdmia"],"application/cdmi-container":["cdmic"],"application/cdmi-domain":["cdmid"],"application/cdmi-object":["cdmio"],"application/cdmi-queue":["cdmiq"],"application/cu-seeme":["cu"],"application/dash+xml":["mpd"],"application/davmount+xml":["davmount"],"application/docbook+xml":["dbk"],"application/dssc+der":["dssc"],"application/dssc+xml":["xdssc"],"application/ecmascript":["ecma","es"],"application/emma+xml":["emma"],"application/emotionml+xml":["emotionml"],"application/epub+zip":["epub"],"application/exi":["exi"],"application/fdt+xml":["fdt"],"application/font-tdpfr":["pfr"],"application/geo+json":["geojson"],"application/gml+xml":["gml"],"application/gpx+xml":["gpx"],"application/gxf":["gxf"],"application/gzip":["gz"],"application/hjson":["hjson"],"application/hyperstudio":["stk"],"application/inkml+xml":["ink","inkml"],"application/ipfix":["ipfix"],"application/its+xml":["its"],"application/java-archive":["jar","war","ear"],"application/java-serialized-object":["ser"],"application/java-vm":["class"],"application/javascript":["js","mjs"],"application/json":["json","map"],"application/json5":["json5"],"application/jsonml+json":["jsonml"],"application/ld+json":["jsonld"],"application/lgr+xml":["lgr"],"application/lost+xml":["lostxml"],"application/mac-binhex40":["hqx"],"application/mac-compactpro":["cpt"],"application/mads+xml":["mads"],"application/manifest+json":["webmanifest"],"application/marc":["mrc"],"application/marcxml+xml":["mrcx"],"application/mathematica":["ma","nb","mb"],"application/mathml+xml":["mathml"],"application/mbox":["mbox"],"application/mediaservercontrol+xml":["mscml"],"application/metalink+xml":["metalink"],"application/metalink4+xml":["meta4"],"application/mets+xml":["mets"],"application/mmt-aei+xml":["maei"],"application/mmt-usd+xml":["musd"],"application/mods+xml":["mods"],"application/mp21":["m21","mp21"],"application/mp4":["mp4s","m4p"],"application/mrb-consumer+xml":["*xdf"],"application/mrb-publish+xml":["*xdf"],"application/msword":["doc","dot"],"application/mxf":["mxf"],"application/n-quads":["nq"],"application/n-triples":["nt"],"application/node":["cjs"],"application/octet-stream":["bin","dms","lrf","mar","so","dist","distz","pkg","bpk","dump","elc","deploy","exe","dll","deb","dmg","iso","img","msi","msp","msm","buffer"],"application/oda":["oda"],"application/oebps-package+xml":["opf"],"application/ogg":["ogx"],"application/omdoc+xml":["omdoc"],"application/onenote":["onetoc","onetoc2","onetmp","onepkg"],"application/oxps":["oxps"],"application/p2p-overlay+xml":["relo"],"application/patch-ops-error+xml":["*xer"],"application/pdf":["pdf"],"application/pgp-encrypted":["pgp"],"application/pgp-signature":["asc","sig"],"application/pics-rules":["prf"],"application/pkcs10":["p10"],"application/pkcs7-mime":["p7m","p7c"],"application/pkcs7-signature":["p7s"],"application/pkcs8":["p8"],"application/pkix-attr-cert":["ac"],"application/pkix-cert":["cer"],"application/pkix-crl":["crl"],"application/pkix-pkipath":["pkipath"],"application/pkixcmp":["pki"],"application/pls+xml":["pls"],"application/postscript":["ai","eps","ps"],"application/provenance+xml":["provx"],"application/pskc+xml":["pskcxml"],"application/raml+yaml":["raml"],"application/rdf+xml":["rdf","owl"],"application/reginfo+xml":["rif"],"application/relax-ng-compact-syntax":["rnc"],"application/resource-lists+xml":["rl"],"application/resource-lists-diff+xml":["rld"],"application/rls-services+xml":["rs"],"application/route-apd+xml":["rapd"],"application/route-s-tsid+xml":["sls"],"application/route-usd+xml":["rusd"],"application/rpki-ghostbusters":["gbr"],"application/rpki-manifest":["mft"],"application/rpki-roa":["roa"],"application/rsd+xml":["rsd"],"application/rss+xml":["rss"],"application/rtf":["rtf"],"application/sbml+xml":["sbml"],"application/scvp-cv-request":["scq"],"application/scvp-cv-response":["scs"],"application/scvp-vp-request":["spq"],"application/scvp-vp-response":["spp"],"application/sdp":["sdp"],"application/senml+xml":["senmlx"],"application/sensml+xml":["sensmlx"],"application/set-payment-initiation":["setpay"],"application/set-registration-initiation":["setreg"],"application/shf+xml":["shf"],"application/sieve":["siv","sieve"],"application/smil+xml":["smi","smil"],"application/sparql-query":["rq"],"application/sparql-results+xml":["srx"],"application/srgs":["gram"],"application/srgs+xml":["grxml"],"application/sru+xml":["sru"],"application/ssdl+xml":["ssdl"],"application/ssml+xml":["ssml"],"application/swid+xml":["swidtag"],"application/tei+xml":["tei","teicorpus"],"application/thraud+xml":["tfi"],"application/timestamped-data":["tsd"],"application/toml":["toml"],"application/ttml+xml":["ttml"],"application/urc-ressheet+xml":["rsheet"],"application/voicexml+xml":["vxml"],"application/wasm":["wasm"],"application/widget":["wgt"],"application/winhlp":["hlp"],"application/wsdl+xml":["wsdl"],"application/wspolicy+xml":["wspolicy"],"application/xaml+xml":["xaml"],"application/xcap-att+xml":["xav"],"application/xcap-caps+xml":["xca"],"application/xcap-diff+xml":["xdf"],"application/xcap-el+xml":["xel"],"application/xcap-error+xml":["xer"],"application/xcap-ns+xml":["xns"],"application/xenc+xml":["xenc"],"application/xhtml+xml":["xhtml","xht"],"application/xliff+xml":["xlf"],"application/xml":["xml","xsl","xsd","rng"],"application/xml-dtd":["dtd"],"application/xop+xml":["xop"],"application/xproc+xml":["xpl"],"application/xslt+xml":["xslt"],"application/xspf+xml":["xspf"],"application/xv+xml":["mxml","xhvml","xvml","xvm"],"application/yang":["yang"],"application/yin+xml":["yin"],"application/zip":["zip"],"audio/3gpp":["*3gpp"],"audio/adpcm":["adp"],"audio/basic":["au","snd"],"audio/midi":["mid","midi","kar","rmi"],"audio/mobile-xmf":["mxmf"],"audio/mp3":["*mp3"],"audio/mp4":["m4a","mp4a"],"audio/mpeg":["mpga","mp2","mp2a","mp3","m2a","m3a"],"audio/ogg":["oga","ogg","spx"],"audio/s3m":["s3m"],"audio/silk":["sil"],"audio/wav":["wav"],"audio/wave":["*wav"],"audio/webm":["weba"],"audio/xm":["xm"],"font/collection":["ttc"],"font/otf":["otf"],"font/ttf":["ttf"],"font/woff":["woff"],"font/woff2":["woff2"],"image/aces":["exr"],"image/apng":["apng"],"image/bmp":["bmp"],"image/cgm":["cgm"],"image/dicom-rle":["drle"],"image/emf":["emf"],"image/fits":["fits"],"image/g3fax":["g3"],"image/gif":["gif"],"image/heic":["heic"],"image/heic-sequence":["heics"],"image/heif":["heif"],"image/heif-sequence":["heifs"],"image/hej2k":["hej2"],"image/hsj2":["hsj2"],"image/ief":["ief"],"image/jls":["jls"],"image/jp2":["jp2","jpg2"],"image/jpeg":["jpeg","jpg","jpe"],"image/jph":["jph"],"image/jphc":["jhc"],"image/jpm":["jpm"],"image/jpx":["jpx","jpf"],"image/jxr":["jxr"],"image/jxra":["jxra"],"image/jxrs":["jxrs"],"image/jxs":["jxs"],"image/jxsc":["jxsc"],"image/jxsi":["jxsi"],"image/jxss":["jxss"],"image/ktx":["ktx"],"image/png":["png"],"image/sgi":["sgi"],"image/svg+xml":["svg","svgz"],"image/t38":["t38"],"image/tiff":["tif","tiff"],"image/tiff-fx":["tfx"],"image/webp":["webp"],"image/wmf":["wmf"],"message/disposition-notification":["disposition-notification"],"message/global":["u8msg"],"message/global-delivery-status":["u8dsn"],"message/global-disposition-notification":["u8mdn"],"message/global-headers":["u8hdr"],"message/rfc822":["eml","mime"],"model/3mf":["3mf"],"model/gltf+json":["gltf"],"model/gltf-binary":["glb"],"model/iges":["igs","iges"],"model/mesh":["msh","mesh","silo"],"model/mtl":["mtl"],"model/obj":["obj"],"model/stl":["stl"],"model/vrml":["wrl","vrml"],"model/x3d+binary":["*x3db","x3dbz"],"model/x3d+fastinfoset":["x3db"],"model/x3d+vrml":["*x3dv","x3dvz"],"model/x3d+xml":["x3d","x3dz"],"model/x3d-vrml":["x3dv"],"text/cache-manifest":["appcache","manifest"],"text/calendar":["ics","ifb"],"text/coffeescript":["coffee","litcoffee"],"text/css":["css"],"text/csv":["csv"],"text/html":["html","htm","shtml"],"text/jade":["jade"],"text/jsx":["jsx"],"text/less":["less"],"text/markdown":["markdown","md"],"text/mathml":["mml"],"text/mdx":["mdx"],"text/n3":["n3"],"text/plain":["txt","text","conf","def","list","log","in","ini"],"text/richtext":["rtx"],"text/rtf":["*rtf"],"text/sgml":["sgml","sgm"],"text/shex":["shex"],"text/slim":["slim","slm"],"text/stylus":["stylus","styl"],"text/tab-separated-values":["tsv"],"text/troff":["t","tr","roff","man","me","ms"],"text/turtle":["ttl"],"text/uri-list":["uri","uris","urls"],"text/vcard":["vcard"],"text/vtt":["vtt"],"text/xml":["*xml"],"text/yaml":["yaml","yml"],"video/3gpp":["3gp","3gpp"],"video/3gpp2":["3g2"],"video/h261":["h261"],"video/h263":["h263"],"video/h264":["h264"],"video/jpeg":["jpgv"],"video/jpm":["*jpm","jpgm"],"video/mj2":["mj2","mjp2"],"video/mp2t":["ts"],"video/mp4":["mp4","mp4v","mpg4"],"video/mpeg":["mpeg","mpg","mpe","m1v","m2v"],"video/ogg":["ogv"],"video/quicktime":["qt","mov"],"video/webm":["webm"]}; - -/***/ }), -/* 22 */ -/***/ (function(module, exports) { +var eachLimit = function (arr, limit, iterator, callback) { + callback = callback || function () {}; + if (!arr.length || limit <= 0) { + return callback(); + } -module.exports = {"application/prs.cww":["cww"],"application/vnd.1000minds.decision-model+xml":["1km"],"application/vnd.3gpp.pic-bw-large":["plb"],"application/vnd.3gpp.pic-bw-small":["psb"],"application/vnd.3gpp.pic-bw-var":["pvb"],"application/vnd.3gpp2.tcap":["tcap"],"application/vnd.3m.post-it-notes":["pwn"],"application/vnd.accpac.simply.aso":["aso"],"application/vnd.accpac.simply.imp":["imp"],"application/vnd.acucobol":["acu"],"application/vnd.acucorp":["atc","acutc"],"application/vnd.adobe.air-application-installer-package+zip":["air"],"application/vnd.adobe.formscentral.fcdt":["fcdt"],"application/vnd.adobe.fxp":["fxp","fxpl"],"application/vnd.adobe.xdp+xml":["xdp"],"application/vnd.adobe.xfdf":["xfdf"],"application/vnd.ahead.space":["ahead"],"application/vnd.airzip.filesecure.azf":["azf"],"application/vnd.airzip.filesecure.azs":["azs"],"application/vnd.amazon.ebook":["azw"],"application/vnd.americandynamics.acc":["acc"],"application/vnd.amiga.ami":["ami"],"application/vnd.android.package-archive":["apk"],"application/vnd.anser-web-certificate-issue-initiation":["cii"],"application/vnd.anser-web-funds-transfer-initiation":["fti"],"application/vnd.antix.game-component":["atx"],"application/vnd.apple.installer+xml":["mpkg"],"application/vnd.apple.keynote":["keynote"],"application/vnd.apple.mpegurl":["m3u8"],"application/vnd.apple.numbers":["numbers"],"application/vnd.apple.pages":["pages"],"application/vnd.apple.pkpass":["pkpass"],"application/vnd.aristanetworks.swi":["swi"],"application/vnd.astraea-software.iota":["iota"],"application/vnd.audiograph":["aep"],"application/vnd.balsamiq.bmml+xml":["bmml"],"application/vnd.blueice.multipass":["mpm"],"application/vnd.bmi":["bmi"],"application/vnd.businessobjects":["rep"],"application/vnd.chemdraw+xml":["cdxml"],"application/vnd.chipnuts.karaoke-mmd":["mmd"],"application/vnd.cinderella":["cdy"],"application/vnd.citationstyles.style+xml":["csl"],"application/vnd.claymore":["cla"],"application/vnd.cloanto.rp9":["rp9"],"application/vnd.clonk.c4group":["c4g","c4d","c4f","c4p","c4u"],"application/vnd.cluetrust.cartomobile-config":["c11amc"],"application/vnd.cluetrust.cartomobile-config-pkg":["c11amz"],"application/vnd.commonspace":["csp"],"application/vnd.contact.cmsg":["cdbcmsg"],"application/vnd.cosmocaller":["cmc"],"application/vnd.crick.clicker":["clkx"],"application/vnd.crick.clicker.keyboard":["clkk"],"application/vnd.crick.clicker.palette":["clkp"],"application/vnd.crick.clicker.template":["clkt"],"application/vnd.crick.clicker.wordbank":["clkw"],"application/vnd.criticaltools.wbs+xml":["wbs"],"application/vnd.ctc-posml":["pml"],"application/vnd.cups-ppd":["ppd"],"application/vnd.curl.car":["car"],"application/vnd.curl.pcurl":["pcurl"],"application/vnd.dart":["dart"],"application/vnd.data-vision.rdz":["rdz"],"application/vnd.dece.data":["uvf","uvvf","uvd","uvvd"],"application/vnd.dece.ttml+xml":["uvt","uvvt"],"application/vnd.dece.unspecified":["uvx","uvvx"],"application/vnd.dece.zip":["uvz","uvvz"],"application/vnd.denovo.fcselayout-link":["fe_launch"],"application/vnd.dna":["dna"],"application/vnd.dolby.mlp":["mlp"],"application/vnd.dpgraph":["dpg"],"application/vnd.dreamfactory":["dfac"],"application/vnd.ds-keypoint":["kpxx"],"application/vnd.dvb.ait":["ait"],"application/vnd.dvb.service":["svc"],"application/vnd.dynageo":["geo"],"application/vnd.ecowin.chart":["mag"],"application/vnd.enliven":["nml"],"application/vnd.epson.esf":["esf"],"application/vnd.epson.msf":["msf"],"application/vnd.epson.quickanime":["qam"],"application/vnd.epson.salt":["slt"],"application/vnd.epson.ssf":["ssf"],"application/vnd.eszigno3+xml":["es3","et3"],"application/vnd.ezpix-album":["ez2"],"application/vnd.ezpix-package":["ez3"],"application/vnd.fdf":["fdf"],"application/vnd.fdsn.mseed":["mseed"],"application/vnd.fdsn.seed":["seed","dataless"],"application/vnd.flographit":["gph"],"application/vnd.fluxtime.clip":["ftc"],"application/vnd.framemaker":["fm","frame","maker","book"],"application/vnd.frogans.fnc":["fnc"],"application/vnd.frogans.ltf":["ltf"],"application/vnd.fsc.weblaunch":["fsc"],"application/vnd.fujitsu.oasys":["oas"],"application/vnd.fujitsu.oasys2":["oa2"],"application/vnd.fujitsu.oasys3":["oa3"],"application/vnd.fujitsu.oasysgp":["fg5"],"application/vnd.fujitsu.oasysprs":["bh2"],"application/vnd.fujixerox.ddd":["ddd"],"application/vnd.fujixerox.docuworks":["xdw"],"application/vnd.fujixerox.docuworks.binder":["xbd"],"application/vnd.fuzzysheet":["fzs"],"application/vnd.genomatix.tuxedo":["txd"],"application/vnd.geogebra.file":["ggb"],"application/vnd.geogebra.tool":["ggt"],"application/vnd.geometry-explorer":["gex","gre"],"application/vnd.geonext":["gxt"],"application/vnd.geoplan":["g2w"],"application/vnd.geospace":["g3w"],"application/vnd.gmx":["gmx"],"application/vnd.google-apps.document":["gdoc"],"application/vnd.google-apps.presentation":["gslides"],"application/vnd.google-apps.spreadsheet":["gsheet"],"application/vnd.google-earth.kml+xml":["kml"],"application/vnd.google-earth.kmz":["kmz"],"application/vnd.grafeq":["gqf","gqs"],"application/vnd.groove-account":["gac"],"application/vnd.groove-help":["ghf"],"application/vnd.groove-identity-message":["gim"],"application/vnd.groove-injector":["grv"],"application/vnd.groove-tool-message":["gtm"],"application/vnd.groove-tool-template":["tpl"],"application/vnd.groove-vcard":["vcg"],"application/vnd.hal+xml":["hal"],"application/vnd.handheld-entertainment+xml":["zmm"],"application/vnd.hbci":["hbci"],"application/vnd.hhe.lesson-player":["les"],"application/vnd.hp-hpgl":["hpgl"],"application/vnd.hp-hpid":["hpid"],"application/vnd.hp-hps":["hps"],"application/vnd.hp-jlyt":["jlt"],"application/vnd.hp-pcl":["pcl"],"application/vnd.hp-pclxl":["pclxl"],"application/vnd.hydrostatix.sof-data":["sfd-hdstx"],"application/vnd.ibm.minipay":["mpy"],"application/vnd.ibm.modcap":["afp","listafp","list3820"],"application/vnd.ibm.rights-management":["irm"],"application/vnd.ibm.secure-container":["sc"],"application/vnd.iccprofile":["icc","icm"],"application/vnd.igloader":["igl"],"application/vnd.immervision-ivp":["ivp"],"application/vnd.immervision-ivu":["ivu"],"application/vnd.insors.igm":["igm"],"application/vnd.intercon.formnet":["xpw","xpx"],"application/vnd.intergeo":["i2g"],"application/vnd.intu.qbo":["qbo"],"application/vnd.intu.qfx":["qfx"],"application/vnd.ipunplugged.rcprofile":["rcprofile"],"application/vnd.irepository.package+xml":["irp"],"application/vnd.is-xpr":["xpr"],"application/vnd.isac.fcs":["fcs"],"application/vnd.jam":["jam"],"application/vnd.jcp.javame.midlet-rms":["rms"],"application/vnd.jisp":["jisp"],"application/vnd.joost.joda-archive":["joda"],"application/vnd.kahootz":["ktz","ktr"],"application/vnd.kde.karbon":["karbon"],"application/vnd.kde.kchart":["chrt"],"application/vnd.kde.kformula":["kfo"],"application/vnd.kde.kivio":["flw"],"application/vnd.kde.kontour":["kon"],"application/vnd.kde.kpresenter":["kpr","kpt"],"application/vnd.kde.kspread":["ksp"],"application/vnd.kde.kword":["kwd","kwt"],"application/vnd.kenameaapp":["htke"],"application/vnd.kidspiration":["kia"],"application/vnd.kinar":["kne","knp"],"application/vnd.koan":["skp","skd","skt","skm"],"application/vnd.kodak-descriptor":["sse"],"application/vnd.las.las+xml":["lasxml"],"application/vnd.llamagraphics.life-balance.desktop":["lbd"],"application/vnd.llamagraphics.life-balance.exchange+xml":["lbe"],"application/vnd.lotus-1-2-3":["123"],"application/vnd.lotus-approach":["apr"],"application/vnd.lotus-freelance":["pre"],"application/vnd.lotus-notes":["nsf"],"application/vnd.lotus-organizer":["org"],"application/vnd.lotus-screencam":["scm"],"application/vnd.lotus-wordpro":["lwp"],"application/vnd.macports.portpkg":["portpkg"],"application/vnd.mcd":["mcd"],"application/vnd.medcalcdata":["mc1"],"application/vnd.mediastation.cdkey":["cdkey"],"application/vnd.mfer":["mwf"],"application/vnd.mfmp":["mfm"],"application/vnd.micrografx.flo":["flo"],"application/vnd.micrografx.igx":["igx"],"application/vnd.mif":["mif"],"application/vnd.mobius.daf":["daf"],"application/vnd.mobius.dis":["dis"],"application/vnd.mobius.mbk":["mbk"],"application/vnd.mobius.mqy":["mqy"],"application/vnd.mobius.msl":["msl"],"application/vnd.mobius.plc":["plc"],"application/vnd.mobius.txf":["txf"],"application/vnd.mophun.application":["mpn"],"application/vnd.mophun.certificate":["mpc"],"application/vnd.mozilla.xul+xml":["xul"],"application/vnd.ms-artgalry":["cil"],"application/vnd.ms-cab-compressed":["cab"],"application/vnd.ms-excel":["xls","xlm","xla","xlc","xlt","xlw"],"application/vnd.ms-excel.addin.macroenabled.12":["xlam"],"application/vnd.ms-excel.sheet.binary.macroenabled.12":["xlsb"],"application/vnd.ms-excel.sheet.macroenabled.12":["xlsm"],"application/vnd.ms-excel.template.macroenabled.12":["xltm"],"application/vnd.ms-fontobject":["eot"],"application/vnd.ms-htmlhelp":["chm"],"application/vnd.ms-ims":["ims"],"application/vnd.ms-lrm":["lrm"],"application/vnd.ms-officetheme":["thmx"],"application/vnd.ms-outlook":["msg"],"application/vnd.ms-pki.seccat":["cat"],"application/vnd.ms-pki.stl":["*stl"],"application/vnd.ms-powerpoint":["ppt","pps","pot"],"application/vnd.ms-powerpoint.addin.macroenabled.12":["ppam"],"application/vnd.ms-powerpoint.presentation.macroenabled.12":["pptm"],"application/vnd.ms-powerpoint.slide.macroenabled.12":["sldm"],"application/vnd.ms-powerpoint.slideshow.macroenabled.12":["ppsm"],"application/vnd.ms-powerpoint.template.macroenabled.12":["potm"],"application/vnd.ms-project":["mpp","mpt"],"application/vnd.ms-word.document.macroenabled.12":["docm"],"application/vnd.ms-word.template.macroenabled.12":["dotm"],"application/vnd.ms-works":["wps","wks","wcm","wdb"],"application/vnd.ms-wpl":["wpl"],"application/vnd.ms-xpsdocument":["xps"],"application/vnd.mseq":["mseq"],"application/vnd.musician":["mus"],"application/vnd.muvee.style":["msty"],"application/vnd.mynfc":["taglet"],"application/vnd.neurolanguage.nlu":["nlu"],"application/vnd.nitf":["ntf","nitf"],"application/vnd.noblenet-directory":["nnd"],"application/vnd.noblenet-sealer":["nns"],"application/vnd.noblenet-web":["nnw"],"application/vnd.nokia.n-gage.ac+xml":["*ac"],"application/vnd.nokia.n-gage.data":["ngdat"],"application/vnd.nokia.n-gage.symbian.install":["n-gage"],"application/vnd.nokia.radio-preset":["rpst"],"application/vnd.nokia.radio-presets":["rpss"],"application/vnd.novadigm.edm":["edm"],"application/vnd.novadigm.edx":["edx"],"application/vnd.novadigm.ext":["ext"],"application/vnd.oasis.opendocument.chart":["odc"],"application/vnd.oasis.opendocument.chart-template":["otc"],"application/vnd.oasis.opendocument.database":["odb"],"application/vnd.oasis.opendocument.formula":["odf"],"application/vnd.oasis.opendocument.formula-template":["odft"],"application/vnd.oasis.opendocument.graphics":["odg"],"application/vnd.oasis.opendocument.graphics-template":["otg"],"application/vnd.oasis.opendocument.image":["odi"],"application/vnd.oasis.opendocument.image-template":["oti"],"application/vnd.oasis.opendocument.presentation":["odp"],"application/vnd.oasis.opendocument.presentation-template":["otp"],"application/vnd.oasis.opendocument.spreadsheet":["ods"],"application/vnd.oasis.opendocument.spreadsheet-template":["ots"],"application/vnd.oasis.opendocument.text":["odt"],"application/vnd.oasis.opendocument.text-master":["odm"],"application/vnd.oasis.opendocument.text-template":["ott"],"application/vnd.oasis.opendocument.text-web":["oth"],"application/vnd.olpc-sugar":["xo"],"application/vnd.oma.dd2+xml":["dd2"],"application/vnd.openblox.game+xml":["obgx"],"application/vnd.openofficeorg.extension":["oxt"],"application/vnd.openstreetmap.data+xml":["osm"],"application/vnd.openxmlformats-officedocument.presentationml.presentation":["pptx"],"application/vnd.openxmlformats-officedocument.presentationml.slide":["sldx"],"application/vnd.openxmlformats-officedocument.presentationml.slideshow":["ppsx"],"application/vnd.openxmlformats-officedocument.presentationml.template":["potx"],"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet":["xlsx"],"application/vnd.openxmlformats-officedocument.spreadsheetml.template":["xltx"],"application/vnd.openxmlformats-officedocument.wordprocessingml.document":["docx"],"application/vnd.openxmlformats-officedocument.wordprocessingml.template":["dotx"],"application/vnd.osgeo.mapguide.package":["mgp"],"application/vnd.osgi.dp":["dp"],"application/vnd.osgi.subsystem":["esa"],"application/vnd.palm":["pdb","pqa","oprc"],"application/vnd.pawaafile":["paw"],"application/vnd.pg.format":["str"],"application/vnd.pg.osasli":["ei6"],"application/vnd.picsel":["efif"],"application/vnd.pmi.widget":["wg"],"application/vnd.pocketlearn":["plf"],"application/vnd.powerbuilder6":["pbd"],"application/vnd.previewsystems.box":["box"],"application/vnd.proteus.magazine":["mgz"],"application/vnd.publishare-delta-tree":["qps"],"application/vnd.pvi.ptid1":["ptid"],"application/vnd.quark.quarkxpress":["qxd","qxt","qwd","qwt","qxl","qxb"],"application/vnd.realvnc.bed":["bed"],"application/vnd.recordare.musicxml":["mxl"],"application/vnd.recordare.musicxml+xml":["musicxml"],"application/vnd.rig.cryptonote":["cryptonote"],"application/vnd.rim.cod":["cod"],"application/vnd.rn-realmedia":["rm"],"application/vnd.rn-realmedia-vbr":["rmvb"],"application/vnd.route66.link66+xml":["link66"],"application/vnd.sailingtracker.track":["st"],"application/vnd.seemail":["see"],"application/vnd.sema":["sema"],"application/vnd.semd":["semd"],"application/vnd.semf":["semf"],"application/vnd.shana.informed.formdata":["ifm"],"application/vnd.shana.informed.formtemplate":["itp"],"application/vnd.shana.informed.interchange":["iif"],"application/vnd.shana.informed.package":["ipk"],"application/vnd.simtech-mindmapper":["twd","twds"],"application/vnd.smaf":["mmf"],"application/vnd.smart.teacher":["teacher"],"application/vnd.software602.filler.form+xml":["fo"],"application/vnd.solent.sdkm+xml":["sdkm","sdkd"],"application/vnd.spotfire.dxp":["dxp"],"application/vnd.spotfire.sfs":["sfs"],"application/vnd.stardivision.calc":["sdc"],"application/vnd.stardivision.draw":["sda"],"application/vnd.stardivision.impress":["sdd"],"application/vnd.stardivision.math":["smf"],"application/vnd.stardivision.writer":["sdw","vor"],"application/vnd.stardivision.writer-global":["sgl"],"application/vnd.stepmania.package":["smzip"],"application/vnd.stepmania.stepchart":["sm"],"application/vnd.sun.wadl+xml":["wadl"],"application/vnd.sun.xml.calc":["sxc"],"application/vnd.sun.xml.calc.template":["stc"],"application/vnd.sun.xml.draw":["sxd"],"application/vnd.sun.xml.draw.template":["std"],"application/vnd.sun.xml.impress":["sxi"],"application/vnd.sun.xml.impress.template":["sti"],"application/vnd.sun.xml.math":["sxm"],"application/vnd.sun.xml.writer":["sxw"],"application/vnd.sun.xml.writer.global":["sxg"],"application/vnd.sun.xml.writer.template":["stw"],"application/vnd.sus-calendar":["sus","susp"],"application/vnd.svd":["svd"],"application/vnd.symbian.install":["sis","sisx"],"application/vnd.syncml+xml":["xsm"],"application/vnd.syncml.dm+wbxml":["bdm"],"application/vnd.syncml.dm+xml":["xdm"],"application/vnd.syncml.dmddf+xml":["ddf"],"application/vnd.tao.intent-module-archive":["tao"],"application/vnd.tcpdump.pcap":["pcap","cap","dmp"],"application/vnd.tmobile-livetv":["tmo"],"application/vnd.trid.tpt":["tpt"],"application/vnd.triscape.mxs":["mxs"],"application/vnd.trueapp":["tra"],"application/vnd.ufdl":["ufd","ufdl"],"application/vnd.uiq.theme":["utz"],"application/vnd.umajin":["umj"],"application/vnd.unity":["unityweb"],"application/vnd.uoml+xml":["uoml"],"application/vnd.vcx":["vcx"],"application/vnd.visio":["vsd","vst","vss","vsw"],"application/vnd.visionary":["vis"],"application/vnd.vsf":["vsf"],"application/vnd.wap.wbxml":["wbxml"],"application/vnd.wap.wmlc":["wmlc"],"application/vnd.wap.wmlscriptc":["wmlsc"],"application/vnd.webturbo":["wtb"],"application/vnd.wolfram.player":["nbp"],"application/vnd.wordperfect":["wpd"],"application/vnd.wqd":["wqd"],"application/vnd.wt.stf":["stf"],"application/vnd.xara":["xar"],"application/vnd.xfdl":["xfdl"],"application/vnd.yamaha.hv-dic":["hvd"],"application/vnd.yamaha.hv-script":["hvs"],"application/vnd.yamaha.hv-voice":["hvp"],"application/vnd.yamaha.openscoreformat":["osf"],"application/vnd.yamaha.openscoreformat.osfpvg+xml":["osfpvg"],"application/vnd.yamaha.smaf-audio":["saf"],"application/vnd.yamaha.smaf-phrase":["spf"],"application/vnd.yellowriver-custom-menu":["cmp"],"application/vnd.zul":["zir","zirz"],"application/vnd.zzazz.deck+xml":["zaz"],"application/x-7z-compressed":["7z"],"application/x-abiword":["abw"],"application/x-ace-compressed":["ace"],"application/x-apple-diskimage":["*dmg"],"application/x-arj":["arj"],"application/x-authorware-bin":["aab","x32","u32","vox"],"application/x-authorware-map":["aam"],"application/x-authorware-seg":["aas"],"application/x-bcpio":["bcpio"],"application/x-bdoc":["*bdoc"],"application/x-bittorrent":["torrent"],"application/x-blorb":["blb","blorb"],"application/x-bzip":["bz"],"application/x-bzip2":["bz2","boz"],"application/x-cbr":["cbr","cba","cbt","cbz","cb7"],"application/x-cdlink":["vcd"],"application/x-cfs-compressed":["cfs"],"application/x-chat":["chat"],"application/x-chess-pgn":["pgn"],"application/x-chrome-extension":["crx"],"application/x-cocoa":["cco"],"application/x-conference":["nsc"],"application/x-cpio":["cpio"],"application/x-csh":["csh"],"application/x-debian-package":["*deb","udeb"],"application/x-dgc-compressed":["dgc"],"application/x-director":["dir","dcr","dxr","cst","cct","cxt","w3d","fgd","swa"],"application/x-doom":["wad"],"application/x-dtbncx+xml":["ncx"],"application/x-dtbook+xml":["dtb"],"application/x-dtbresource+xml":["res"],"application/x-dvi":["dvi"],"application/x-envoy":["evy"],"application/x-eva":["eva"],"application/x-font-bdf":["bdf"],"application/x-font-ghostscript":["gsf"],"application/x-font-linux-psf":["psf"],"application/x-font-pcf":["pcf"],"application/x-font-snf":["snf"],"application/x-font-type1":["pfa","pfb","pfm","afm"],"application/x-freearc":["arc"],"application/x-futuresplash":["spl"],"application/x-gca-compressed":["gca"],"application/x-glulx":["ulx"],"application/x-gnumeric":["gnumeric"],"application/x-gramps-xml":["gramps"],"application/x-gtar":["gtar"],"application/x-hdf":["hdf"],"application/x-httpd-php":["php"],"application/x-install-instructions":["install"],"application/x-iso9660-image":["*iso"],"application/x-java-archive-diff":["jardiff"],"application/x-java-jnlp-file":["jnlp"],"application/x-keepass2":["kdbx"],"application/x-latex":["latex"],"application/x-lua-bytecode":["luac"],"application/x-lzh-compressed":["lzh","lha"],"application/x-makeself":["run"],"application/x-mie":["mie"],"application/x-mobipocket-ebook":["prc","mobi"],"application/x-ms-application":["application"],"application/x-ms-shortcut":["lnk"],"application/x-ms-wmd":["wmd"],"application/x-ms-wmz":["wmz"],"application/x-ms-xbap":["xbap"],"application/x-msaccess":["mdb"],"application/x-msbinder":["obd"],"application/x-mscardfile":["crd"],"application/x-msclip":["clp"],"application/x-msdos-program":["*exe"],"application/x-msdownload":["*exe","*dll","com","bat","*msi"],"application/x-msmediaview":["mvb","m13","m14"],"application/x-msmetafile":["*wmf","*wmz","*emf","emz"],"application/x-msmoney":["mny"],"application/x-mspublisher":["pub"],"application/x-msschedule":["scd"],"application/x-msterminal":["trm"],"application/x-mswrite":["wri"],"application/x-netcdf":["nc","cdf"],"application/x-ns-proxy-autoconfig":["pac"],"application/x-nzb":["nzb"],"application/x-perl":["pl","pm"],"application/x-pilot":["*prc","*pdb"],"application/x-pkcs12":["p12","pfx"],"application/x-pkcs7-certificates":["p7b","spc"],"application/x-pkcs7-certreqresp":["p7r"],"application/x-rar-compressed":["rar"],"application/x-redhat-package-manager":["rpm"],"application/x-research-info-systems":["ris"],"application/x-sea":["sea"],"application/x-sh":["sh"],"application/x-shar":["shar"],"application/x-shockwave-flash":["swf"],"application/x-silverlight-app":["xap"],"application/x-sql":["sql"],"application/x-stuffit":["sit"],"application/x-stuffitx":["sitx"],"application/x-subrip":["srt"],"application/x-sv4cpio":["sv4cpio"],"application/x-sv4crc":["sv4crc"],"application/x-t3vm-image":["t3"],"application/x-tads":["gam"],"application/x-tar":["tar"],"application/x-tcl":["tcl","tk"],"application/x-tex":["tex"],"application/x-tex-tfm":["tfm"],"application/x-texinfo":["texinfo","texi"],"application/x-tgif":["*obj"],"application/x-ustar":["ustar"],"application/x-virtualbox-hdd":["hdd"],"application/x-virtualbox-ova":["ova"],"application/x-virtualbox-ovf":["ovf"],"application/x-virtualbox-vbox":["vbox"],"application/x-virtualbox-vbox-extpack":["vbox-extpack"],"application/x-virtualbox-vdi":["vdi"],"application/x-virtualbox-vhd":["vhd"],"application/x-virtualbox-vmdk":["vmdk"],"application/x-wais-source":["src"],"application/x-web-app-manifest+json":["webapp"],"application/x-x509-ca-cert":["der","crt","pem"],"application/x-xfig":["fig"],"application/x-xliff+xml":["*xlf"],"application/x-xpinstall":["xpi"],"application/x-xz":["xz"],"application/x-zmachine":["z1","z2","z3","z4","z5","z6","z7","z8"],"audio/vnd.dece.audio":["uva","uvva"],"audio/vnd.digital-winds":["eol"],"audio/vnd.dra":["dra"],"audio/vnd.dts":["dts"],"audio/vnd.dts.hd":["dtshd"],"audio/vnd.lucent.voice":["lvp"],"audio/vnd.ms-playready.media.pya":["pya"],"audio/vnd.nuera.ecelp4800":["ecelp4800"],"audio/vnd.nuera.ecelp7470":["ecelp7470"],"audio/vnd.nuera.ecelp9600":["ecelp9600"],"audio/vnd.rip":["rip"],"audio/x-aac":["aac"],"audio/x-aiff":["aif","aiff","aifc"],"audio/x-caf":["caf"],"audio/x-flac":["flac"],"audio/x-m4a":["*m4a"],"audio/x-matroska":["mka"],"audio/x-mpegurl":["m3u"],"audio/x-ms-wax":["wax"],"audio/x-ms-wma":["wma"],"audio/x-pn-realaudio":["ram","ra"],"audio/x-pn-realaudio-plugin":["rmp"],"audio/x-realaudio":["*ra"],"audio/x-wav":["*wav"],"chemical/x-cdx":["cdx"],"chemical/x-cif":["cif"],"chemical/x-cmdf":["cmdf"],"chemical/x-cml":["cml"],"chemical/x-csml":["csml"],"chemical/x-xyz":["xyz"],"image/prs.btif":["btif"],"image/prs.pti":["pti"],"image/vnd.adobe.photoshop":["psd"],"image/vnd.airzip.accelerator.azv":["azv"],"image/vnd.dece.graphic":["uvi","uvvi","uvg","uvvg"],"image/vnd.djvu":["djvu","djv"],"image/vnd.dvb.subtitle":["*sub"],"image/vnd.dwg":["dwg"],"image/vnd.dxf":["dxf"],"image/vnd.fastbidsheet":["fbs"],"image/vnd.fpx":["fpx"],"image/vnd.fst":["fst"],"image/vnd.fujixerox.edmics-mmr":["mmr"],"image/vnd.fujixerox.edmics-rlc":["rlc"],"image/vnd.microsoft.icon":["ico"],"image/vnd.ms-dds":["dds"],"image/vnd.ms-modi":["mdi"],"image/vnd.ms-photo":["wdp"],"image/vnd.net-fpx":["npx"],"image/vnd.tencent.tap":["tap"],"image/vnd.valve.source.texture":["vtf"],"image/vnd.wap.wbmp":["wbmp"],"image/vnd.xiff":["xif"],"image/vnd.zbrush.pcx":["pcx"],"image/x-3ds":["3ds"],"image/x-cmu-raster":["ras"],"image/x-cmx":["cmx"],"image/x-freehand":["fh","fhc","fh4","fh5","fh7"],"image/x-icon":["*ico"],"image/x-jng":["jng"],"image/x-mrsid-image":["sid"],"image/x-ms-bmp":["*bmp"],"image/x-pcx":["*pcx"],"image/x-pict":["pic","pct"],"image/x-portable-anymap":["pnm"],"image/x-portable-bitmap":["pbm"],"image/x-portable-graymap":["pgm"],"image/x-portable-pixmap":["ppm"],"image/x-rgb":["rgb"],"image/x-tga":["tga"],"image/x-xbitmap":["xbm"],"image/x-xpixmap":["xpm"],"image/x-xwindowdump":["xwd"],"message/vnd.wfa.wsc":["wsc"],"model/vnd.collada+xml":["dae"],"model/vnd.dwf":["dwf"],"model/vnd.gdl":["gdl"],"model/vnd.gtw":["gtw"],"model/vnd.mts":["mts"],"model/vnd.opengex":["ogex"],"model/vnd.parasolid.transmit.binary":["x_b"],"model/vnd.parasolid.transmit.text":["x_t"],"model/vnd.usdz+zip":["usdz"],"model/vnd.valve.source.compiled-map":["bsp"],"model/vnd.vtu":["vtu"],"text/prs.lines.tag":["dsc"],"text/vnd.curl":["curl"],"text/vnd.curl.dcurl":["dcurl"],"text/vnd.curl.mcurl":["mcurl"],"text/vnd.curl.scurl":["scurl"],"text/vnd.dvb.subtitle":["sub"],"text/vnd.fly":["fly"],"text/vnd.fmi.flexstor":["flx"],"text/vnd.graphviz":["gv"],"text/vnd.in3d.3dml":["3dml"],"text/vnd.in3d.spot":["spot"],"text/vnd.sun.j2me.app-descriptor":["jad"],"text/vnd.wap.wml":["wml"],"text/vnd.wap.wmlscript":["wmls"],"text/x-asm":["s","asm"],"text/x-c":["c","cc","cxx","cpp","h","hh","dic"],"text/x-component":["htc"],"text/x-fortran":["f","for","f77","f90"],"text/x-handlebars-template":["hbs"],"text/x-java-source":["java"],"text/x-lua":["lua"],"text/x-markdown":["mkd"],"text/x-nfo":["nfo"],"text/x-opml":["opml"],"text/x-org":["*org"],"text/x-pascal":["p","pas"],"text/x-processing":["pde"],"text/x-sass":["sass"],"text/x-scss":["scss"],"text/x-setext":["etx"],"text/x-sfv":["sfv"],"text/x-suse-ymp":["ymp"],"text/x-uuencode":["uu"],"text/x-vcalendar":["vcs"],"text/x-vcard":["vcf"],"video/vnd.dece.hd":["uvh","uvvh"],"video/vnd.dece.mobile":["uvm","uvvm"],"video/vnd.dece.pd":["uvp","uvvp"],"video/vnd.dece.sd":["uvs","uvvs"],"video/vnd.dece.video":["uvv","uvvv"],"video/vnd.dvb.file":["dvb"],"video/vnd.fvt":["fvt"],"video/vnd.mpegurl":["mxu","m4u"],"video/vnd.ms-playready.media.pyv":["pyv"],"video/vnd.uvvu.mp4":["uvu","uvvu"],"video/vnd.vivo":["viv"],"video/x-f4v":["f4v"],"video/x-fli":["fli"],"video/x-flv":["flv"],"video/x-m4v":["m4v"],"video/x-matroska":["mkv","mk3d","mks"],"video/x-mng":["mng"],"video/x-ms-asf":["asf","asx"],"video/x-ms-vob":["vob"],"video/x-ms-wm":["wm"],"video/x-ms-wmv":["wmv"],"video/x-ms-wmx":["wmx"],"video/x-ms-wvx":["wvx"],"video/x-msvideo":["avi"],"video/x-sgi-movie":["movie"],"video/x-smv":["smv"],"x-conference/x-cooltalk":["ice"]}; + var completed = 0; + var started = 0; + var running = 0; -/***/ }), -/* 23 */ -/***/ (function(module, exports, __webpack_require__) { + (function replenish () { + if (completed >= arr.length) { + return callback(); + } -var session = __webpack_require__(5); -var Async = __webpack_require__(24); -var EventProxy = __webpack_require__(4).EventProxy; -var util = __webpack_require__(0); - -// 文件分块上传全过程,暴露的分块上传接口 -function sliceUploadFile(params, callback) { - var self = this; - - // 如果小程序版本不支持获取文件分片内容,统一转到 postObject 接口上传 - if (!util.canFileSlice()) { - params.SkipTask = true; - self.postObject(params, callback); - return; - } - - var ep = new EventProxy(); - var TaskId = params.TaskId; - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var FilePath = params.FilePath; - var ChunkSize = params.ChunkSize || params.SliceSize || self.options.ChunkSize; - var AsyncLimit = params.AsyncLimit; - var StorageClass = params.StorageClass; - var ServerSideEncryption = params.ServerSideEncryption; - var FileSize; - - var onProgress; - var onHashProgress = params.onHashProgress; - - // 上传过程中出现错误,返回错误 - ep.on('error', function (err) { - if (!self._isRunningTask(TaskId)) return; - return callback(err); - }); - - // 上传分块完成,开始 uploadSliceComplete 操作 - ep.on('upload_complete', function (UploadCompleteData) { - callback(null, UploadCompleteData); - }); - - // 上传分块完成,开始 uploadSliceComplete 操作 - ep.on('upload_slice_complete', function (UploadData) { - uploadSliceComplete.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key, - UploadId: UploadData.UploadId, - SliceList: UploadData.SliceList, - }, function (err, data) { - if (!self._isRunningTask(TaskId)) return; - session.removeUsing(UploadData.UploadId); - if (err) { - onProgress(null, true); - return ep.emit('error', err); - } - session.removeUploadId(UploadData.UploadId); - onProgress({loaded: FileSize, total: FileSize}, true); - ep.emit('upload_complete', data); - }); - }); - - // 获取 UploadId 完成,开始上传每个分片 - ep.on('get_upload_data_finish', function (UploadData) { - - // 处理 UploadId 缓存 - var uuid = session.getFileId(params.FileStat, params.ChunkSize, Bucket, Key); - uuid && session.saveUploadId(uuid, UploadData.UploadId, self.options.UploadIdCacheLimit); // 缓存 UploadId - session.setUsing(UploadData.UploadId); // 标记 UploadId 为正在使用 - - // 获取 UploadId - onProgress(null, true); // 任务状态开始 uploading - uploadSliceList.call(self, { - TaskId: TaskId, - Bucket: Bucket, - Region: Region, - Key: Key, - FilePath: FilePath, - FileSize: FileSize, - SliceSize: ChunkSize, - AsyncLimit: AsyncLimit, - ServerSideEncryption: ServerSideEncryption, - UploadData: UploadData, - onProgress: onProgress - }, function (err, data) { - if (!self._isRunningTask(TaskId)) return; - if (err) { - onProgress(null, true); - return ep.emit('error', err); - } - ep.emit('upload_slice_complete', data); - }); - }); - - // 开始获取文件 UploadId,里面会视情况计算 ETag,并比对,保证文件一致性,也优化上传 - ep.on('get_file_size_finish', function () { - - onProgress = util.throttleOnProgress.call(self, FileSize, params.onProgress); - - if (params.UploadData.UploadId) { - ep.emit('get_upload_data_finish', params.UploadData); - } else { - var _params = util.extend({ - TaskId: TaskId, - Bucket: Bucket, - Region: Region, - Key: Key, - Headers: params.Headers, - StorageClass: StorageClass, - FilePath: FilePath, - FileSize: FileSize, - SliceSize: ChunkSize, - onHashProgress: onHashProgress, - }, params); - getUploadIdAndPartList.call(self, _params, function (err, UploadData) { - if (!self._isRunningTask(TaskId)) return; - if (err) return ep.emit('error', err); - params.UploadData.UploadId = UploadData.UploadId; - params.UploadData.PartList = UploadData.PartList; - ep.emit('get_upload_data_finish', params.UploadData); - }); - } - }); - - // 获取上传文件大小 - FileSize = params.ContentLength; - delete params.ContentLength; - !params.Headers && (params.Headers = {}); - util.each(params.Headers, function (item, key) { - if (key.toLowerCase() === 'content-length') { - delete params.Headers[key]; - } - }); - - // 控制分片大小 - (function () { - var SIZE = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 1024 * 2, 1024 * 4, 1024 * 5]; - var AutoChunkSize = 1024 * 1024; - for (var i = 0; i < SIZE.length; i++) { - AutoChunkSize = SIZE[i] * 1024 * 1024; - if (FileSize / AutoChunkSize <= self.options.MaxPartNumber) break; - } - params.ChunkSize = params.SliceSize = ChunkSize = Math.max(ChunkSize, AutoChunkSize); - })(); - - // 开始上传 - if (FileSize === 0) { - params.Body = ''; - params.ContentLength = 0; - params.SkipTask = true; - self.putObject(params, function (err, data) { - if (err) { - return callback(err); - } - callback(null, data); - }); - } else { - ep.emit('get_file_size_finish'); - } - -} - -// 获取上传任务的 UploadId -function getUploadIdAndPartList(params, callback) { - var TaskId = params.TaskId; - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var StorageClass = params.StorageClass; - var self = this; - - // 计算 ETag - var ETagMap = {}; - var FileSize = params.FileSize; - var SliceSize = params.SliceSize; - var SliceCount = Math.ceil(FileSize / SliceSize); - var FinishSliceCount = 0; - var FinishSize = 0; - var onHashProgress = util.throttleOnProgress.call(self, FileSize, params.onHashProgress); - var getChunkETag = function (PartNumber, callback) { - var start = SliceSize * (PartNumber - 1); - var end = Math.min(start + SliceSize, FileSize); - var ChunkSize = end - start; - - if (ETagMap[PartNumber]) { - callback(null, { - PartNumber: PartNumber, - ETag: ETagMap[PartNumber], - Size: ChunkSize - }); - } else { - util.fileSlice(params.FilePath, start, end, function (chunkItem) { - try { - var md5 = util.getFileMd5(chunkItem); - } catch (err) { - return callback(err); - } - var ETag = '"' + md5 + '"'; - ETagMap[PartNumber] = ETag; - FinishSliceCount += 1; - FinishSize += ChunkSize; - callback(null, { - PartNumber: PartNumber, - ETag: ETag, - Size: ChunkSize - }); - onHashProgress({loaded: FinishSize, total: FileSize}); - }); - } - }; - - // 通过和文件的 md5 对比,判断 UploadId 是否可用 - var isAvailableUploadList = function (PartList, callback) { - var PartCount = PartList.length; - // 如果没有分片,通过 - if (PartCount === 0) { - return callback(null, true); - } - // 检查分片数量 - if (PartCount > SliceCount) { - return callback(null, false); - } - // 检查分片大小 - if (PartCount > 1) { - var PartSliceSize = Math.max(PartList[0].Size, PartList[1].Size); - if (PartSliceSize !== SliceSize) { - return callback(null, false); - } - } - // 逐个分片计算并检查 ETag 是否一致 - var next = function (index) { - if (index < PartCount) { - var Part = PartList[index]; - getChunkETag(Part.PartNumber, function (err, chunk) { - if (chunk && chunk.ETag === Part.ETag && chunk.Size === Part.Size) { - next(index + 1); - } else { - callback(null, false); - } - }); - } else { - callback(null, true); - } - }; - next(0); - }; - - var ep = new EventProxy(); - ep.on('error', function (errData) { - if (!self._isRunningTask(TaskId)) return; - return callback(errData); - }); - - // 存在 UploadId - ep.on('upload_id_available', function (UploadData) { - // 转换成 map - var map = {}; - var list = []; - util.each(UploadData.PartList, function (item) { - map[item.PartNumber] = item; - }); - for (var PartNumber = 1; PartNumber <= SliceCount; PartNumber++) { - var item = map[PartNumber]; - if (item) { - item.PartNumber = PartNumber; - item.Uploaded = true; - } else { - item = { - PartNumber: PartNumber, - ETag: null, - Uploaded: false - }; - } - list.push(item); - } - UploadData.PartList = list; - callback(null, UploadData); - }); - - // 不存在 UploadId, 初始化生成 UploadId - ep.on('no_available_upload_id', function () { - if (!self._isRunningTask(TaskId)) return; - var _params = util.extend({ - Bucket: Bucket, - Region: Region, - Key: Key, - Headers: util.clone(params.Headers), - Query: util.clone(params.Query), - StorageClass: StorageClass, - }, params); - self.multipartInit(_params, function (err, data) { - if (!self._isRunningTask(TaskId)) return; - if (err) return ep.emit('error', err); - var UploadId = data.UploadId; - if (!UploadId) { - return callback({Message: 'no upload id'}); - } - ep.emit('upload_id_available', {UploadId: UploadId, PartList: []}); - }); - }); - - // 如果已存在 UploadId,找一个可以用的 UploadId - ep.on('has_and_check_upload_id', function (UploadIdList) { - // 串行地,找一个内容一致的 UploadId - UploadIdList = UploadIdList.reverse(); - Async.eachLimit(UploadIdList, 1, function (UploadId, asyncCallback) { - if (!self._isRunningTask(TaskId)) return; - // 如果正在上传,跳过 - if (session.using[UploadId]) { - asyncCallback(); // 检查下一个 UploadId - return; - } - // 判断 UploadId 是否可用 - wholeMultipartListPart.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key, - UploadId: UploadId, - }, function (err, PartListData) { - if (!self._isRunningTask(TaskId)) return; - if (err) { - session.removeUsing(UploadId); - return ep.emit('error', err); - } - var PartList = PartListData.PartList; - PartList.forEach(function (item) { - item.PartNumber *= 1; - item.Size *= 1; - item.ETag = item.ETag || ''; - }); - isAvailableUploadList(PartList, function (err, isAvailable) { - if (!self._isRunningTask(TaskId)) return; - if (err) return ep.emit('error', err); - if (isAvailable) { - asyncCallback({ - UploadId: UploadId, - PartList: PartList - }); // 马上结束 - } else { - asyncCallback(); // 检查下一个 UploadId - } - }); - }); - }, function (AvailableUploadData) { - if (!self._isRunningTask(TaskId)) return; - onHashProgress(null, true); - if (AvailableUploadData && AvailableUploadData.UploadId) { - ep.emit('upload_id_available', AvailableUploadData); - } else { - ep.emit('no_available_upload_id'); - } - }); - }); - - // 在本地缓存找可用的 UploadId - ep.on('seek_local_avail_upload_id', function (RemoteUploadIdList) { - // 在本地找可用的 UploadId - var uuid = session.getFileId(params.FileStat, params.ChunkSize, Bucket, Key); - var LocalUploadIdList = session.getUploadIdList(uuid); - if (!uuid || !LocalUploadIdList) { - ep.emit('has_and_check_upload_id', RemoteUploadIdList); - return; - } - var next = function (index) { - // 如果本地找不到可用 UploadId,再一个个遍历校验远端 - if (index >= LocalUploadIdList.length) { - ep.emit('has_and_check_upload_id', RemoteUploadIdList); - return; - } - var UploadId = LocalUploadIdList[index]; - // 如果不在远端 UploadId 列表里,跳过并删除 - if (!util.isInArray(RemoteUploadIdList, UploadId)) { - session.removeUploadId(UploadId); - next(index + 1); - return; - } - // 如果正在上传,跳过 - if (session.using[UploadId]) { - next(index + 1); - return; - } - // 判断 UploadId 是否存在线上 - wholeMultipartListPart.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key, - UploadId: UploadId, - }, function (err, PartListData) { - if (!self._isRunningTask(TaskId)) return; - if (err) { - // 如果 UploadId 获取会出错,跳过并删除 - session.removeUploadId(UploadId); - next(index + 1); - } else { - // 找到可用 UploadId - ep.emit('upload_id_available', { - UploadId: UploadId, - PartList: PartListData.PartList, - }); - } - }); - }; - next(0); - }); - - // 获取线上 UploadId 列表 - ep.on('get_remote_upload_id_list', function () { - // 获取符合条件的 UploadId 列表,因为同一个文件可以有多个上传任务。 - wholeMultipartList.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key, - }, function (err, data) { - if (!self._isRunningTask(TaskId)) return; - if (err) { - return ep.emit('error', err); - } - // 整理远端 UploadId 列表 - var RemoteUploadIdList = util.filter(data.UploadList, function (item) { - return item.Key === Key && (!StorageClass || item.StorageClass.toUpperCase() === StorageClass.toUpperCase()); - }).reverse().map(function (item) { - return item.UploadId || item.UploadID; - }); - if (RemoteUploadIdList.length) { - ep.emit('seek_local_avail_upload_id', RemoteUploadIdList); - } else { - // 远端没有 UploadId,清理缓存的 UploadId - var uuid = session.getFileId(params.FileStat, params.ChunkSize, Bucket, Key), LocalUploadIdList; - if (uuid && (LocalUploadIdList = session.getUploadIdList(uuid))) { - util.each(LocalUploadIdList, function (UploadId) { - session.removeUploadId(UploadId); - }); - } - ep.emit('no_available_upload_id'); - } - }); - }); - - // 开始找可用 UploadId - ep.emit('get_remote_upload_id_list'); - -} - -// 获取符合条件的全部上传任务 (条件包括 Bucket, Region, Prefix) -function wholeMultipartList(params, callback) { - var self = this; - var UploadList = []; - var sendParams = { - Bucket: params.Bucket, - Region: params.Region, - Prefix: params.Key - }; - var next = function () { - self.multipartList(sendParams, function (err, data) { - if (err) return callback(err); - UploadList.push.apply(UploadList, data.Upload || []); - if (data.IsTruncated === 'true') { // 列表不完整 - sendParams.KeyMarker = data.NextKeyMarker; - sendParams.UploadIdMarker = data.NextUploadIdMarker; - next(); - } else { - callback(null, {UploadList: UploadList}); - } - }); - }; - next(); -} - -// 获取指定上传任务的分块列表 -function wholeMultipartListPart(params, callback) { - var self = this; - var PartList = []; - var sendParams = { - Bucket: params.Bucket, - Region: params.Region, - Key: params.Key, - UploadId: params.UploadId - }; - var next = function () { - self.multipartListPart(sendParams, function (err, data) { - if (err) return callback(err); - PartList.push.apply(PartList, data.Part || []); - if (data.IsTruncated === 'true') { // 列表不完整 - sendParams.PartNumberMarker = data.NextPartNumberMarker; - next(); - } else { - callback(null, {PartList: PartList}); - } - }); - }; - next(); -} - -// 上传文件分块,包括 -/* - UploadId (上传任务编号) - AsyncLimit (并发量), - SliceList (上传的分块数组), - FilePath (本地文件的位置), - SliceSize (文件分块大小) - FileSize (文件大小) - onProgress (上传成功之后的回调函数) - */ -function uploadSliceList(params, cb) { - var self = this; - var TaskId = params.TaskId; - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var UploadData = params.UploadData; - var FileSize = params.FileSize; - var SliceSize = params.SliceSize; - var ChunkParallel = Math.min(params.AsyncLimit || self.options.ChunkParallelLimit || 1, 256); - var FilePath = params.FilePath; - var SliceCount = Math.ceil(FileSize / SliceSize); - var FinishSize = 0; - var ServerSideEncryption = params.ServerSideEncryption; - var needUploadSlices = util.filter(UploadData.PartList, function (SliceItem) { - if (SliceItem['Uploaded']) { - FinishSize += SliceItem['PartNumber'] >= SliceCount ? (FileSize % SliceSize || SliceSize) : SliceSize; - } - return !SliceItem['Uploaded']; - }); - var onProgress = params.onProgress; - - Async.eachLimit(needUploadSlices, ChunkParallel, function (SliceItem, asyncCallback) { - if (!self._isRunningTask(TaskId)) return; - var PartNumber = SliceItem['PartNumber']; - var currentSize = Math.min(FileSize, SliceItem['PartNumber'] * SliceSize) - (SliceItem['PartNumber'] - 1) * SliceSize; - var preAddSize = 0; - uploadSliceItem.call(self, { - TaskId: TaskId, - Bucket: Bucket, - Region: Region, - Key: Key, - SliceSize: SliceSize, - FileSize: FileSize, - PartNumber: PartNumber, - ServerSideEncryption: ServerSideEncryption, - FilePath: FilePath, - UploadData: UploadData, - onProgress: function (data) { - FinishSize += data.loaded - preAddSize; - preAddSize = data.loaded; - onProgress({loaded: FinishSize, total: FileSize}); - }, - }, function (err, data) { - if (!self._isRunningTask(TaskId)) return; - if (err) { - FinishSize -= preAddSize; - } else { - FinishSize += currentSize - preAddSize; - SliceItem.ETag = data.ETag; - } - onProgress({loaded: FinishSize, total: FileSize}); - asyncCallback(err || null, data); - }); - }, function (err) { - if (!self._isRunningTask(TaskId)) return; - if (err) return cb(err); - cb(null, { - UploadId: UploadData.UploadId, - SliceList: UploadData.PartList - }); - }); -} - -// 上传指定分片 -function uploadSliceItem(params, callback) { - var self = this; - var TaskId = params.TaskId; - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var FileSize = params.FileSize; - var FilePath = params.FilePath; - var PartNumber = params.PartNumber * 1; - var SliceSize = params.SliceSize; - var ServerSideEncryption = params.ServerSideEncryption; - var UploadData = params.UploadData; - var ChunkRetryTimes = self.options.ChunkRetryTimes + 1; - - var start = SliceSize * (PartNumber - 1); - - var ContentLength = SliceSize; - - var end = start + SliceSize; - - if (end > FileSize) { - end = FileSize; - ContentLength = end - start; - } - - util.fileSlice(FilePath, start, end, function (Body) { - var md5 = util.getFileMd5(Body); - var contentMd5 = md5 ? util.binaryBase64(md5) : null; - var PartItem = UploadData.PartList[PartNumber - 1]; - Async.retry(ChunkRetryTimes, function (tryCallback) { - if (!self._isRunningTask(TaskId)) return; - self.multipartUpload({ - TaskId: TaskId, - Bucket: Bucket, - Region: Region, - Key: Key, - ContentLength: ContentLength, - PartNumber: PartNumber, - UploadId: UploadData.UploadId, - ServerSideEncryption: ServerSideEncryption, - Body: Body, - onProgress: params.onProgress, - ContentMD5: contentMd5, - }, function (err, data) { - if (!self._isRunningTask(TaskId)) return; - if (err) { - return tryCallback(err); - } else { - PartItem.Uploaded = true; - return tryCallback(null, data); - } - }); - }, function (err, data) { - if (!self._isRunningTask(TaskId)) return; - return callback(err, data); - }); - }); -} - - -// 完成分块上传 -function uploadSliceComplete(params, callback) { - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var UploadId = params.UploadId; - var SliceList = params.SliceList; - var self = this; - var ChunkRetryTimes = this.options.ChunkRetryTimes + 1; - var Parts = SliceList.map(function (item) { - return { - PartNumber: item.PartNumber, - ETag: item.ETag - }; - }); - // 完成上传的请求也做重试 - Async.retry(ChunkRetryTimes, function (tryCallback) { - self.multipartComplete({ - Bucket: Bucket, - Region: Region, - Key: Key, - UploadId: UploadId, - Parts: Parts - }, tryCallback); - }, function (err, data) { - callback(err, data); - }); -} - -// 抛弃分块上传任务 -/* - AsyncLimit (抛弃上传任务的并发量), - UploadId (上传任务的编号,当 Level 为 task 时候需要) - Level (抛弃分块上传任务的级别,task : 抛弃指定的上传任务,file : 抛弃指定的文件对应的上传任务,其他值 :抛弃指定Bucket 的全部上传任务) - */ -function abortUploadTask(params, callback) { - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var UploadId = params.UploadId; - var Level = params.Level || 'task'; - var AsyncLimit = params.AsyncLimit; - var self = this; - - var ep = new EventProxy(); - - ep.on('error', function (errData) { - return callback(errData); - }); - - // 已经获取到需要抛弃的任务列表 - ep.on('get_abort_array', function (AbortArray) { - abortUploadTaskArray.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key, - Headers: params.Headers, - AsyncLimit: AsyncLimit, - AbortArray: AbortArray - }, function (err, data) { - if (err) { - return callback(err); - } - callback(null, data); - }); - }); - - if (Level === 'bucket') { - // Bucket 级别的任务抛弃,抛弃该 Bucket 下的全部上传任务 - wholeMultipartList.call(self, { - Bucket: Bucket, - Region: Region - }, function (err, data) { - if (err) { - return callback(err); - } - ep.emit('get_abort_array', data.UploadList || []); - }); - } else if (Level === 'file') { - // 文件级别的任务抛弃,抛弃该文件的全部上传任务 - if (!Key) return callback({error: 'abort_upload_task_no_key'}); - wholeMultipartList.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key - }, function (err, data) { - if (err) { - return callback(err); - } - ep.emit('get_abort_array', data.UploadList || []); - }); - } else if (Level === 'task') { - // 单个任务级别的任务抛弃,抛弃指定 UploadId 的上传任务 - if (!UploadId) return callback({error: 'abort_upload_task_no_id'}); - if (!Key) return callback({error: 'abort_upload_task_no_key'}); - ep.emit('get_abort_array', [{ - Key: Key, - UploadId: UploadId - }]); - } else { - return callback({error: 'abort_unknown_level'}); - } -} - -// 批量抛弃分块上传任务 -function abortUploadTaskArray(params, callback) { - - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var AbortArray = params.AbortArray; - var AsyncLimit = params.AsyncLimit || 1; - var self = this; - - var index = 0; - var resultList = new Array(AbortArray.length); - Async.eachLimit(AbortArray, AsyncLimit, function (AbortItem, callback) { - var eachIndex = index; - if (Key && Key !== AbortItem.Key) { - resultList[eachIndex] = {error: {KeyNotMatch: true}}; - callback(null); - return; - } - var UploadId = AbortItem.UploadId || AbortItem.UploadID; - - self.multipartAbort({ - Bucket: Bucket, - Region: Region, - Key: AbortItem.Key, - Headers: params.Headers, - UploadId: UploadId - }, function (err) { - var task = { - Bucket: Bucket, - Region: Region, - Key: AbortItem.Key, - UploadId: UploadId - }; - resultList[eachIndex] = {error: err, task: task}; - callback(null); - }); - index++; - - }, function (err) { - if (err) { - return callback(err); - } - - var successList = []; - var errorList = []; - - for (var i = 0, len = resultList.length; i < len; i++) { - var item = resultList[i]; - if (item['task']) { - if (item['error']) { - errorList.push(item['task']); - } else { - successList.push(item['task']); - } - } - } - - return callback(null, { - successList: successList, - errorList: errorList - }); - }); -} - - -// 批量上传文件 -function uploadFiles(params, callback) { - var self = this; - - // 判断多大的文件使用分片上传 - var SliceSize = params.SliceSize === undefined ? self.options.SliceSize : params.SliceSize; - - // 汇总返回进度 - var TotalSize = 0; - var TotalFinish = 0; - var onTotalProgress = util.throttleOnProgress.call(self, TotalFinish, params.onProgress); - - // 汇总返回回调 - var unFinishCount = params.files.length; - var _onTotalFileFinish = params.onFileFinish; - var resultList = Array(unFinishCount); - var onTotalFileFinish = function (err, data, options) { - onTotalProgress(null, true); - _onTotalFileFinish && _onTotalFileFinish(err, data, options); - resultList[options.Index] = { - options: options, - error: err, - data: data - }; - if (--unFinishCount <= 0 && callback) { - callback(null, { - files: resultList, - }); - } - }; - - // 开始处理每个文件 - var taskList = []; - util.each(params.files, function (fileParams, index) { - var FileSize = fileParams.FileSize; - var fileInfo = {Index: index, TaskId: ''}; - - // 更新文件总大小 - TotalSize += FileSize; - - // 整理 option,用于返回给回调 - util.each(fileParams, function (v, k) { - if (typeof v !== 'object' && typeof v !== 'function') { - fileInfo[k] = v; - } - }); - - // 处理单个文件 TaskReady - var _onTaskReady = fileParams.onTaskReady; - fileParams.onTaskReady = function (tid) { - fileInfo.TaskId = tid; - _onTaskReady && _onTaskReady(tid); - }; - - // 处理单个文件进度 - var PreAddSize = 0; - var _onProgress = fileParams.onProgress; - fileParams.onProgress = function (info) { - TotalFinish = TotalFinish - PreAddSize + info.loaded; - PreAddSize = info.loaded; - _onProgress && _onProgress(info); - onTotalProgress({loaded: TotalFinish, total: TotalSize}); - }; - - // 处理单个文件完成 - var _onFileFinish = fileParams.onFileFinish; - var onFileFinish = function (err, data) { - _onFileFinish && _onFileFinish(err, data); - onTotalFileFinish && onTotalFileFinish(err, data, fileInfo); - }; - - // 添加上传任务 - var api = FileSize > SliceSize ? 'sliceUploadFile' : 'postObject'; - taskList.push({ - api: api, - params: fileParams, - callback: onFileFinish, - }); - }); - self._addTasks(taskList); -} - -// 分片复制文件 -function sliceCopyFile(params, callback) { - var ep = new EventProxy(); - - var self = this; - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var CopySource = params.CopySource; - var m = CopySource.match(/^([^.]+-\d+)\.cos(v6)?\.([^.]+)\.[^/]+\/(.+)$/); - if (!m) { - callback({error: 'CopySource format error'}); - return; - } - - var SourceBucket = m[1]; - var SourceRegion = m[3]; - var SourceKey = decodeURIComponent(m[4]); - var CopySliceSize = params.CopySliceSize === undefined ? self.options.CopySliceSize : params.CopySliceSize; - CopySliceSize = Math.max(0, CopySliceSize); - - var ChunkSize = params.CopyChunkSize || this.options.CopyChunkSize; - var ChunkParallel = this.options.CopyChunkParallelLimit; - - var FinishSize = 0; - var FileSize; - var onProgress; - - // 分片复制完成,开始 multipartComplete 操作 - ep.on('copy_slice_complete', function (UploadData) { - self.multipartComplete({ - Bucket: Bucket, - Region: Region, - Key: Key, - UploadId: UploadData.UploadId, - Parts: UploadData.PartList, - },function (err, data) { - if (err) { - onProgress(null, true); - return callback(err); - } - onProgress({loaded: FileSize, total: FileSize}, true); - callback(null, data); - }); - }); - - ep.on('get_copy_data_finish',function (UploadData) { - Async.eachLimit(UploadData.PartList, ChunkParallel, function (SliceItem, asyncCallback) { - var PartNumber = SliceItem.PartNumber; - var CopySourceRange = SliceItem.CopySourceRange; - var currentSize = SliceItem.end - SliceItem.start; - var preAddSize = 0; - - copySliceItem.call(self, { - Bucket: Bucket, - Region: Region, - Key: Key, - CopySource: CopySource, - UploadId: UploadData.UploadId, - PartNumber: PartNumber, - CopySourceRange: CopySourceRange, - onProgress: function (data) { - FinishSize += data.loaded - preAddSize; - preAddSize = data.loaded; - onProgress({loaded: FinishSize, total: FileSize}); - } - },function (err,data) { - if (err) { - return asyncCallback(err); - } - onProgress({loaded: FinishSize, total: FileSize}); - - FinishSize += currentSize - preAddSize; - SliceItem.ETag = data.ETag; - asyncCallback(err || null, data); - }); - }, function (err) { - if (err) { - onProgress(null, true); - return callback(err); - } - - ep.emit('copy_slice_complete', UploadData); - }); - }); - - ep.on('get_file_size_finish', function (SourceHeaders) { - // 控制分片大小 - (function () { - var SIZE = [1, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024, 1024 * 2, 1024 * 4, 1024 * 5]; - var AutoChunkSize = 1024 * 1024; - for (var i = 0; i < SIZE.length; i++) { - AutoChunkSize = SIZE[i] * 1024 * 1024; - if (FileSize / AutoChunkSize <= self.options.MaxPartNumber) break; - } - params.ChunkSize = ChunkSize = Math.max(ChunkSize, AutoChunkSize); - - var ChunkCount = Math.ceil(FileSize / ChunkSize); - - var list = []; - for (var partNumber = 1; partNumber <= ChunkCount; partNumber++) { - var start = (partNumber - 1) * ChunkSize; - var end = partNumber * ChunkSize < FileSize ? (partNumber * ChunkSize - 1) : FileSize - 1; - var item = { - PartNumber: partNumber, - start: start, - end: end, - CopySourceRange: "bytes=" + start + "-" + end, - }; - list.push(item); - } - params.PartList = list; - })(); - - var TargetHeader; - if (params.Headers['x-cos-metadata-directive'] === 'Replaced') { - TargetHeader = params.Headers; - } else { - TargetHeader = SourceHeaders; - } - TargetHeader['x-cos-storage-class'] = params.Headers['x-cos-storage-class'] || SourceHeaders['x-cos-storage-class']; - TargetHeader = util.clearKey(TargetHeader); - /** - * 对于归档存储的对象,如果未恢复副本,则不允许 Copy - */ - if (SourceHeaders['x-cos-storage-class'] === 'ARCHIVE' || SourceHeaders['x-cos-storage-class'] === 'DEEP_ARCHIVE') { - var restoreHeader = SourceHeaders['x-cos-restore']; - if (!restoreHeader || restoreHeader === 'ongoing-request="true"') { - callback({ error: 'Unrestored archive object is not allowed to be copied' }); - return; - } - } - /** - * 去除一些无用的头部,规避 multipartInit 出错 - * 这些头部通常是在 putObjectCopy 时才使用 - */ - delete TargetHeader['x-cos-copy-source']; - delete TargetHeader['x-cos-metadata-directive']; - delete TargetHeader['x-cos-copy-source-If-Modified-Since']; - delete TargetHeader['x-cos-copy-source-If-Unmodified-Since']; - delete TargetHeader['x-cos-copy-source-If-Match']; - delete TargetHeader['x-cos-copy-source-If-None-Match']; - self.multipartInit({ - Bucket: Bucket, - Region: Region, - Key: Key, - Headers: TargetHeader, - },function (err,data) { - if (err) { - return callback(err); - } - params.UploadId = data.UploadId; - ep.emit('get_copy_data_finish', params); - }); - }); - - // 获取远端复制源文件的大小 - self.headObject({ - Bucket: SourceBucket, - Region: SourceRegion, - Key: SourceKey, - },function(err, data) { - if (err) { - if (err.statusCode && err.statusCode === 404) { - callback({ErrorStatus: SourceKey + ' Not Exist'}); - } else { - callback(err); - } - return; - } - - FileSize = params.FileSize = data.headers['content-length']; - if (FileSize === undefined || !FileSize) { - callback({error: 'get Content-Length error, please add "Content-Length" to CORS ExposeHeader setting.'}); - return; - } - - onProgress = util.throttleOnProgress.call(self, FileSize, params.onProgress); - - // 开始上传 - if (FileSize <= CopySliceSize) { - if (!params.Headers['x-cos-metadata-directive']) { - params.Headers['x-cos-metadata-directive'] = 'Copy'; - } - self.putObjectCopy(params, function (err, data) { - if (err) { - onProgress(null, true); - return callback(err); - } - onProgress({loaded: FileSize, total: FileSize}, true); - callback(err, data); - }); - } else { - var resHeaders = data.headers; - var SourceHeaders = { - 'Cache-Control': resHeaders['cache-control'], - 'Content-Disposition': resHeaders['content-disposition'], - 'Content-Encoding': resHeaders['content-encoding'], - 'Content-Type': resHeaders['content-type'], - 'Expires': resHeaders['expires'], - 'x-cos-storage-class': resHeaders['x-cos-storage-class'], - }; - util.each(resHeaders, function (v, k) { - var metaPrefix = 'x-cos-meta-'; - if (k.indexOf(metaPrefix) === 0 && k.length > metaPrefix.length) { - SourceHeaders[k] = v; - } - }); - ep.emit('get_file_size_finish', SourceHeaders); - } - }); -} - -// 复制指定分片 -function copySliceItem(params, callback) { - var TaskId = params.TaskId; - var Bucket = params.Bucket; - var Region = params.Region; - var Key = params.Key; - var CopySource = params.CopySource; - var UploadId = params.UploadId; - var PartNumber = params.PartNumber * 1; - var CopySourceRange = params.CopySourceRange; - - var ChunkRetryTimes = this.options.ChunkRetryTimes + 1; - var self = this; - - Async.retry(ChunkRetryTimes, function (tryCallback) { - self.uploadPartCopy({ - TaskId: TaskId, - Bucket: Bucket, - Region: Region, - Key: Key, - CopySource: CopySource, - UploadId: UploadId, - PartNumber:PartNumber, - CopySourceRange:CopySourceRange, - onProgress:params.onProgress, - },function (err,data) { - tryCallback(err || null, data); - }) - }, function (err, data) { - return callback(err, data); - }); -} - - -var API_MAP = { - sliceUploadFile: sliceUploadFile, - abortUploadTask: abortUploadTask, - uploadFiles: uploadFiles, - sliceCopyFile: sliceCopyFile, -}; - -module.exports.init = function (COS, task) { - task.transferToTaskMethod(API_MAP, 'sliceUploadFile'); - util.each(API_MAP, function (fn, apiName) { - COS.prototype[apiName] = util.apiWrapper(apiName, fn); - }); -}; + while (running < limit && started < arr.length) { + started += 1; + running += 1; + iterator(arr[started - 1], function (err) { + + if (err) { + callback(err); + callback = function () {}; + } else { + completed += 1; + running -= 1; + if (completed >= arr.length) { + callback(); + } else { + replenish(); + } + } + }); + } + })(); +}; +var retry = function (times, iterator, callback) { + var next = function (index) { + iterator(function (err, data) { + if (err && index < times) { + next(index + 1); + } else { + callback(err, data); + } + }); + }; + if (times < 1) { + callback(); + } else { + next(1); + } +}; -/***/ }), -/* 24 */ -/***/ (function(module, exports) { +var async = { + eachLimit: eachLimit, + retry: retry +}; -var eachLimit = function (arr, limit, iterator, callback) { - callback = callback || function () {}; - if (!arr.length || limit <= 0) { - return callback(); - } - - var completed = 0; - var started = 0; - var running = 0; - - (function replenish () { - if (completed >= arr.length) { - return callback(); - } - - while (running < limit && started < arr.length) { - started += 1; - running += 1; - iterator(arr[started - 1], function (err) { - - if (err) { - callback(err); - callback = function () {}; - } else { - completed += 1; - running -= 1; - if (completed >= arr.length) { - callback(); - } else { - replenish(); - } - } - }); - } - })(); -}; - -var retry = function (times, iterator, callback) { - var next = function (index) { - iterator(function (err, data) { - if (err && index < times) { - next(index + 1); - } else { - callback(err, data); - } - }); - }; - if (times < 1) { - callback(); - } else { - next(1); - } -}; - -var async = { - eachLimit: eachLimit, - retry: retry -}; - module.exports = async; /***/ }) diff --git a/package.json b/package.json index 82d06ab..377a550 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cos-wx-sdk-v5", - "version": "1.0.7", + "version": "1.0.10", "description": "小程序 SDK for [腾讯云对象存储服务](https://cloud.tencent.com/product/cos)", "main": "demo/lib/cos-wx-sdk-v5.js", "scripts": { diff --git a/src/advance.js b/src/advance.js index 9dc1c6b..cc2fc51 100644 --- a/src/advance.js +++ b/src/advance.js @@ -32,12 +32,19 @@ function sliceUploadFile(params, callback) { // 上传过程中出现错误,返回错误 ep.on('error', function (err) { if (!self._isRunningTask(TaskId)) return; - return callback(err); + var _err = { + UploadId: params.UploadData.UploadId || '', + err: err, + }; + return callback(_err); }); // 上传分块完成,开始 uploadSliceComplete 操作 ep.on('upload_complete', function (UploadCompleteData) { - callback(null, UploadCompleteData); + var _UploadCompleteData = util.extend({ + UploadId: params.UploadData.UploadId || '' + }, UploadCompleteData); + callback(null, _UploadCompleteData); }); // 上传分块完成,开始 uploadSliceComplete 操作 @@ -796,6 +803,48 @@ function abortUploadTaskArray(params, callback) { }); } +// 高级上传 +function uploadFile(params, callback) { + var self = this; + + // 判断多大的文件使用分片上传 + var SliceSize = params.SliceSize === undefined ? self.options.SliceSize : params.SliceSize; + + var taskList = []; + + var FileSize = params.FileSize; + var fileInfo = {TaskId: ''}; + + // 整理 option,用于返回给回调 + util.each(params, function (v, k) { + if (typeof v !== 'object' && typeof v !== 'function') { + fileInfo[k] = v; + } + }); + + // 处理文件 TaskReady + var _onTaskReady = params.onTaskReady; + params.onTaskReady = function (tid) { + fileInfo.TaskId = tid; + _onTaskReady && _onTaskReady(tid); + }; + + // 处理文件完成 + var _onFileFinish = params.onFileFinish; + var onFileFinish = function (err, data) { + _onFileFinish && _onFileFinish(err, data, fileInfo); + callback && callback(err, data); + }; + + // 添加上传任务 + var api = FileSize > SliceSize ? 'sliceUploadFile' : 'postObject'; + taskList.push({ + api: api, + params: params, + callback: onFileFinish, + }); + self._addTasks(taskList); +} // 批量上传文件 function uploadFiles(params, callback) { @@ -1129,6 +1178,7 @@ function copySliceItem(params, callback) { var API_MAP = { sliceUploadFile: sliceUploadFile, abortUploadTask: abortUploadTask, + uploadFile: uploadFile, uploadFiles: uploadFiles, sliceCopyFile: sliceCopyFile, }; diff --git a/src/base.js b/src/base.js index 624e3c6..84c9637 100644 --- a/src/base.js +++ b/src/base.js @@ -2898,6 +2898,8 @@ function getObjectUrl(params, callback) { Method: params.Method || 'get', Key: params.Key, Expires: params.Expires, + Headers: params.Headers, + Query: params.Query }, function (err, AuthData) { if (!callback) return; if (err) { @@ -2918,7 +2920,7 @@ function getObjectUrl(params, callback) { }); if (AuthData) { - signUrl += '?' + AuthData.Authorization + + syncUrl += '?' + AuthData.Authorization + (AuthData.XCosSecurityToken ? '&x-cos-security-token=' + AuthData.XCosSecurityToken : ''); queryParamsStr && (syncUrl += '&' + queryParamsStr); } else { diff --git a/src/cos.js b/src/cos.js index 6cb36bd..b4d8f9b 100644 --- a/src/cos.js +++ b/src/cos.js @@ -57,6 +57,6 @@ base.init(COS, task); advance.init(COS, task); COS.getAuthorization = util.getAuth; -COS.version = '1.0.7'; +COS.version = '1.0.10'; module.exports = COS;