@nocobase/plugin-file-manager 2.1.0-beta.30 → 2.1.0-beta.33

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/client/index.js +1 -1
  2. package/dist/client-v2/125.01d5562df948d974.js +10 -0
  3. package/dist/client-v2/229.bd72c2d7aa088310.js +10 -0
  4. package/dist/client-v2/336.1dd1b32466d0c778.js +10 -0
  5. package/dist/client-v2/43.eb45d53ba3e9828b.js +10 -0
  6. package/dist/client-v2/450.f590b4c220108742.js +10 -0
  7. package/dist/client-v2/929.d7e783304cc1f236.js +10 -0
  8. package/dist/client-v2/942.c10c97317af6dd02.js +10 -0
  9. package/dist/{client/StorageOptions.d.ts → client-v2/components/BaseUrlField.d.ts} +1 -1
  10. package/dist/client-v2/components/DefaultField.d.ts +18 -0
  11. package/dist/client-v2/{storageTypes/index.d.ts → components/FileSizeField.d.ts} +2 -2
  12. package/dist/client-v2/components/MimetypeField.d.ts +10 -0
  13. package/dist/client-v2/components/NameField.d.ts +10 -0
  14. package/dist/client-v2/components/ParanoidField.d.ts +10 -0
  15. package/dist/client-v2/components/PathField.d.ts +18 -0
  16. package/dist/client-v2/components/RenameModeField.d.ts +10 -0
  17. package/dist/client-v2/components/TitleField.d.ts +10 -0
  18. package/dist/client-v2/components/index.d.ts +17 -0
  19. package/dist/client-v2/index.d.ts +5 -0
  20. package/dist/client-v2/index.js +1 -1
  21. package/dist/client-v2/plugin.d.ts +47 -6
  22. package/dist/client-v2/storage-forms/AliOssStorageForm.d.ts +10 -0
  23. package/dist/client-v2/storage-forms/LocalStorageForm.d.ts +10 -0
  24. package/dist/client-v2/storage-forms/S3StorageForm.d.ts +10 -0
  25. package/dist/client-v2/storage-forms/TxCosStorageForm.d.ts +10 -0
  26. package/dist/externalVersion.js +10 -13
  27. package/dist/node_modules/@aws-sdk/client-s3/package.json +1 -1
  28. package/dist/node_modules/@aws-sdk/lib-storage/package.json +1 -1
  29. package/dist/node_modules/ali-oss/package.json +1 -1
  30. package/dist/node_modules/cos-nodejs-sdk-v5/.github/workflows/auto-changelog.yml +55 -0
  31. package/dist/node_modules/cos-nodejs-sdk-v5/.prettierrc +10 -0
  32. package/dist/node_modules/cos-nodejs-sdk-v5/.travis.yml +16 -0
  33. package/dist/node_modules/cos-nodejs-sdk-v5/LICENSE +21 -0
  34. package/dist/node_modules/cos-nodejs-sdk-v5/demo/crc64.js +9 -0
  35. package/dist/node_modules/cos-nodejs-sdk-v5/demo/demo-sts-scope.js +75 -0
  36. package/dist/node_modules/cos-nodejs-sdk-v5/demo/demo-sts.js +65 -0
  37. package/dist/node_modules/cos-nodejs-sdk-v5/demo/demo.js +4542 -0
  38. package/dist/node_modules/cos-nodejs-sdk-v5/demo/util.js +135 -0
  39. package/dist/node_modules/cos-nodejs-sdk-v5/index.d.ts +2610 -0
  40. package/dist/node_modules/{multer-cos → cos-nodejs-sdk-v5}/index.js +2 -2
  41. package/dist/node_modules/cos-nodejs-sdk-v5/package.json +1 -0
  42. package/dist/node_modules/cos-nodejs-sdk-v5/sdk/advance.js +1659 -0
  43. package/dist/node_modules/cos-nodejs-sdk-v5/sdk/async.js +59 -0
  44. package/dist/node_modules/cos-nodejs-sdk-v5/sdk/base.js +4404 -0
  45. package/dist/node_modules/cos-nodejs-sdk-v5/sdk/cos.js +137 -0
  46. package/dist/node_modules/cos-nodejs-sdk-v5/sdk/event.js +34 -0
  47. package/dist/node_modules/cos-nodejs-sdk-v5/sdk/select-stream.js +181 -0
  48. package/dist/node_modules/cos-nodejs-sdk-v5/sdk/session.js +126 -0
  49. package/dist/node_modules/cos-nodejs-sdk-v5/sdk/task.js +255 -0
  50. package/dist/node_modules/cos-nodejs-sdk-v5/sdk/util.js +776 -0
  51. package/dist/node_modules/cos-nodejs-sdk-v5/test/csp.js +1302 -0
  52. package/dist/node_modules/cos-nodejs-sdk-v5/test/test.js +6119 -0
  53. package/dist/node_modules/mime-match/package.json +1 -1
  54. package/dist/node_modules/mime-types/package.json +1 -1
  55. package/dist/node_modules/mkdirp/package.json +1 -1
  56. package/dist/node_modules/url-join/package.json +1 -1
  57. package/dist/server/storages/tx-cos.d.ts +16 -1
  58. package/dist/server/storages/tx-cos.js +111 -10
  59. package/dist/shared/previewer/filePreviewTypes.d.ts +1 -0
  60. package/dist/shared/previewer/filePreviewTypes.js +21 -0
  61. package/package.json +2 -3
  62. package/dist/client-v2/855.e7d2e24a0b457a89.js +0 -10
  63. package/dist/client-v2/storageTypes/types.d.ts +0 -26
  64. package/dist/node_modules/multer-cos/LICENSE +0 -24
  65. package/dist/node_modules/multer-cos/demo/index.js +0 -39
  66. package/dist/node_modules/multer-cos/demo/myMulter.js +0 -88
  67. package/dist/node_modules/multer-cos/package.json +0 -1
@@ -0,0 +1,4404 @@
1
+ var pkg = require('../package.json');
2
+ var REQUEST = require('request');
3
+ var mime = require('mime-types');
4
+ var Stream = require('stream');
5
+ var util = require('./util');
6
+ var fs = require('fs');
7
+
8
+ // Bucket 相关
9
+
10
+ /**
11
+ * 获取用户的 bucket 列表
12
+ * @param {Object} params 回调函数,必须,下面为参数列表
13
+ * 无特殊参数
14
+ * @param {Function} callback 回调函数,必须
15
+ */
16
+ function getService(params, callback) {
17
+ if (typeof params === 'function') {
18
+ callback = params;
19
+ params = {};
20
+ }
21
+ var protocol = this.options.Protocol || (util.isBrowser && location.protocol === 'http:' ? 'http:' : 'https:');
22
+ var domain = this.options.ServiceDomain;
23
+ var appId = params.AppId || this.options.appId;
24
+ var region = params.Region;
25
+ if (domain) {
26
+ domain = domain
27
+ .replace(/\{\{AppId\}\}/gi, appId || '')
28
+ .replace(/\{\{Region\}\}/gi, region || '')
29
+ .replace(/\{\{.*?\}\}/gi, '');
30
+ if (!/^[a-zA-Z]+:\/\//.test(domain)) {
31
+ domain = protocol + '//' + domain;
32
+ }
33
+ if (domain.slice(-1) === '/') {
34
+ domain = domain.slice(0, -1);
35
+ }
36
+ } else if (region) {
37
+ domain = protocol + '//cos.' + region + '.myqcloud.com';
38
+ } else {
39
+ domain = protocol + '//service.cos.myqcloud.com';
40
+ }
41
+
42
+ var SignHost = '';
43
+ var standardHost = region ? 'cos.' + region + '.myqcloud.com' : 'service.cos.myqcloud.com';
44
+ var urlHost = domain.replace(/^https?:\/\/([^/]+)(\/.*)?$/, '$1');
45
+ if (standardHost === urlHost) SignHost = standardHost;
46
+
47
+ submitRequest.call(
48
+ this,
49
+ {
50
+ Action: 'name/cos:GetService',
51
+ url: domain,
52
+ method: 'GET',
53
+ headers: params.Headers,
54
+ SignHost: SignHost,
55
+ },
56
+ function (err, data) {
57
+ if (err) return callback(err);
58
+ var buckets =
59
+ (data &&
60
+ data.ListAllMyBucketsResult &&
61
+ data.ListAllMyBucketsResult.Buckets &&
62
+ data.ListAllMyBucketsResult.Buckets.Bucket) ||
63
+ [];
64
+ buckets = util.isArray(buckets) ? buckets : [buckets];
65
+ var owner = (data && data.ListAllMyBucketsResult && data.ListAllMyBucketsResult.Owner) || {};
66
+ callback(null, {
67
+ Buckets: buckets,
68
+ Owner: owner,
69
+ statusCode: data.statusCode,
70
+ headers: data.headers,
71
+ });
72
+ }
73
+ );
74
+ }
75
+
76
+ /**
77
+ * 创建 Bucket,并初始化访问权限
78
+ * @param {Object} params 参数对象,必须
79
+ * @param {String} params.Bucket Bucket名称,必须
80
+ * @param {String} params.Region 地域名称,必须
81
+ * @param {String} params.ACL 用户自定义文件权限,可以设置:private,public-read;默认值:private,非必须
82
+ * @param {String} params.GrantRead 赋予被授权者读的权限,格式x-cos-grant-read: uin=" ",uin=" ",非必须
83
+ * @param {String} params.GrantWrite 赋予被授权者写的权限,格式x-cos-grant-write: uin=" ",uin=" ",非必须
84
+ * @param {String} params.GrantFullControl 赋予被授权者读写权限,格式x-cos-grant-full-control: uin=" ",uin=" ",非必须
85
+ * @param {Function} callback 回调函数,必须
86
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
87
+ * @return {Object} data 返回的数据
88
+ * @return {String} data.Location 操作地址
89
+ */
90
+ function putBucket(params, callback) {
91
+ var self = this;
92
+
93
+ var xml = '';
94
+ var conf = {};
95
+ if (params.BucketAZConfig) conf.BucketAZConfig = params.BucketAZConfig;
96
+ if (params.BucketArchConfig) conf.BucketArchConfig = params.BucketArchConfig;
97
+ if (conf.BucketAZConfig || conf.BucketArchConfig) xml = util.json2xml({ CreateBucketConfiguration: conf });
98
+
99
+ submitRequest.call(
100
+ this,
101
+ {
102
+ Action: 'name/cos:PutBucket',
103
+ method: 'PUT',
104
+ Bucket: params.Bucket,
105
+ Region: params.Region,
106
+ headers: params.Headers,
107
+ body: xml,
108
+ },
109
+ function (err, data) {
110
+ if (err) return callback(err);
111
+ var url = getUrl({
112
+ protocol: self.options.Protocol,
113
+ domain: self.options.Domain,
114
+ bucket: params.Bucket,
115
+ region: params.Region,
116
+ isLocation: true,
117
+ });
118
+ callback(null, {
119
+ Location: url,
120
+ statusCode: data.statusCode,
121
+ headers: data.headers,
122
+ });
123
+ }
124
+ );
125
+ }
126
+
127
+ /**
128
+ * 查看是否存在该Bucket,是否有权限访问
129
+ * @param {Object} params 参数对象,必须
130
+ * @param {String} params.Bucket Bucket名称,必须
131
+ * @param {String} params.Region 地域名称,必须
132
+ * @param {Function} callback 回调函数,必须
133
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
134
+ * @return {Object} data 返回的数据
135
+ * @return {Boolean} data.BucketExist Bucket是否存在
136
+ * @return {Boolean} data.BucketAuth 是否有 Bucket 的访问权限
137
+ */
138
+ function headBucket(params, callback) {
139
+ submitRequest.call(
140
+ this,
141
+ {
142
+ Action: 'name/cos:HeadBucket',
143
+ Bucket: params.Bucket,
144
+ Region: params.Region,
145
+ headers: params.Headers,
146
+ method: 'HEAD',
147
+ },
148
+ callback
149
+ );
150
+ }
151
+
152
+ /**
153
+ * 获取 Bucket 下的 object 列表
154
+ * @param {Object} params 参数对象,必须
155
+ * @param {String} params.Bucket Bucket名称,必须
156
+ * @param {String} params.Region 地域名称,必须
157
+ * @param {String} params.Prefix 前缀匹配,用来规定返回的文件前缀地址,非必须
158
+ * @param {String} params.Delimiter 定界符为一个符号,如果有Prefix,则将Prefix到delimiter之间的相同路径归为一类,非必须
159
+ * @param {String} params.Marker 默认以UTF-8二进制顺序列出条目,所有列出条目从marker开始,非必须
160
+ * @param {String} params.MaxKeys 单次返回最大的条目数量,默认1000,非必须
161
+ * @param {String} params.EncodingType 规定返回值的编码方式,非必须
162
+ * @param {Function} callback 回调函数,必须
163
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
164
+ * @return {Object} data 返回的数据
165
+ * @return {Object} data.ListBucketResult 返回的 object 列表信息
166
+ */
167
+ function getBucket(params, callback) {
168
+ var reqParams = {};
169
+ reqParams['prefix'] = params['Prefix'] || '';
170
+ reqParams['delimiter'] = params['Delimiter'];
171
+ reqParams['marker'] = params['Marker'];
172
+ reqParams['max-keys'] = params['MaxKeys'];
173
+ reqParams['encoding-type'] = params['EncodingType'];
174
+
175
+ submitRequest.call(
176
+ this,
177
+ {
178
+ Action: 'name/cos:GetBucket',
179
+ ResourceKey: reqParams['prefix'],
180
+ method: 'GET',
181
+ Bucket: params.Bucket,
182
+ Region: params.Region,
183
+ headers: params.Headers,
184
+ qs: reqParams,
185
+ },
186
+ function (err, data) {
187
+ if (err) return callback(err);
188
+ var ListBucketResult = data.ListBucketResult || {};
189
+ var Contents = ListBucketResult.Contents || [];
190
+ var CommonPrefixes = ListBucketResult.CommonPrefixes || [];
191
+
192
+ Contents = util.isArray(Contents) ? Contents : [Contents];
193
+ CommonPrefixes = util.isArray(CommonPrefixes) ? CommonPrefixes : [CommonPrefixes];
194
+
195
+ var result = util.clone(ListBucketResult);
196
+ util.extend(result, {
197
+ Contents: Contents,
198
+ CommonPrefixes: CommonPrefixes,
199
+ statusCode: data.statusCode,
200
+ headers: data.headers,
201
+ });
202
+
203
+ callback(null, result);
204
+ }
205
+ );
206
+ }
207
+
208
+ /**
209
+ * 删除 Bucket
210
+ * @param {Object} params 参数对象,必须
211
+ * @param {String} params.Bucket Bucket名称,必须
212
+ * @param {String} params.Region 地域名称,必须
213
+ * @param {Function} callback 回调函数,必须
214
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
215
+ * @return {Object} data 返回的数据
216
+ * @return {String} data.Location 操作地址
217
+ */
218
+ function deleteBucket(params, callback) {
219
+ submitRequest.call(
220
+ this,
221
+ {
222
+ Action: 'name/cos:DeleteBucket',
223
+ Bucket: params.Bucket,
224
+ Region: params.Region,
225
+ headers: params.Headers,
226
+ method: 'DELETE',
227
+ },
228
+ function (err, data) {
229
+ if (err && err.statusCode === 204) {
230
+ return callback(null, { statusCode: err.statusCode });
231
+ } else if (err) {
232
+ return callback(err);
233
+ }
234
+ callback(null, {
235
+ statusCode: data.statusCode,
236
+ headers: data.headers,
237
+ });
238
+ }
239
+ );
240
+ }
241
+
242
+ /**
243
+ * 设置 Bucket 的 权限列表
244
+ * @param {Object} params 参数对象,必须
245
+ * @param {String} params.Bucket Bucket名称,必须
246
+ * @param {String} params.Region 地域名称,必须
247
+ * @param {String} params.ACL 用户自定义文件权限,可以设置:private,public-read;默认值:private,非必须
248
+ * @param {String} params.GrantRead 赋予被授权者读的权限,格式x-cos-grant-read: uin=" ",uin=" ",非必须
249
+ * @param {String} params.GrantWrite 赋予被授权者写的权限,格式x-cos-grant-write: uin=" ",uin=" ",非必须
250
+ * @param {String} params.GrantFullControl 赋予被授权者读写权限,格式x-cos-grant-full-control: uin=" ",uin=" ",非必须
251
+ * @param {Function} callback 回调函数,必须
252
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
253
+ * @return {Object} data 返回的数据
254
+ */
255
+ function putBucketAcl(params, callback) {
256
+ var headers = params.Headers;
257
+
258
+ var xml = '';
259
+ if (params['AccessControlPolicy']) {
260
+ var AccessControlPolicy = util.clone(params['AccessControlPolicy'] || {});
261
+ var Grants = AccessControlPolicy.Grants || AccessControlPolicy.Grant;
262
+ Grants = util.isArray(Grants) ? Grants : [Grants];
263
+ delete AccessControlPolicy.Grant;
264
+ delete AccessControlPolicy.Grants;
265
+ AccessControlPolicy.AccessControlList = { Grant: Grants };
266
+ xml = util.json2xml({ AccessControlPolicy: AccessControlPolicy });
267
+
268
+ headers['Content-Type'] = 'application/xml';
269
+ headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
270
+ }
271
+
272
+ // Grant Header 去重
273
+ util.each(headers, function (val, key) {
274
+ if (key.indexOf('x-cos-grant-') === 0) {
275
+ headers[key] = uniqGrant(headers[key]);
276
+ }
277
+ });
278
+
279
+ submitRequest.call(
280
+ this,
281
+ {
282
+ Action: 'name/cos:PutBucketACL',
283
+ method: 'PUT',
284
+ Bucket: params.Bucket,
285
+ Region: params.Region,
286
+ headers: headers,
287
+ action: 'acl',
288
+ body: xml,
289
+ },
290
+ function (err, data) {
291
+ if (err) return callback(err);
292
+ callback(null, {
293
+ statusCode: data.statusCode,
294
+ headers: data.headers,
295
+ });
296
+ }
297
+ );
298
+ }
299
+
300
+ /**
301
+ * 获取 Bucket 的 权限列表
302
+ * @param {Object} params 参数对象,必须
303
+ * @param {String} params.Bucket Bucket名称,必须
304
+ * @param {String} params.Region 地域名称,必须
305
+ * @param {Function} callback 回调函数,必须
306
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
307
+ * @return {Object} data 返回的数据
308
+ * @return {Object} data.AccessControlPolicy 访问权限信息
309
+ */
310
+ function getBucketAcl(params, callback) {
311
+ submitRequest.call(
312
+ this,
313
+ {
314
+ Action: 'name/cos:GetBucketACL',
315
+ method: 'GET',
316
+ Bucket: params.Bucket,
317
+ Region: params.Region,
318
+ headers: params.Headers,
319
+ action: 'acl',
320
+ },
321
+ function (err, data) {
322
+ if (err) return callback(err);
323
+ var AccessControlPolicy = data.AccessControlPolicy || {};
324
+ var Owner = AccessControlPolicy.Owner || {};
325
+ var Grant = (AccessControlPolicy.AccessControlList && AccessControlPolicy.AccessControlList.Grant) || [];
326
+ Grant = util.isArray(Grant) ? Grant : [Grant];
327
+ var result = decodeAcl(AccessControlPolicy);
328
+ if (data.headers && data.headers['x-cos-acl']) {
329
+ result.ACL = data.headers['x-cos-acl'];
330
+ }
331
+ result = util.extend(result, {
332
+ Owner: Owner,
333
+ Grants: Grant,
334
+ statusCode: data.statusCode,
335
+ headers: data.headers,
336
+ });
337
+ callback(null, result);
338
+ }
339
+ );
340
+ }
341
+
342
+ /**
343
+ * 设置 Bucket 的 跨域设置
344
+ * @param {Object} params 参数对象,必须
345
+ * @param {String} params.Bucket Bucket名称,必须
346
+ * @param {String} params.Region 地域名称,必须
347
+ * @param {Object} params.CORSConfiguration 相关的跨域设置,必须
348
+ * @param {Array} params.CORSConfiguration.CORSRules 对应的跨域规则
349
+ * @param {Function} callback 回调函数,必须
350
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
351
+ * @return {Object} data 返回的数据
352
+ */
353
+ function putBucketCors(params, callback) {
354
+ var CORSConfiguration = params['CORSConfiguration'] || {};
355
+ var CORSRules = CORSConfiguration['CORSRules'] || params['CORSRules'] || [];
356
+ CORSRules = util.clone(util.isArray(CORSRules) ? CORSRules : [CORSRules]);
357
+ util.each(CORSRules, function (rule) {
358
+ util.each(['AllowedOrigin', 'AllowedHeader', 'AllowedMethod', 'ExposeHeader'], function (key) {
359
+ var sKey = key + 's';
360
+ var val = rule[sKey] || rule[key] || [];
361
+ delete rule[sKey];
362
+ rule[key] = util.isArray(val) ? val : [val];
363
+ });
364
+ });
365
+
366
+ var Conf = { CORSRule: CORSRules };
367
+ if (params.ResponseVary) Conf.ResponseVary = params.ResponseVary;
368
+
369
+ var xml = util.json2xml({ CORSConfiguration: Conf });
370
+
371
+ var headers = params.Headers;
372
+ headers['Content-Type'] = 'application/xml';
373
+ headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
374
+
375
+ submitRequest.call(
376
+ this,
377
+ {
378
+ Action: 'name/cos:PutBucketCORS',
379
+ method: 'PUT',
380
+ Bucket: params.Bucket,
381
+ Region: params.Region,
382
+ body: xml,
383
+ action: 'cors',
384
+ headers: headers,
385
+ },
386
+ function (err, data) {
387
+ if (err) return callback(err);
388
+ callback(null, {
389
+ statusCode: data.statusCode,
390
+ headers: data.headers,
391
+ });
392
+ }
393
+ );
394
+ }
395
+
396
+ /**
397
+ * 获取 Bucket 的 跨域设置
398
+ * @param {Object} params 参数对象,必须
399
+ * @param {String} params.Bucket Bucket名称,必须
400
+ * @param {String} params.Region 地域名称,必须
401
+ * @param {Function} callback 回调函数,必须
402
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
403
+ * @return {Object} data 返回的数据
404
+ * @return {Object} data.CORSRules Bucket的跨域设置
405
+ */
406
+ function getBucketCors(params, callback) {
407
+ submitRequest.call(
408
+ this,
409
+ {
410
+ Action: 'name/cos:GetBucketCORS',
411
+ method: 'GET',
412
+ Bucket: params.Bucket,
413
+ Region: params.Region,
414
+ headers: params.Headers,
415
+ action: 'cors',
416
+ },
417
+ function (err, data) {
418
+ if (err) {
419
+ if (err.statusCode === 404 && err.error && err.error.Code === 'NoSuchCORSConfiguration') {
420
+ var result = {
421
+ CORSRules: [],
422
+ statusCode: err.statusCode,
423
+ };
424
+ err.headers && (result.headers = err.headers);
425
+ callback(null, result);
426
+ } else {
427
+ callback(err);
428
+ }
429
+ return;
430
+ }
431
+ var CORSConfiguration = data.CORSConfiguration || {};
432
+ var CORSRules = CORSConfiguration.CORSRules || CORSConfiguration.CORSRule || [];
433
+ CORSRules = util.clone(util.isArray(CORSRules) ? CORSRules : [CORSRules]);
434
+ var ResponseVary = CORSConfiguration.ResponseVary;
435
+
436
+ util.each(CORSRules, function (rule) {
437
+ util.each(['AllowedOrigin', 'AllowedHeader', 'AllowedMethod', 'ExposeHeader'], function (key) {
438
+ var sKey = key + 's';
439
+ var val = rule[sKey] || rule[key] || [];
440
+ delete rule[key];
441
+ rule[sKey] = util.isArray(val) ? val : [val];
442
+ });
443
+ });
444
+
445
+ callback(null, {
446
+ CORSRules: CORSRules,
447
+ ResponseVary: ResponseVary,
448
+ statusCode: data.statusCode,
449
+ headers: data.headers,
450
+ });
451
+ }
452
+ );
453
+ }
454
+
455
+ /**
456
+ * 删除 Bucket 的 跨域设置
457
+ * @param {Object} params 参数对象,必须
458
+ * @param {String} params.Bucket Bucket名称,必须
459
+ * @param {String} params.Region 地域名称,必须
460
+ * @param {Function} callback 回调函数,必须
461
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
462
+ * @return {Object} data 返回的数据
463
+ */
464
+ function deleteBucketCors(params, callback) {
465
+ submitRequest.call(
466
+ this,
467
+ {
468
+ Action: 'name/cos:DeleteBucketCORS',
469
+ method: 'DELETE',
470
+ Bucket: params.Bucket,
471
+ Region: params.Region,
472
+ headers: params.Headers,
473
+ action: 'cors',
474
+ },
475
+ function (err, data) {
476
+ if (err && err.statusCode === 204) {
477
+ return callback(null, { statusCode: err.statusCode });
478
+ } else if (err) {
479
+ return callback(err);
480
+ }
481
+ callback(null, {
482
+ statusCode: data.statusCode || err.statusCode,
483
+ headers: data.headers,
484
+ });
485
+ }
486
+ );
487
+ }
488
+
489
+ /**
490
+ * 获取 Bucket 的 地域信息
491
+ * @param {Object} params 参数对象,必须
492
+ * @param {String} params.Bucket Bucket名称,必须
493
+ * @param {String} params.Region 地域名称,必须
494
+ * @param {Function} callback 回调函数,必须
495
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
496
+ * @return {Object} data 返回数据,包含地域信息 LocationConstraint
497
+ */
498
+ function getBucketLocation(params, callback) {
499
+ submitRequest.call(
500
+ this,
501
+ {
502
+ Action: 'name/cos:GetBucketLocation',
503
+ method: 'GET',
504
+ Bucket: params.Bucket,
505
+ Region: params.Region,
506
+ headers: params.Headers,
507
+ action: 'location',
508
+ },
509
+ callback
510
+ );
511
+ }
512
+
513
+ function putBucketPolicy(params, callback) {
514
+ var Policy = params['Policy'];
515
+ try {
516
+ if (typeof Policy === 'string') Policy = JSON.parse(Policy);
517
+ } catch (e) {}
518
+ if (!Policy || typeof Policy === 'string') return callback(util.error(new Error('Policy format error')));
519
+ var PolicyStr = JSON.stringify(Policy);
520
+ if (!Policy.version) Policy.version = '2.0';
521
+
522
+ var headers = params.Headers;
523
+ headers['Content-Type'] = 'application/json';
524
+ headers['Content-MD5'] = util.binaryBase64(util.md5(PolicyStr));
525
+
526
+ submitRequest.call(
527
+ this,
528
+ {
529
+ Action: 'name/cos:PutBucketPolicy',
530
+ method: 'PUT',
531
+ Bucket: params.Bucket,
532
+ Region: params.Region,
533
+ action: 'policy',
534
+ body: PolicyStr,
535
+ headers: headers,
536
+ },
537
+ function (err, data) {
538
+ if (err && err.statusCode === 204) {
539
+ return callback(null, { statusCode: err.statusCode });
540
+ } else if (err) {
541
+ return callback(err);
542
+ }
543
+ callback(null, {
544
+ statusCode: data.statusCode,
545
+ headers: data.headers,
546
+ });
547
+ }
548
+ );
549
+ }
550
+
551
+ /**
552
+ * 获取 Bucket 的读取权限策略
553
+ * @param {Object} params 参数对象,必须
554
+ * @param {String} params.Bucket Bucket名称,必须
555
+ * @param {String} params.Region 地域名称,必须
556
+ * @param {Function} callback 回调函数,必须
557
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
558
+ * @return {Object} data 返回数据
559
+ */
560
+ function getBucketPolicy(params, callback) {
561
+ submitRequest.call(
562
+ this,
563
+ {
564
+ Action: 'name/cos:GetBucketPolicy',
565
+ method: 'GET',
566
+ Bucket: params.Bucket,
567
+ Region: params.Region,
568
+ headers: params.Headers,
569
+ action: 'policy',
570
+ rawBody: true,
571
+ },
572
+ function (err, data) {
573
+ if (err) {
574
+ if (err.statusCode && err.statusCode === 403) {
575
+ return callback(util.error(err, { ErrorStatus: 'Access Denied' }));
576
+ }
577
+ if (err.statusCode && err.statusCode === 405) {
578
+ return callback(util.error(err, { ErrorStatus: 'Method Not Allowed' }));
579
+ }
580
+ if (err.statusCode && err.statusCode === 404) {
581
+ return callback(util.error(err, { ErrorStatus: 'Policy Not Found' }));
582
+ }
583
+ return callback(err);
584
+ }
585
+ var Policy = {};
586
+ try {
587
+ Policy = JSON.parse(data.body);
588
+ } catch (e) {}
589
+ callback(null, {
590
+ Policy: Policy,
591
+ statusCode: data.statusCode,
592
+ headers: data.headers,
593
+ });
594
+ }
595
+ );
596
+ }
597
+
598
+ /**
599
+ * 删除 Bucket 的 跨域设置
600
+ * @param {Object} params 参数对象,必须
601
+ * @param {String} params.Bucket Bucket名称,必须
602
+ * @param {String} params.Region 地域名称,必须
603
+ * @param {Function} callback 回调函数,必须
604
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
605
+ * @return {Object} data 返回的数据
606
+ */
607
+ function deleteBucketPolicy(params, callback) {
608
+ submitRequest.call(
609
+ this,
610
+ {
611
+ Action: 'name/cos:DeleteBucketPolicy',
612
+ method: 'DELETE',
613
+ Bucket: params.Bucket,
614
+ Region: params.Region,
615
+ headers: params.Headers,
616
+ action: 'policy',
617
+ },
618
+ function (err, data) {
619
+ if (err && err.statusCode === 204) {
620
+ return callback(null, { statusCode: err.statusCode });
621
+ } else if (err) {
622
+ return callback(err);
623
+ }
624
+ callback(null, {
625
+ statusCode: data.statusCode || err.statusCode,
626
+ headers: data.headers,
627
+ });
628
+ }
629
+ );
630
+ }
631
+
632
+ /**
633
+ * 设置 Bucket 的标签
634
+ * @param {Object} params 参数对象,必须
635
+ * @param {String} params.Bucket Bucket名称,必须
636
+ * @param {String} params.Region 地域名称,必须
637
+ * @param {Array} params.TagSet 标签设置,必须
638
+ * @param {Function} callback 回调函数,必须
639
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
640
+ * @return {Object} data 返回数据
641
+ */
642
+ function putBucketTagging(params, callback) {
643
+ var Tagging = params['Tagging'] || {};
644
+ var Tags = Tagging.TagSet || Tagging.Tags || params['Tags'] || [];
645
+ Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]);
646
+ var xml = util.json2xml({ Tagging: { TagSet: { Tag: Tags } } });
647
+
648
+ var headers = params.Headers;
649
+ headers['Content-Type'] = 'application/xml';
650
+ headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
651
+
652
+ submitRequest.call(
653
+ this,
654
+ {
655
+ Action: 'name/cos:PutBucketTagging',
656
+ method: 'PUT',
657
+ Bucket: params.Bucket,
658
+ Region: params.Region,
659
+ body: xml,
660
+ action: 'tagging',
661
+ headers: headers,
662
+ },
663
+ function (err, data) {
664
+ if (err && err.statusCode === 204) {
665
+ return callback(null, { statusCode: err.statusCode });
666
+ } else if (err) {
667
+ return callback(err);
668
+ }
669
+ callback(null, {
670
+ statusCode: data.statusCode,
671
+ headers: data.headers,
672
+ });
673
+ }
674
+ );
675
+ }
676
+
677
+ /**
678
+ * 获取 Bucket 的标签设置
679
+ * @param {Object} params 参数对象,必须
680
+ * @param {String} params.Bucket Bucket名称,必须
681
+ * @param {String} params.Region 地域名称,必须
682
+ * @param {Function} callback 回调函数,必须
683
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
684
+ * @return {Object} data 返回数据
685
+ */
686
+ function getBucketTagging(params, callback) {
687
+ submitRequest.call(
688
+ this,
689
+ {
690
+ Action: 'name/cos:GetBucketTagging',
691
+ method: 'GET',
692
+ Bucket: params.Bucket,
693
+ Region: params.Region,
694
+ headers: params.Headers,
695
+ action: 'tagging',
696
+ },
697
+ function (err, data) {
698
+ if (err) {
699
+ if (err.statusCode === 404 && err.error && (err.error === 'Not Found' || err.error.Code === 'NoSuchTagSet')) {
700
+ var result = {
701
+ Tags: [],
702
+ statusCode: err.statusCode,
703
+ };
704
+ err.headers && (result.headers = err.headers);
705
+ callback(null, result);
706
+ } else {
707
+ callback(err);
708
+ }
709
+ return;
710
+ }
711
+ var Tags = [];
712
+ try {
713
+ Tags = data.Tagging.TagSet.Tag || [];
714
+ } catch (e) {}
715
+ Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]);
716
+ callback(null, {
717
+ Tags: Tags,
718
+ statusCode: data.statusCode,
719
+ headers: data.headers,
720
+ });
721
+ }
722
+ );
723
+ }
724
+
725
+ /**
726
+ * 删除 Bucket 的 标签设置
727
+ * @param {Object} params 参数对象,必须
728
+ * @param {String} params.Bucket Bucket名称,必须
729
+ * @param {String} params.Region 地域名称,必须
730
+ * @param {Function} callback 回调函数,必须
731
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
732
+ * @return {Object} data 返回的数据
733
+ */
734
+ function deleteBucketTagging(params, callback) {
735
+ submitRequest.call(
736
+ this,
737
+ {
738
+ Action: 'name/cos:DeleteBucketTagging',
739
+ method: 'DELETE',
740
+ Bucket: params.Bucket,
741
+ Region: params.Region,
742
+ headers: params.Headers,
743
+ action: 'tagging',
744
+ },
745
+ function (err, data) {
746
+ if (err && err.statusCode === 204) {
747
+ return callback(null, { statusCode: err.statusCode });
748
+ } else if (err) {
749
+ return callback(err);
750
+ }
751
+ callback(null, {
752
+ statusCode: data.statusCode,
753
+ headers: data.headers,
754
+ });
755
+ }
756
+ );
757
+ }
758
+
759
+ function putBucketLifecycle(params, callback) {
760
+ var LifecycleConfiguration = params['LifecycleConfiguration'] || {};
761
+ var Rules = LifecycleConfiguration.Rules || params.Rules || [];
762
+ Rules = util.clone(Rules);
763
+ var xml = util.json2xml({ LifecycleConfiguration: { Rule: Rules } });
764
+
765
+ var headers = params.Headers;
766
+ headers['Content-Type'] = 'application/xml';
767
+ headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
768
+
769
+ submitRequest.call(
770
+ this,
771
+ {
772
+ Action: 'name/cos:PutBucketLifecycle',
773
+ method: 'PUT',
774
+ Bucket: params.Bucket,
775
+ Region: params.Region,
776
+ body: xml,
777
+ action: 'lifecycle',
778
+ headers: headers,
779
+ },
780
+ function (err, data) {
781
+ if (err && err.statusCode === 204) {
782
+ return callback(null, { statusCode: err.statusCode });
783
+ } else if (err) {
784
+ return callback(err);
785
+ }
786
+ callback(null, {
787
+ statusCode: data.statusCode,
788
+ headers: data.headers,
789
+ });
790
+ }
791
+ );
792
+ }
793
+
794
+ function getBucketLifecycle(params, callback) {
795
+ submitRequest.call(
796
+ this,
797
+ {
798
+ Action: 'name/cos:GetBucketLifecycle',
799
+ method: 'GET',
800
+ Bucket: params.Bucket,
801
+ Region: params.Region,
802
+ headers: params.Headers,
803
+ action: 'lifecycle',
804
+ },
805
+ function (err, data) {
806
+ if (err) {
807
+ if (err.statusCode === 404 && err.error && err.error.Code === 'NoSuchLifecycleConfiguration') {
808
+ var result = {
809
+ Rules: [],
810
+ statusCode: err.statusCode,
811
+ };
812
+ err.headers && (result.headers = err.headers);
813
+ callback(null, result);
814
+ } else {
815
+ callback(err);
816
+ }
817
+ return;
818
+ }
819
+ var Rules = [];
820
+ try {
821
+ Rules = data.LifecycleConfiguration.Rule || [];
822
+ } catch (e) {}
823
+ Rules = util.clone(util.isArray(Rules) ? Rules : [Rules]);
824
+ callback(null, {
825
+ Rules: Rules,
826
+ statusCode: data.statusCode,
827
+ headers: data.headers,
828
+ });
829
+ }
830
+ );
831
+ }
832
+
833
+ function deleteBucketLifecycle(params, callback) {
834
+ submitRequest.call(
835
+ this,
836
+ {
837
+ Action: 'name/cos:DeleteBucketLifecycle',
838
+ method: 'DELETE',
839
+ Bucket: params.Bucket,
840
+ Region: params.Region,
841
+ headers: params.Headers,
842
+ action: 'lifecycle',
843
+ },
844
+ function (err, data) {
845
+ if (err && err.statusCode === 204) {
846
+ return callback(null, { statusCode: err.statusCode });
847
+ } else if (err) {
848
+ return callback(err);
849
+ }
850
+ callback(null, {
851
+ statusCode: data.statusCode,
852
+ headers: data.headers,
853
+ });
854
+ }
855
+ );
856
+ }
857
+
858
+ function putBucketVersioning(params, callback) {
859
+ if (!params['VersioningConfiguration']) {
860
+ callback(util.error(new Error('missing param VersioningConfiguration')));
861
+ return;
862
+ }
863
+ var VersioningConfiguration = params['VersioningConfiguration'] || {};
864
+ var xml = util.json2xml({ VersioningConfiguration: VersioningConfiguration });
865
+
866
+ var headers = params.Headers;
867
+ headers['Content-Type'] = 'application/xml';
868
+ headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
869
+
870
+ submitRequest.call(
871
+ this,
872
+ {
873
+ Action: 'name/cos:PutBucketVersioning',
874
+ method: 'PUT',
875
+ Bucket: params.Bucket,
876
+ Region: params.Region,
877
+ body: xml,
878
+ action: 'versioning',
879
+ headers: headers,
880
+ },
881
+ function (err, data) {
882
+ if (err && err.statusCode === 204) {
883
+ return callback(null, { statusCode: err.statusCode });
884
+ } else if (err) {
885
+ return callback(err);
886
+ }
887
+ callback(null, {
888
+ statusCode: data.statusCode,
889
+ headers: data.headers,
890
+ });
891
+ }
892
+ );
893
+ }
894
+
895
+ function getBucketVersioning(params, callback) {
896
+ submitRequest.call(
897
+ this,
898
+ {
899
+ Action: 'name/cos:GetBucketVersioning',
900
+ method: 'GET',
901
+ Bucket: params.Bucket,
902
+ Region: params.Region,
903
+ headers: params.Headers,
904
+ action: 'versioning',
905
+ },
906
+ function (err, data) {
907
+ if (!err) {
908
+ !data.VersioningConfiguration && (data.VersioningConfiguration = {});
909
+ }
910
+ callback(err, data);
911
+ }
912
+ );
913
+ }
914
+
915
+ function putBucketReplication(params, callback) {
916
+ var ReplicationConfiguration = util.clone(params.ReplicationConfiguration);
917
+ var xml = util.json2xml({ ReplicationConfiguration: ReplicationConfiguration });
918
+ xml = xml.replace(/<(\/?)Rules>/gi, '<$1Rule>');
919
+ xml = xml.replace(/<(\/?)Tags>/gi, '<$1Tag>');
920
+
921
+ var headers = params.Headers;
922
+ headers['Content-Type'] = 'application/xml';
923
+ headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
924
+
925
+ submitRequest.call(
926
+ this,
927
+ {
928
+ Action: 'name/cos:PutBucketReplication',
929
+ method: 'PUT',
930
+ Bucket: params.Bucket,
931
+ Region: params.Region,
932
+ body: xml,
933
+ action: 'replication',
934
+ headers: headers,
935
+ },
936
+ function (err, data) {
937
+ if (err && err.statusCode === 204) {
938
+ return callback(null, { statusCode: err.statusCode });
939
+ } else if (err) {
940
+ return callback(err);
941
+ }
942
+ callback(null, {
943
+ statusCode: data.statusCode,
944
+ headers: data.headers,
945
+ });
946
+ }
947
+ );
948
+ }
949
+
950
+ function getBucketReplication(params, callback) {
951
+ submitRequest.call(
952
+ this,
953
+ {
954
+ Action: 'name/cos:GetBucketReplication',
955
+ method: 'GET',
956
+ Bucket: params.Bucket,
957
+ Region: params.Region,
958
+ headers: params.Headers,
959
+ action: 'replication',
960
+ },
961
+ function (err, data) {
962
+ if (err) {
963
+ if (
964
+ err.statusCode === 404 &&
965
+ err.error &&
966
+ (err.error === 'Not Found' || err.error.Code === 'ReplicationConfigurationnotFoundError')
967
+ ) {
968
+ var result = {
969
+ ReplicationConfiguration: { Rules: [] },
970
+ statusCode: err.statusCode,
971
+ };
972
+ err.headers && (result.headers = err.headers);
973
+ callback(null, result);
974
+ } else {
975
+ callback(err);
976
+ }
977
+ return;
978
+ }
979
+ if (!err) {
980
+ !data.ReplicationConfiguration && (data.ReplicationConfiguration = {});
981
+ }
982
+ if (data.ReplicationConfiguration.Rule) {
983
+ data.ReplicationConfiguration.Rules = util.makeArray(data.ReplicationConfiguration.Rule);
984
+ delete data.ReplicationConfiguration.Rule;
985
+ }
986
+ callback(err, data);
987
+ }
988
+ );
989
+ }
990
+
991
+ function deleteBucketReplication(params, callback) {
992
+ submitRequest.call(
993
+ this,
994
+ {
995
+ Action: 'name/cos:DeleteBucketReplication',
996
+ method: 'DELETE',
997
+ Bucket: params.Bucket,
998
+ Region: params.Region,
999
+ headers: params.Headers,
1000
+ action: 'replication',
1001
+ },
1002
+ function (err, data) {
1003
+ if (err && err.statusCode === 204) {
1004
+ return callback(null, { statusCode: err.statusCode });
1005
+ } else if (err) {
1006
+ return callback(err);
1007
+ }
1008
+ callback(null, {
1009
+ statusCode: data.statusCode,
1010
+ headers: data.headers,
1011
+ });
1012
+ }
1013
+ );
1014
+ }
1015
+
1016
+ /**
1017
+ * 设置 Bucket 静态网站配置信息
1018
+ * @param {Object} params 参数对象,必须
1019
+ * @param {String} params.Bucket Bucket名称,必须
1020
+ * @param {String} params.Region 地域名称,必须
1021
+ * @param {Object} params.WebsiteConfiguration 地域名称,必须
1022
+ * @param {Object} WebsiteConfiguration.IndexDocument 索引文档,必须
1023
+ * @param {Object} WebsiteConfiguration.ErrorDocument 错误文档,非必须
1024
+ * @param {Object} WebsiteConfiguration.RedirectAllRequestsTo 重定向所有请求,非必须
1025
+ * @param {Array} params.RoutingRules 重定向规则,非必须
1026
+ * @param {Function} callback 回调函数,必须
1027
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
1028
+ * @return {Object} data 返回数据
1029
+ */
1030
+ function putBucketWebsite(params, callback) {
1031
+ if (!params['WebsiteConfiguration']) {
1032
+ callback(util.error(new Error('missing param WebsiteConfiguration')));
1033
+ return;
1034
+ }
1035
+
1036
+ var WebsiteConfiguration = util.clone(params['WebsiteConfiguration'] || {});
1037
+ var RoutingRules = WebsiteConfiguration['RoutingRules'] || WebsiteConfiguration['RoutingRule'] || [];
1038
+ RoutingRules = util.isArray(RoutingRules) ? RoutingRules : [RoutingRules];
1039
+ delete WebsiteConfiguration.RoutingRule;
1040
+ delete WebsiteConfiguration.RoutingRules;
1041
+ if (RoutingRules.length) WebsiteConfiguration.RoutingRules = { RoutingRule: RoutingRules };
1042
+ var xml = util.json2xml({ WebsiteConfiguration: WebsiteConfiguration });
1043
+
1044
+ var headers = params.Headers;
1045
+ headers['Content-Type'] = 'application/xml';
1046
+ headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
1047
+
1048
+ submitRequest.call(
1049
+ this,
1050
+ {
1051
+ Action: 'name/cos:PutBucketWebsite',
1052
+ method: 'PUT',
1053
+ Bucket: params.Bucket,
1054
+ Region: params.Region,
1055
+ body: xml,
1056
+ action: 'website',
1057
+ headers: headers,
1058
+ },
1059
+ function (err, data) {
1060
+ if (err && err.statusCode === 204) {
1061
+ return callback(null, { statusCode: err.statusCode });
1062
+ } else if (err) {
1063
+ return callback(err);
1064
+ }
1065
+ callback(null, {
1066
+ statusCode: data.statusCode,
1067
+ headers: data.headers,
1068
+ });
1069
+ }
1070
+ );
1071
+ }
1072
+
1073
+ /**
1074
+ * 获取 Bucket 的静态网站配置信息
1075
+ * @param {Object} params 参数对象,必须
1076
+ * @param {String} params.Bucket Bucket名称,必须
1077
+ * @param {String} params.Region 地域名称,必须
1078
+ * @param {Function} callback 回调函数,必须
1079
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
1080
+ * @return {Object} data 返回数据
1081
+ */
1082
+ function getBucketWebsite(params, callback) {
1083
+ submitRequest.call(
1084
+ this,
1085
+ {
1086
+ Action: 'name/cos:GetBucketWebsite',
1087
+ method: 'GET',
1088
+ Bucket: params.Bucket,
1089
+ Region: params.Region,
1090
+ Key: params.Key,
1091
+ headers: params.Headers,
1092
+ action: 'website',
1093
+ },
1094
+ function (err, data) {
1095
+ if (err) {
1096
+ if (err.statusCode === 404 && err.error.Code === 'NoSuchWebsiteConfiguration') {
1097
+ var result = {
1098
+ WebsiteConfiguration: {},
1099
+ statusCode: err.statusCode,
1100
+ };
1101
+ err.headers && (result.headers = err.headers);
1102
+ callback(null, result);
1103
+ } else {
1104
+ callback(err);
1105
+ }
1106
+ return;
1107
+ }
1108
+
1109
+ var WebsiteConfiguration = data.WebsiteConfiguration || {};
1110
+ if (WebsiteConfiguration['RoutingRules']) {
1111
+ var RoutingRules = util.clone(WebsiteConfiguration['RoutingRules'].RoutingRule || []);
1112
+ RoutingRules = util.makeArray(RoutingRules);
1113
+ WebsiteConfiguration.RoutingRules = RoutingRules;
1114
+ }
1115
+
1116
+ callback(null, {
1117
+ WebsiteConfiguration: WebsiteConfiguration,
1118
+ statusCode: data.statusCode,
1119
+ headers: data.headers,
1120
+ });
1121
+ }
1122
+ );
1123
+ }
1124
+
1125
+ /**
1126
+ * 删除 Bucket 的静态网站配置
1127
+ * @param {Object} params 参数对象,必须
1128
+ * @param {String} params.Bucket Bucket名称,必须
1129
+ * @param {String} params.Region 地域名称,必须
1130
+ * @param {Function} callback 回调函数,必须
1131
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
1132
+ * @return {Object} data 返回数据
1133
+ */
1134
+ function deleteBucketWebsite(params, callback) {
1135
+ submitRequest.call(
1136
+ this,
1137
+ {
1138
+ Action: 'name/cos:DeleteBucketWebsite',
1139
+ method: 'DELETE',
1140
+ Bucket: params.Bucket,
1141
+ Region: params.Region,
1142
+ headers: params.Headers,
1143
+ action: 'website',
1144
+ },
1145
+ function (err, data) {
1146
+ if (err && err.statusCode === 204) {
1147
+ return callback(null, { statusCode: err.statusCode });
1148
+ } else if (err) {
1149
+ return callback(err);
1150
+ }
1151
+ callback(null, {
1152
+ statusCode: data.statusCode,
1153
+ headers: data.headers,
1154
+ });
1155
+ }
1156
+ );
1157
+ }
1158
+
1159
+ /**
1160
+ * 设置 Bucket 的防盗链白名单或者黑名单
1161
+ * @param {Object} params 参数对象,必须
1162
+ * @param {String} params.Bucket Bucket名称,必须
1163
+ * @param {String} params.Region 地域名称,必须
1164
+ * @param {Object} params.RefererConfiguration 地域名称,必须
1165
+ * @param {String} RefererConfiguration.Status 是否开启防盗链,枚举值:Enabled、Disabled
1166
+ * @param {String} RefererConfiguration.RefererType 防盗链类型,枚举值:Black-List、White-List,必须
1167
+ * @param {Array} RefererConfiguration.DomianList.Domain 生效域名,必须
1168
+ * @param {String} RefererConfiguration.EmptyReferConfiguration ,非必须
1169
+ * @param {Function} callback 回调函数,必须
1170
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
1171
+ * @return {Object} data 返回数据
1172
+ */
1173
+ function putBucketReferer(params, callback) {
1174
+ if (!params['RefererConfiguration']) {
1175
+ callback(util.error(new Error('missing param RefererConfiguration')));
1176
+ return;
1177
+ }
1178
+
1179
+ var RefererConfiguration = util.clone(params['RefererConfiguration'] || {});
1180
+ var DomainList = RefererConfiguration['DomainList'] || {};
1181
+ var Domains = DomainList['Domains'] || DomainList['Domain'] || [];
1182
+ Domains = util.isArray(Domains) ? Domains : [Domains];
1183
+ if (Domains.length) RefererConfiguration.DomainList = { Domain: Domains };
1184
+ var xml = util.json2xml({ RefererConfiguration: RefererConfiguration });
1185
+
1186
+ var headers = params.Headers;
1187
+ headers['Content-Type'] = 'application/xml';
1188
+ headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
1189
+
1190
+ submitRequest.call(
1191
+ this,
1192
+ {
1193
+ Action: 'name/cos:PutBucketReferer',
1194
+ method: 'PUT',
1195
+ Bucket: params.Bucket,
1196
+ Region: params.Region,
1197
+ body: xml,
1198
+ action: 'referer',
1199
+ headers: headers,
1200
+ },
1201
+ function (err, data) {
1202
+ if (err && err.statusCode === 204) {
1203
+ return callback(null, { statusCode: err.statusCode });
1204
+ } else if (err) {
1205
+ return callback(err);
1206
+ }
1207
+ callback(null, {
1208
+ statusCode: data.statusCode,
1209
+ headers: data.headers,
1210
+ });
1211
+ }
1212
+ );
1213
+ }
1214
+
1215
+ /**
1216
+ * 获取 Bucket 的防盗链白名单或者黑名单
1217
+ * @param {Object} params 参数对象,必须
1218
+ * @param {String} params.Bucket Bucket名称,必须
1219
+ * @param {String} params.Region 地域名称,必须
1220
+ * @param {Function} callback 回调函数,必须
1221
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
1222
+ * @return {Object} data 返回数据
1223
+ */
1224
+ function getBucketReferer(params, callback) {
1225
+ submitRequest.call(
1226
+ this,
1227
+ {
1228
+ Action: 'name/cos:GetBucketReferer',
1229
+ method: 'GET',
1230
+ Bucket: params.Bucket,
1231
+ Region: params.Region,
1232
+ Key: params.Key,
1233
+ headers: params.Headers,
1234
+ action: 'referer',
1235
+ },
1236
+ function (err, data) {
1237
+ if (err) {
1238
+ if (err.statusCode === 404 && err.error.Code === 'NoSuchRefererConfiguration') {
1239
+ var result = {
1240
+ WebsiteConfiguration: {},
1241
+ statusCode: err.statusCode,
1242
+ };
1243
+ err.headers && (result.headers = err.headers);
1244
+ callback(null, result);
1245
+ } else {
1246
+ callback(err);
1247
+ }
1248
+ return;
1249
+ }
1250
+
1251
+ var RefererConfiguration = data.RefererConfiguration || {};
1252
+ if (RefererConfiguration['DomainList']) {
1253
+ var Domains = util.makeArray(RefererConfiguration['DomainList'].Domain || []);
1254
+ RefererConfiguration.DomainList = { Domains: Domains };
1255
+ }
1256
+
1257
+ callback(null, {
1258
+ RefererConfiguration: RefererConfiguration,
1259
+ statusCode: data.statusCode,
1260
+ headers: data.headers,
1261
+ });
1262
+ }
1263
+ );
1264
+ }
1265
+
1266
+ /**
1267
+ * 设置 Bucket 自定义域名
1268
+ * @param {Object} params 参数对象,必须
1269
+ * @param {String} params.Bucket Bucket名称,必须
1270
+ * @param {String} params.Region 地域名称,必须
1271
+ * @param {Function} callback 回调函数,必须
1272
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
1273
+ * @return {Object} data 返回数据
1274
+ */
1275
+ function putBucketDomain(params, callback) {
1276
+ var DomainConfiguration = params['DomainConfiguration'] || {};
1277
+ var DomainRule = DomainConfiguration.DomainRule || params.DomainRule || [];
1278
+ DomainRule = util.clone(DomainRule);
1279
+ var xml = util.json2xml({ DomainConfiguration: { DomainRule: DomainRule } });
1280
+
1281
+ var headers = params.Headers;
1282
+ headers['Content-Type'] = 'application/xml';
1283
+ headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
1284
+
1285
+ submitRequest.call(
1286
+ this,
1287
+ {
1288
+ Action: 'name/cos:PutBucketDomain',
1289
+ method: 'PUT',
1290
+ Bucket: params.Bucket,
1291
+ Region: params.Region,
1292
+ body: xml,
1293
+ action: 'domain',
1294
+ headers: headers,
1295
+ },
1296
+ function (err, data) {
1297
+ if (err && err.statusCode === 204) {
1298
+ return callback(null, { statusCode: err.statusCode });
1299
+ } else if (err) {
1300
+ return callback(err);
1301
+ }
1302
+ callback(null, {
1303
+ statusCode: data.statusCode,
1304
+ headers: data.headers,
1305
+ });
1306
+ }
1307
+ );
1308
+ }
1309
+
1310
+ /**
1311
+ * 获取 Bucket 的自定义域名
1312
+ * @param {Object} params 参数对象,必须
1313
+ * @param {String} params.Bucket Bucket名称,必须
1314
+ * @param {String} params.Region 地域名称,必须
1315
+ * @param {Function} callback 回调函数,必须
1316
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
1317
+ * @return {Object} data 返回数据
1318
+ */
1319
+ function getBucketDomain(params, callback) {
1320
+ submitRequest.call(
1321
+ this,
1322
+ {
1323
+ Action: 'name/cos:GetBucketDomain',
1324
+ method: 'GET',
1325
+ Bucket: params.Bucket,
1326
+ Region: params.Region,
1327
+ headers: params.Headers,
1328
+ action: 'domain',
1329
+ },
1330
+ function (err, data) {
1331
+ if (err) return callback(err);
1332
+
1333
+ var DomainRule = [];
1334
+ try {
1335
+ DomainRule = data.DomainConfiguration.DomainRule || [];
1336
+ } catch (e) {}
1337
+ DomainRule = util.clone(util.isArray(DomainRule) ? DomainRule : [DomainRule]);
1338
+ callback(null, {
1339
+ DomainRule: DomainRule,
1340
+ statusCode: data.statusCode,
1341
+ headers: data.headers,
1342
+ });
1343
+ }
1344
+ );
1345
+ }
1346
+
1347
+ /**
1348
+ * 删除 Bucket 自定义域名
1349
+ * @param {Object} params 参数对象,必须
1350
+ * @param {String} params.Bucket Bucket名称,必须
1351
+ * @param {String} params.Region 地域名称,必须
1352
+ * @param {Function} callback 回调函数,必须
1353
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
1354
+ * @return {Object} data 返回数据
1355
+ */
1356
+ function deleteBucketDomain(params, callback) {
1357
+ submitRequest.call(
1358
+ this,
1359
+ {
1360
+ Action: 'name/cos:DeleteBucketDomain',
1361
+ method: 'DELETE',
1362
+ Bucket: params.Bucket,
1363
+ Region: params.Region,
1364
+ headers: params.Headers,
1365
+ action: 'domain',
1366
+ },
1367
+ function (err, data) {
1368
+ if (err && err.statusCode === 204) {
1369
+ return callback(null, { statusCode: err.statusCode });
1370
+ } else if (err) {
1371
+ return callback(err);
1372
+ }
1373
+ callback(null, {
1374
+ statusCode: data.statusCode,
1375
+ headers: data.headers,
1376
+ });
1377
+ }
1378
+ );
1379
+ }
1380
+
1381
+ /**
1382
+ * 设置 Bucket 的回源
1383
+ * @param {Object} params 参数对象,必须
1384
+ * @param {String} params.Bucket Bucket名称,必须
1385
+ * @param {String} params.Region 地域名称,必须
1386
+ * @param {Function} callback 回调函数,必须
1387
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
1388
+ * @return {Object} data 返回数据
1389
+ */
1390
+ function putBucketOrigin(params, callback) {
1391
+ var OriginConfiguration = params['OriginConfiguration'] || {};
1392
+ var OriginRule = OriginConfiguration.OriginRule || params.OriginRule || [];
1393
+ OriginRule = util.clone(OriginRule);
1394
+ var xml = util.json2xml({ OriginConfiguration: { OriginRule: OriginRule } });
1395
+
1396
+ var headers = params.Headers;
1397
+ headers['Content-Type'] = 'application/xml';
1398
+ headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
1399
+
1400
+ submitRequest.call(
1401
+ this,
1402
+ {
1403
+ Action: 'name/cos:PutBucketOrigin',
1404
+ method: 'PUT',
1405
+ Bucket: params.Bucket,
1406
+ Region: params.Region,
1407
+ body: xml,
1408
+ action: 'origin',
1409
+ headers: headers,
1410
+ },
1411
+ function (err, data) {
1412
+ if (err && err.statusCode === 204) {
1413
+ return callback(null, { statusCode: err.statusCode });
1414
+ } else if (err) {
1415
+ return callback(err);
1416
+ }
1417
+ callback(null, {
1418
+ statusCode: data.statusCode,
1419
+ headers: data.headers,
1420
+ });
1421
+ }
1422
+ );
1423
+ }
1424
+
1425
+ /**
1426
+ * 获取 Bucket 的回源
1427
+ * @param {Object} params 参数对象,必须
1428
+ * @param {String} params.Bucket Bucket名称,必须
1429
+ * @param {String} params.Region 地域名称,必须
1430
+ * @param {Function} callback 回调函数,必须
1431
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
1432
+ * @return {Object} data 返回数据
1433
+ */
1434
+ function getBucketOrigin(params, callback) {
1435
+ submitRequest.call(
1436
+ this,
1437
+ {
1438
+ Action: 'name/cos:GetBucketOrigin',
1439
+ method: 'GET',
1440
+ Bucket: params.Bucket,
1441
+ Region: params.Region,
1442
+ headers: params.Headers,
1443
+ action: 'origin',
1444
+ },
1445
+ function (err, data) {
1446
+ if (err) return callback(err);
1447
+
1448
+ var OriginRule = [];
1449
+ try {
1450
+ OriginRule = data.OriginConfiguration.OriginRule || [];
1451
+ } catch (e) {}
1452
+ OriginRule = util.clone(util.isArray(OriginRule) ? OriginRule : [OriginRule]);
1453
+ callback(null, {
1454
+ OriginRule: OriginRule,
1455
+ statusCode: data.statusCode,
1456
+ headers: data.headers,
1457
+ });
1458
+ }
1459
+ );
1460
+ }
1461
+
1462
+ /**
1463
+ * 删除 Bucket 的回源
1464
+ * @param {Object} params 参数对象,必须
1465
+ * @param {String} params.Bucket Bucket名称,必须
1466
+ * @param {String} params.Region 地域名称,必须
1467
+ * @param {Function} callback 回调函数,必须
1468
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
1469
+ * @return {Object} data 返回数据
1470
+ */
1471
+ function deleteBucketOrigin(params, callback) {
1472
+ submitRequest.call(
1473
+ this,
1474
+ {
1475
+ Action: 'name/cos:DeleteBucketOrigin',
1476
+ method: 'DELETE',
1477
+ Bucket: params.Bucket,
1478
+ Region: params.Region,
1479
+ headers: params.Headers,
1480
+ action: 'origin',
1481
+ },
1482
+ function (err, data) {
1483
+ if (err && err.statusCode === 204) {
1484
+ return callback(null, { statusCode: err.statusCode });
1485
+ } else if (err) {
1486
+ return callback(err);
1487
+ }
1488
+ callback(null, {
1489
+ statusCode: data.statusCode,
1490
+ headers: data.headers,
1491
+ });
1492
+ }
1493
+ );
1494
+ }
1495
+
1496
+ /**
1497
+ * 设置 Bucket 的日志记录
1498
+ * @param {Object} params 参数对象,必须
1499
+ * @param {String} params.Bucket Bucket名称,必须
1500
+ * @param {String} params.Region 地域名称,必须
1501
+ * @param {(Object|String)} params.BucketLoggingStatus 说明日志记录配置的状态,如果无子节点信息则意为关闭日志记录,必须
1502
+ * @param {Function} callback 回调函数,必须
1503
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
1504
+ * @return {Object} data 返回数据
1505
+ */
1506
+ function putBucketLogging(params, callback) {
1507
+ var xml = util.json2xml({
1508
+ BucketLoggingStatus: params['BucketLoggingStatus'] || '',
1509
+ });
1510
+
1511
+ var headers = params.Headers;
1512
+ headers['Content-Type'] = 'application/xml';
1513
+ headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
1514
+
1515
+ submitRequest.call(
1516
+ this,
1517
+ {
1518
+ Action: 'name/cos:PutBucketLogging',
1519
+ method: 'PUT',
1520
+ Bucket: params.Bucket,
1521
+ Region: params.Region,
1522
+ body: xml,
1523
+ action: 'logging',
1524
+ headers: headers,
1525
+ },
1526
+ function (err, data) {
1527
+ if (err && err.statusCode === 204) {
1528
+ return callback(null, { statusCode: err.statusCode });
1529
+ } else if (err) {
1530
+ return callback(err);
1531
+ }
1532
+ callback(null, {
1533
+ statusCode: data.statusCode,
1534
+ headers: data.headers,
1535
+ });
1536
+ }
1537
+ );
1538
+ }
1539
+
1540
+ /**
1541
+ * 获取 Bucket 的日志记录
1542
+ * @param {Object} params 参数对象,必须
1543
+ * @param {String} params.Bucket Bucket名称,必须
1544
+ * @param {String} params.Region 地域名称,必须
1545
+ * @param {Function} callback 回调函数,必须
1546
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
1547
+ * @return {Object} data 返回数据
1548
+ */
1549
+ function getBucketLogging(params, callback) {
1550
+ submitRequest.call(
1551
+ this,
1552
+ {
1553
+ Action: 'name/cos:GetBucketLogging',
1554
+ method: 'GET',
1555
+ Bucket: params.Bucket,
1556
+ Region: params.Region,
1557
+ headers: params.Headers,
1558
+ action: 'logging',
1559
+ },
1560
+ function (err, data) {
1561
+ if (err) return callback(err);
1562
+ callback(null, {
1563
+ BucketLoggingStatus: data.BucketLoggingStatus,
1564
+ statusCode: data.statusCode,
1565
+ headers: data.headers,
1566
+ });
1567
+ }
1568
+ );
1569
+ }
1570
+
1571
+ /**
1572
+ * 创建/编辑 Bucket 的清单任务
1573
+ * @param {Object} params 参数对象,必须
1574
+ * @param {String} params.Bucket Bucket名称,必须
1575
+ * @param {String} params.Region 地域名称,必须
1576
+ * @param {String} params.Id 清单任务的名称,必须
1577
+ * @param {Object} params.InventoryConfiguration 包含清单的配置参数,必须
1578
+ * @param {Function} callback 回调函数,必须
1579
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
1580
+ * @return {Object} data 返回数据
1581
+ */
1582
+ function putBucketInventory(params, callback) {
1583
+ var InventoryConfiguration = util.clone(params['InventoryConfiguration']);
1584
+
1585
+ if (InventoryConfiguration.OptionalFields) {
1586
+ var Field = InventoryConfiguration.OptionalFields || [];
1587
+ InventoryConfiguration.OptionalFields = {
1588
+ Field: Field,
1589
+ };
1590
+ }
1591
+
1592
+ if (
1593
+ InventoryConfiguration.Destination &&
1594
+ InventoryConfiguration.Destination.COSBucketDestination &&
1595
+ InventoryConfiguration.Destination.COSBucketDestination.Encryption
1596
+ ) {
1597
+ var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption;
1598
+ if (Object.keys(Encryption).indexOf('SSECOS') > -1) {
1599
+ Encryption['SSE-COS'] = Encryption['SSECOS'];
1600
+ delete Encryption['SSECOS'];
1601
+ }
1602
+ }
1603
+
1604
+ var xml = util.json2xml({
1605
+ InventoryConfiguration: InventoryConfiguration,
1606
+ });
1607
+
1608
+ var headers = params.Headers;
1609
+ headers['Content-Type'] = 'application/xml';
1610
+ headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
1611
+
1612
+ submitRequest.call(
1613
+ this,
1614
+ {
1615
+ Action: 'name/cos:PutBucketInventory',
1616
+ method: 'PUT',
1617
+ Bucket: params.Bucket,
1618
+ Region: params.Region,
1619
+ body: xml,
1620
+ action: 'inventory',
1621
+ qs: {
1622
+ id: params['Id'],
1623
+ },
1624
+ headers: headers,
1625
+ },
1626
+ function (err, data) {
1627
+ if (err && err.statusCode === 204) {
1628
+ return callback(null, { statusCode: err.statusCode });
1629
+ } else if (err) {
1630
+ return callback(err);
1631
+ }
1632
+ callback(null, {
1633
+ statusCode: data.statusCode,
1634
+ headers: data.headers,
1635
+ });
1636
+ }
1637
+ );
1638
+ }
1639
+
1640
+ /**
1641
+ * 获取 Bucket 的清单任务信息
1642
+ * @param {Object} params 参数对象,必须
1643
+ * @param {String} params.Bucket Bucket名称,必须
1644
+ * @param {String} params.Region 地域名称,必须
1645
+ * @param {String} params.Id 清单任务的名称,必须
1646
+ * @param {Function} callback 回调函数,必须
1647
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
1648
+ * @return {Object} data 返回数据
1649
+ */
1650
+ function getBucketInventory(params, callback) {
1651
+ submitRequest.call(
1652
+ this,
1653
+ {
1654
+ Action: 'name/cos:GetBucketInventory',
1655
+ method: 'GET',
1656
+ Bucket: params.Bucket,
1657
+ Region: params.Region,
1658
+ headers: params.Headers,
1659
+ action: 'inventory',
1660
+ qs: {
1661
+ id: params['Id'],
1662
+ },
1663
+ },
1664
+ function (err, data) {
1665
+ if (err) return callback(err);
1666
+
1667
+ var InventoryConfiguration = data['InventoryConfiguration'];
1668
+ if (
1669
+ InventoryConfiguration &&
1670
+ InventoryConfiguration.OptionalFields &&
1671
+ InventoryConfiguration.OptionalFields.Field
1672
+ ) {
1673
+ var Field = InventoryConfiguration.OptionalFields.Field;
1674
+ if (!util.isArray(Field)) {
1675
+ Field = [Field];
1676
+ }
1677
+ InventoryConfiguration.OptionalFields = Field;
1678
+ }
1679
+ if (
1680
+ InventoryConfiguration.Destination &&
1681
+ InventoryConfiguration.Destination.COSBucketDestination &&
1682
+ InventoryConfiguration.Destination.COSBucketDestination.Encryption
1683
+ ) {
1684
+ var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption;
1685
+ if (Object.keys(Encryption).indexOf('SSE-COS') > -1) {
1686
+ Encryption['SSECOS'] = Encryption['SSE-COS'];
1687
+ delete Encryption['SSE-COS'];
1688
+ }
1689
+ }
1690
+
1691
+ callback(null, {
1692
+ InventoryConfiguration: InventoryConfiguration,
1693
+ statusCode: data.statusCode,
1694
+ headers: data.headers,
1695
+ });
1696
+ }
1697
+ );
1698
+ }
1699
+
1700
+ /**
1701
+ * 获取 Bucket 的清单任务信息
1702
+ * @param {Object} params 参数对象,必须
1703
+ * @param {String} params.Bucket Bucket名称,必须
1704
+ * @param {String} params.Region 地域名称,必须
1705
+ * @param {String} params.ContinuationToken 当 COS 响应体中 IsTruncated 为 true,且 NextContinuationToken 节点中存在参数值时,您可以将这个参数作为 continuation-token 参数值,以获取下一页的清单任务信息,非必须
1706
+ * @param {Function} callback 回调函数,必须
1707
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
1708
+ * @return {Object} data 返回数据
1709
+ */
1710
+ function listBucketInventory(params, callback) {
1711
+ submitRequest.call(
1712
+ this,
1713
+ {
1714
+ Action: 'name/cos:ListBucketInventory',
1715
+ method: 'GET',
1716
+ Bucket: params.Bucket,
1717
+ Region: params.Region,
1718
+ headers: params.Headers,
1719
+ action: 'inventory',
1720
+ qs: {
1721
+ 'continuation-token': params['ContinuationToken'],
1722
+ },
1723
+ },
1724
+ function (err, data) {
1725
+ if (err) return callback(err);
1726
+ var ListInventoryConfigurationResult = data['ListInventoryConfigurationResult'];
1727
+ var InventoryConfigurations = ListInventoryConfigurationResult.InventoryConfiguration || [];
1728
+ InventoryConfigurations = util.isArray(InventoryConfigurations)
1729
+ ? InventoryConfigurations
1730
+ : [InventoryConfigurations];
1731
+ delete ListInventoryConfigurationResult['InventoryConfiguration'];
1732
+ util.each(InventoryConfigurations, function (InventoryConfiguration) {
1733
+ if (
1734
+ InventoryConfiguration &&
1735
+ InventoryConfiguration.OptionalFields &&
1736
+ InventoryConfiguration.OptionalFields.Field
1737
+ ) {
1738
+ var Field = InventoryConfiguration.OptionalFields.Field;
1739
+ if (!util.isArray(Field)) {
1740
+ Field = [Field];
1741
+ }
1742
+ InventoryConfiguration.OptionalFields = Field;
1743
+ }
1744
+
1745
+ if (
1746
+ InventoryConfiguration.Destination &&
1747
+ InventoryConfiguration.Destination.COSBucketDestination &&
1748
+ InventoryConfiguration.Destination.COSBucketDestination.Encryption
1749
+ ) {
1750
+ var Encryption = InventoryConfiguration.Destination.COSBucketDestination.Encryption;
1751
+ if (Object.keys(Encryption).indexOf('SSE-COS') > -1) {
1752
+ Encryption['SSECOS'] = Encryption['SSE-COS'];
1753
+ delete Encryption['SSE-COS'];
1754
+ }
1755
+ }
1756
+ });
1757
+ ListInventoryConfigurationResult.InventoryConfigurations = InventoryConfigurations;
1758
+ util.extend(ListInventoryConfigurationResult, {
1759
+ statusCode: data.statusCode,
1760
+ headers: data.headers,
1761
+ });
1762
+ callback(null, ListInventoryConfigurationResult);
1763
+ }
1764
+ );
1765
+ }
1766
+
1767
+ /**
1768
+ * 删除 Bucket 的清单任务
1769
+ * @param {Object} params 参数对象,必须
1770
+ * @param {String} params.Bucket Bucket名称,必须
1771
+ * @param {String} params.Region 地域名称,必须
1772
+ * @param {String} params.Id 清单任务的名称,必须
1773
+ * @param {Function} callback 回调函数,必须
1774
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
1775
+ * @return {Object} data 返回数据
1776
+ */
1777
+ function deleteBucketInventory(params, callback) {
1778
+ submitRequest.call(
1779
+ this,
1780
+ {
1781
+ Action: 'name/cos:DeleteBucketInventory',
1782
+ method: 'DELETE',
1783
+ Bucket: params.Bucket,
1784
+ Region: params.Region,
1785
+ headers: params.Headers,
1786
+ action: 'inventory',
1787
+ qs: {
1788
+ id: params['Id'],
1789
+ },
1790
+ },
1791
+ function (err, data) {
1792
+ if (err && err.statusCode === 204) {
1793
+ return callback(null, { statusCode: err.statusCode });
1794
+ } else if (err) {
1795
+ return callback(err);
1796
+ }
1797
+ callback(null, {
1798
+ statusCode: data.statusCode,
1799
+ headers: data.headers,
1800
+ });
1801
+ }
1802
+ );
1803
+ }
1804
+
1805
+ /* 全球加速 */
1806
+ function putBucketAccelerate(params, callback) {
1807
+ if (!params['AccelerateConfiguration']) {
1808
+ callback(util.error(new Error('missing param AccelerateConfiguration')));
1809
+ return;
1810
+ }
1811
+
1812
+ var configuration = { AccelerateConfiguration: params.AccelerateConfiguration || {} };
1813
+
1814
+ var xml = util.json2xml(configuration);
1815
+
1816
+ var headers = {};
1817
+ headers['Content-Type'] = 'application/xml';
1818
+ headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
1819
+
1820
+ submitRequest.call(
1821
+ this,
1822
+ {
1823
+ Action: 'name/cos:PutBucketAccelerate',
1824
+ method: 'PUT',
1825
+ Bucket: params.Bucket,
1826
+ Region: params.Region,
1827
+ body: xml,
1828
+ action: 'accelerate',
1829
+ headers: headers,
1830
+ },
1831
+ function (err, data) {
1832
+ if (err) return callback(err);
1833
+ callback(null, {
1834
+ statusCode: data.statusCode,
1835
+ headers: data.headers,
1836
+ });
1837
+ }
1838
+ );
1839
+ }
1840
+
1841
+ function getBucketAccelerate(params, callback) {
1842
+ submitRequest.call(
1843
+ this,
1844
+ {
1845
+ Action: 'name/cos:GetBucketAccelerate',
1846
+ method: 'GET',
1847
+ Bucket: params.Bucket,
1848
+ Region: params.Region,
1849
+ action: 'accelerate',
1850
+ },
1851
+ function (err, data) {
1852
+ if (!err) {
1853
+ !data.AccelerateConfiguration && (data.AccelerateConfiguration = {});
1854
+ }
1855
+ callback(err, data);
1856
+ }
1857
+ );
1858
+ }
1859
+
1860
+ function putBucketEncryption(params, callback) {
1861
+ var conf = params.ServerSideEncryptionConfiguration || {};
1862
+ var Rules = conf.Rule || conf.Rules || [];
1863
+ var xml = util.json2xml({ ServerSideEncryptionConfiguration: { Rule: Rules } });
1864
+
1865
+ var headers = params.Headers;
1866
+ headers['Content-Type'] = 'application/xml';
1867
+ headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
1868
+
1869
+ submitRequest.call(
1870
+ this,
1871
+ {
1872
+ Action: 'name/cos:PutBucketEncryption',
1873
+ method: 'PUT',
1874
+ Bucket: params.Bucket,
1875
+ Region: params.Region,
1876
+ body: xml,
1877
+ action: 'encryption',
1878
+ headers: headers,
1879
+ },
1880
+ function (err, data) {
1881
+ if (err && err.statusCode === 204) {
1882
+ return callback(null, { statusCode: err.statusCode });
1883
+ } else if (err) {
1884
+ return callback(err);
1885
+ }
1886
+ callback(null, {
1887
+ statusCode: data.statusCode,
1888
+ headers: data.headers,
1889
+ });
1890
+ }
1891
+ );
1892
+ }
1893
+
1894
+ function getBucketEncryption(params, callback) {
1895
+ submitRequest.call(
1896
+ this,
1897
+ {
1898
+ Action: 'name/cos:GetBucketEncryption',
1899
+ method: 'GET',
1900
+ Bucket: params.Bucket,
1901
+ Region: params.Region,
1902
+ headers: params.Headers,
1903
+ action: 'encryption',
1904
+ },
1905
+ function (err, data) {
1906
+ if (err) {
1907
+ if (err.statusCode === 404 && err.code === 'NoSuchEncryptionConfiguration') {
1908
+ var result = {
1909
+ EncryptionConfiguration: { Rules: [] },
1910
+ statusCode: err.statusCode,
1911
+ };
1912
+ err.headers && (result.headers = err.headers);
1913
+ callback(null, result);
1914
+ } else {
1915
+ callback(err);
1916
+ }
1917
+ return;
1918
+ }
1919
+ var Rules = util.makeArray((data.EncryptionConfiguration && data.EncryptionConfiguration.Rule) || []);
1920
+ data.EncryptionConfiguration = { Rules: Rules };
1921
+ callback(err, data);
1922
+ }
1923
+ );
1924
+ }
1925
+
1926
+ function deleteBucketEncryption(params, callback) {
1927
+ submitRequest.call(
1928
+ this,
1929
+ {
1930
+ Action: 'name/cos:DeleteBucketReplication',
1931
+ method: 'DELETE',
1932
+ Bucket: params.Bucket,
1933
+ Region: params.Region,
1934
+ headers: params.Headers,
1935
+ action: 'encryption',
1936
+ },
1937
+ function (err, data) {
1938
+ if (err && err.statusCode === 204) {
1939
+ return callback(null, { statusCode: err.statusCode });
1940
+ } else if (err) {
1941
+ return callback(err);
1942
+ }
1943
+ callback(null, {
1944
+ statusCode: data.statusCode,
1945
+ headers: data.headers,
1946
+ });
1947
+ }
1948
+ );
1949
+ }
1950
+
1951
+ // Object 相关
1952
+
1953
+ /**
1954
+ * 取回对应Object的元数据,Head的权限与Get的权限一致
1955
+ * @param {Object} params 参数对象,必须
1956
+ * @param {String} params.Bucket Bucket名称,必须
1957
+ * @param {String} params.Region 地域名称,必须
1958
+ * @param {String} params.Key 文件名称,必须
1959
+ * @param {String} params.IfModifiedSince 当Object在指定时间后被修改,则返回对应Object元信息,否则返回304,非必须
1960
+ * @param {Function} callback 回调函数,必须
1961
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
1962
+ * @return {Object} data 为指定 object 的元数据,如果设置了 IfModifiedSince ,且文件未修改,则返回一个对象,NotModified 属性为 true
1963
+ * @return {Boolean} data.NotModified 是否在 IfModifiedSince 时间点之后未修改该 object,则为 true
1964
+ */
1965
+ function headObject(params, callback) {
1966
+ submitRequest.call(
1967
+ this,
1968
+ {
1969
+ Action: 'name/cos:HeadObject',
1970
+ method: 'HEAD',
1971
+ Bucket: params.Bucket,
1972
+ Region: params.Region,
1973
+ Key: params.Key,
1974
+ VersionId: params.VersionId,
1975
+ headers: params.Headers,
1976
+ },
1977
+ function (err, data) {
1978
+ if (err) {
1979
+ var statusCode = err.statusCode;
1980
+ if (params.Headers['If-Modified-Since'] && statusCode && statusCode === 304) {
1981
+ return callback(null, {
1982
+ NotModified: true,
1983
+ statusCode: statusCode,
1984
+ });
1985
+ }
1986
+ return callback(err);
1987
+ }
1988
+ data.ETag = util.attr(data.headers, 'etag', '');
1989
+ callback(null, data);
1990
+ }
1991
+ );
1992
+ }
1993
+
1994
+ function listObjectVersions(params, callback) {
1995
+ var reqParams = {};
1996
+ reqParams['prefix'] = params['Prefix'] || '';
1997
+ reqParams['delimiter'] = params['Delimiter'];
1998
+ reqParams['key-marker'] = params['KeyMarker'];
1999
+ reqParams['version-id-marker'] = params['VersionIdMarker'];
2000
+ reqParams['max-keys'] = params['MaxKeys'];
2001
+ reqParams['encoding-type'] = params['EncodingType'];
2002
+
2003
+ submitRequest.call(
2004
+ this,
2005
+ {
2006
+ Action: 'name/cos:GetBucketObjectVersions',
2007
+ ResourceKey: reqParams['prefix'],
2008
+ method: 'GET',
2009
+ Bucket: params.Bucket,
2010
+ Region: params.Region,
2011
+ headers: params.Headers,
2012
+ qs: reqParams,
2013
+ action: 'versions',
2014
+ },
2015
+ function (err, data) {
2016
+ if (err) return callback(err);
2017
+ var ListVersionsResult = data.ListVersionsResult || {};
2018
+ var DeleteMarkers = ListVersionsResult.DeleteMarker || [];
2019
+ DeleteMarkers = util.isArray(DeleteMarkers) ? DeleteMarkers : [DeleteMarkers];
2020
+ var Versions = ListVersionsResult.Version || [];
2021
+ Versions = util.isArray(Versions) ? Versions : [Versions];
2022
+
2023
+ var result = util.clone(ListVersionsResult);
2024
+ delete result.DeleteMarker;
2025
+ delete result.Version;
2026
+ util.extend(result, {
2027
+ DeleteMarkers: DeleteMarkers,
2028
+ Versions: Versions,
2029
+ statusCode: data.statusCode,
2030
+ headers: data.headers,
2031
+ });
2032
+
2033
+ callback(null, result);
2034
+ }
2035
+ );
2036
+ }
2037
+
2038
+ /**
2039
+ * 下载 object
2040
+ * @param {Object} params 参数对象,必须
2041
+ * @param {String} params.Bucket Bucket名称,必须
2042
+ * @param {String} params.Region 地域名称,必须
2043
+ * @param {String} params.Key 文件名称,必须
2044
+ * @param {WriteStream} params.Output 文件写入流,非必须
2045
+ * @param {String} params.IfModifiedSince 当Object在指定时间后被修改,则返回对应Object元信息,否则返回304,非必须
2046
+ * @param {String} params.IfUnmodifiedSince 如果文件修改时间早于或等于指定时间,才返回文件内容。否则返回 412 (precondition failed),非必须
2047
+ * @param {String} params.IfMatch 当 ETag 与指定的内容一致,才返回文件。否则返回 412 (precondition failed),非必须
2048
+ * @param {String} params.IfNoneMatch 当 ETag 与指定的内容不一致,才返回文件。否则返回304 (not modified),非必须
2049
+ * @param {String} params.ResponseContentType 设置返回头部中的 Content-Type 参数,非必须
2050
+ * @param {String} params.ResponseContentLanguage 设置返回头部中的 Content-Language 参数,非必须
2051
+ * @param {String} params.ResponseExpires 设置返回头部中的 Content-Expires 参数,非必须
2052
+ * @param {String} params.ResponseCacheControl 设置返回头部中的 Cache-Control 参数,非必须
2053
+ * @param {String} params.ResponseContentDisposition 设置返回头部中的 Content-Disposition 参数,非必须
2054
+ * @param {String} params.ResponseContentEncoding 设置返回头部中的 Content-Encoding 参数,非必须
2055
+ * @param {Function} callback 回调函数,必须
2056
+ * @param {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
2057
+ * @param {Object} data 为对应的 object 数据,包括 body 和 headers
2058
+ */
2059
+ function getObject(params, callback) {
2060
+ var reqParams = params.Query || {};
2061
+ var reqParamsStr = params.QueryString || '';
2062
+
2063
+ reqParams['response-content-type'] = params['ResponseContentType'];
2064
+ reqParams['response-content-language'] = params['ResponseContentLanguage'];
2065
+ reqParams['response-expires'] = params['ResponseExpires'];
2066
+ reqParams['response-cache-control'] = params['ResponseCacheControl'];
2067
+ reqParams['response-content-disposition'] = params['ResponseContentDisposition'];
2068
+ reqParams['response-content-encoding'] = params['ResponseContentEncoding'];
2069
+
2070
+ var BodyType;
2071
+
2072
+ var self = this;
2073
+ var outputStream = params.Output;
2074
+ if (params.ReturnStream) {
2075
+ outputStream = new Stream.PassThrough();
2076
+ BodyType = 'stream';
2077
+ } else if (outputStream && typeof outputStream === 'string') {
2078
+ outputStream = fs.createWriteStream(outputStream);
2079
+ BodyType = 'stream';
2080
+ } else if (outputStream && typeof outputStream.pipe === 'function') {
2081
+ BodyType = 'stream';
2082
+ } else {
2083
+ BodyType = 'buffer';
2084
+ }
2085
+
2086
+ var onProgress = params.onProgress;
2087
+ var onDownloadProgress = (function () {
2088
+ var time0 = Date.now();
2089
+ var size0 = 0;
2090
+ var FinishSize = 0;
2091
+ var FileSize = 0;
2092
+ var progressTimer;
2093
+ var update = function () {
2094
+ progressTimer = 0;
2095
+ if (onProgress && typeof onProgress === 'function') {
2096
+ var time1 = Date.now();
2097
+ var speed = parseInt(((FinishSize - size0) / ((time1 - time0) / 1000)) * 100) / 100 || 0;
2098
+ var percent = parseInt((FinishSize / FileSize) * 100) / 100 || 0;
2099
+ time0 = time1;
2100
+ size0 = FinishSize;
2101
+ try {
2102
+ onProgress({
2103
+ loaded: FinishSize,
2104
+ total: FileSize,
2105
+ speed: speed,
2106
+ percent: percent,
2107
+ });
2108
+ } catch (e) {}
2109
+ }
2110
+ };
2111
+ return function (info, immediately) {
2112
+ if (info && info.loaded) {
2113
+ FinishSize = info.loaded;
2114
+ FileSize = info.total;
2115
+ }
2116
+ if (immediately) {
2117
+ clearTimeout(progressTimer);
2118
+ update();
2119
+ } else {
2120
+ if (progressTimer) return;
2121
+ progressTimer = setTimeout(update, self.options.ProgressInterval || 1000);
2122
+ }
2123
+ };
2124
+ })();
2125
+
2126
+ // 如果用户自己传入了 output
2127
+ submitRequest.call(
2128
+ this,
2129
+ {
2130
+ Action: 'name/cos:GetObject',
2131
+ method: 'GET',
2132
+ Bucket: params.Bucket,
2133
+ Region: params.Region,
2134
+ Key: params.Key,
2135
+ VersionId: params.VersionId,
2136
+ headers: params.Headers,
2137
+ qs: reqParams,
2138
+ qsStr: reqParamsStr,
2139
+ rawBody: true,
2140
+ outputStream: outputStream,
2141
+ onDownloadProgress: onDownloadProgress,
2142
+ },
2143
+ function (err, data) {
2144
+ onDownloadProgress(null, true);
2145
+ if (err) {
2146
+ var statusCode = err.statusCode;
2147
+ if (params.Headers['If-Modified-Since'] && statusCode && statusCode === 304) {
2148
+ return callback(null, { NotModified: true });
2149
+ }
2150
+ if (outputStream) outputStream.emit('error', err);
2151
+ return callback(err);
2152
+ }
2153
+ var result = {};
2154
+ if (data.body) {
2155
+ if (BodyType === 'buffer') {
2156
+ result.Body = Buffer.from(data.body);
2157
+ } else if (BodyType === 'string') {
2158
+ result.Body = data.body;
2159
+ }
2160
+ }
2161
+ util.extend(result, {
2162
+ ETag: util.attr(data.headers, 'etag', ''),
2163
+ statusCode: data.statusCode,
2164
+ headers: data.headers,
2165
+ });
2166
+ callback(null, result);
2167
+ }
2168
+ );
2169
+ if (params.ReturnStream) return outputStream;
2170
+ }
2171
+
2172
+ function getObjectStream(params, callback) {
2173
+ params.ReturnStream = true;
2174
+ return getObject.call(this, params, callback);
2175
+ }
2176
+
2177
+ /**
2178
+ * 上传 object
2179
+ * @param {Object} params 参数对象,必须
2180
+ * @param {String} params.Bucket Bucket名称,必须
2181
+ * @param {String} params.Region 地域名称,必须
2182
+ * @param {String} params.Key 文件名称,必须
2183
+ * @param {Buffer || ReadStream || String} params.Body 上传文件的内容或流或字符串
2184
+ * @param {String} params.CacheControl RFC 2616 中定义的缓存策略,将作为 Object 元数据保存,非必须
2185
+ * @param {String} params.ContentDisposition RFC 2616 中定义的文件名称,将作为 Object 元数据保存,非必须
2186
+ * @param {String} params.ContentEncoding RFC 2616 中定义的编码格式,将作为 Object 元数据保存,非必须
2187
+ * @param {String} params.ContentLength RFC 2616 中定义的 HTTP 请求内容长度(字节),必须
2188
+ * @param {String} params.ContentType RFC 2616 中定义的内容类型(MIME),将作为 Object 元数据保存,非必须
2189
+ * @param {String} params.Expect 当使用 Expect: 100-continue 时,在收到服务端确认后,才会发送请求内容,非必须
2190
+ * @param {String} params.Expires RFC 2616 中定义的过期时间,将作为 Object 元数据保存,非必须
2191
+ * @param {String} params.ACL 允许用户自定义文件权限,有效值:private | public-read,非必须
2192
+ * @param {String} params.GrantRead 赋予被授权者读取对象的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,非必须
2193
+ * @param {String} params.GrantReadAcp 赋予被授权者读取对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,非必须
2194
+ * @param {String} params.GrantWriteAcp 赋予被授权者写入对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,非必须
2195
+ * @param {String} params.GrantFullControl 赋予被授权者操作对象的所有权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,非必须
2196
+ * @param {String} params.StorageClass 设置对象的存储级别,枚举值:STANDARD、STANDARD_IA、ARCHIVE,默认值:STANDARD,非必须
2197
+ * @param {String} params.x-cos-meta-* 允许用户自定义的头部信息,将作为对象的元数据保存。大小限制2KB,非必须
2198
+ * @param {String} params.ContentSha1 RFC 3174 中定义的 160-bit 内容 SHA-1 算法校验,非必须
2199
+ * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须
2200
+ * @param {Function} params.onProgress 上传进度回调函数
2201
+ * @param {Function} callback 回调函数,必须
2202
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
2203
+ * @return {Object} data 为对应的 object 数据
2204
+ * @return {String} data.ETag 为对应上传文件的 ETag 值
2205
+ */
2206
+ function putObject(params, callback) {
2207
+ var self = this;
2208
+ var FileSize = params.ContentLength;
2209
+ var onProgress = util.throttleOnProgress.call(self, FileSize, params.onProgress);
2210
+
2211
+ // 特殊处理 Cache-Control、Content-Type,避免代理更改这两个字段导致写入到 Object 属性里
2212
+ var headers = params.Headers;
2213
+ if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = '';
2214
+
2215
+ util.getBodyMd5(self.options.UploadCheckContentMd5, params.Body, function (md5) {
2216
+ if (md5) params.Headers['Content-MD5'] = util.binaryBase64(md5);
2217
+ if (params.ContentLength !== undefined) {
2218
+ params.Headers['Content-Length'] = params.ContentLength;
2219
+ }
2220
+ onProgress(null, true); // 任务状态开始 uploading
2221
+ submitRequest.call(
2222
+ self,
2223
+ {
2224
+ Action: 'name/cos:PutObject',
2225
+ TaskId: params.TaskId,
2226
+ method: 'PUT',
2227
+ Bucket: params.Bucket,
2228
+ Region: params.Region,
2229
+ Key: params.Key,
2230
+ headers: params.Headers,
2231
+ qs: params.Query,
2232
+ body: params.Body,
2233
+ onProgress: onProgress,
2234
+ },
2235
+ function (err, data) {
2236
+ if (err) {
2237
+ onProgress(null, true);
2238
+ return callback(err);
2239
+ }
2240
+ onProgress({ loaded: FileSize, total: FileSize }, true);
2241
+ if (data) {
2242
+ var url = getUrl({
2243
+ ForcePathStyle: self.options.ForcePathStyle,
2244
+ protocol: self.options.Protocol,
2245
+ domain: self.options.Domain,
2246
+ bucket: params.Bucket,
2247
+ region: !self.options.UseAccelerate ? params.Region : 'accelerate',
2248
+ object: params.Key,
2249
+ });
2250
+ url = url.substr(url.indexOf('://') + 3);
2251
+ data.Location = url;
2252
+ if (data.headers && data.headers.etag) data.ETag = data.headers.etag;
2253
+ return callback(null, data);
2254
+ }
2255
+ callback(null, data);
2256
+ }
2257
+ );
2258
+ });
2259
+ }
2260
+
2261
+ /**
2262
+ * 删除 object
2263
+ * @param {Object} params 参数对象,必须
2264
+ * @param {String} params.Bucket Bucket名称,必须
2265
+ * @param {String} params.Region 地域名称,必须
2266
+ * @param {String} params.Key object名称,必须
2267
+ * @param {Function} callback 回调函数,必须
2268
+ * @param {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
2269
+ * @param {Object} data 删除操作成功之后返回的数据
2270
+ */
2271
+ function deleteObject(params, callback) {
2272
+ submitRequest.call(
2273
+ this,
2274
+ {
2275
+ Action: 'name/cos:DeleteObject',
2276
+ method: 'DELETE',
2277
+ Bucket: params.Bucket,
2278
+ Region: params.Region,
2279
+ Key: params.Key,
2280
+ headers: params.Headers,
2281
+ VersionId: params.VersionId,
2282
+ },
2283
+ function (err, data) {
2284
+ if (err) {
2285
+ var statusCode = err.statusCode;
2286
+ if (statusCode && statusCode === 404) {
2287
+ return callback(null, { BucketNotFound: true, statusCode: statusCode });
2288
+ } else {
2289
+ return callback(err);
2290
+ }
2291
+ }
2292
+ callback(null, {
2293
+ statusCode: data.statusCode,
2294
+ headers: data.headers,
2295
+ });
2296
+ }
2297
+ );
2298
+ }
2299
+
2300
+ /**
2301
+ * 获取 object 的 权限列表
2302
+ * @param {Object} params 参数对象,必须
2303
+ * @param {String} params.Bucket Bucket名称,必须
2304
+ * @param {String} params.Region 地域名称,必须
2305
+ * @param {String} params.Key object名称,必须
2306
+ * @param {Function} callback 回调函数,必须
2307
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
2308
+ * @return {Object} data 返回的数据
2309
+ * @return {Object} data.AccessControlPolicy 权限列表
2310
+ */
2311
+ function getObjectAcl(params, callback) {
2312
+ var reqParams = {};
2313
+
2314
+ if (params.VersionId) {
2315
+ reqParams.versionId = params.VersionId;
2316
+ }
2317
+ submitRequest.call(
2318
+ this,
2319
+ {
2320
+ Action: 'name/cos:GetObjectACL',
2321
+ method: 'GET',
2322
+ Bucket: params.Bucket,
2323
+ Region: params.Region,
2324
+ Key: params.Key,
2325
+ headers: params.Headers,
2326
+ qs: reqParams,
2327
+ action: 'acl',
2328
+ },
2329
+ function (err, data) {
2330
+ if (err) return callback(err);
2331
+ var AccessControlPolicy = data.AccessControlPolicy || {};
2332
+ var Owner = AccessControlPolicy.Owner || {};
2333
+ var Grant = (AccessControlPolicy.AccessControlList && AccessControlPolicy.AccessControlList.Grant) || [];
2334
+ Grant = util.isArray(Grant) ? Grant : [Grant];
2335
+ var result = decodeAcl(AccessControlPolicy);
2336
+ delete result.GrantWrite;
2337
+ if (data.headers && data.headers['x-cos-acl']) {
2338
+ result.ACL = data.headers['x-cos-acl'];
2339
+ }
2340
+ result = util.extend(result, {
2341
+ Owner: Owner,
2342
+ Grants: Grant,
2343
+ statusCode: data.statusCode,
2344
+ headers: data.headers,
2345
+ });
2346
+ callback(null, result);
2347
+ }
2348
+ );
2349
+ }
2350
+
2351
+ /**
2352
+ * 设置 object 的 权限列表
2353
+ * @param {Object} params 参数对象,必须
2354
+ * @param {String} params.Bucket Bucket名称,必须
2355
+ * @param {String} params.Region 地域名称,必须
2356
+ * @param {String} params.Key object名称,必须
2357
+ * @param {Function} callback 回调函数,必须
2358
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
2359
+ * @return {Object} data 返回的数据
2360
+ */
2361
+ function putObjectAcl(params, callback) {
2362
+ var headers = params.Headers;
2363
+
2364
+ var xml = '';
2365
+ if (params['AccessControlPolicy']) {
2366
+ var AccessControlPolicy = util.clone(params['AccessControlPolicy'] || {});
2367
+ var Grants = AccessControlPolicy.Grants || AccessControlPolicy.Grant;
2368
+ Grants = util.isArray(Grants) ? Grants : [Grants];
2369
+ delete AccessControlPolicy.Grant;
2370
+ delete AccessControlPolicy.Grants;
2371
+ AccessControlPolicy.AccessControlList = { Grant: Grants };
2372
+ xml = util.json2xml({ AccessControlPolicy: AccessControlPolicy });
2373
+
2374
+ headers['Content-Type'] = 'application/xml';
2375
+ headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
2376
+ }
2377
+
2378
+ // Grant Header 去重
2379
+ util.each(headers, function (val, key) {
2380
+ if (key.indexOf('x-cos-grant-') === 0) {
2381
+ headers[key] = uniqGrant(headers[key]);
2382
+ }
2383
+ });
2384
+
2385
+ submitRequest.call(
2386
+ this,
2387
+ {
2388
+ Action: 'name/cos:PutObjectACL',
2389
+ method: 'PUT',
2390
+ Bucket: params.Bucket,
2391
+ Region: params.Region,
2392
+ Key: params.Key,
2393
+ action: 'acl',
2394
+ headers: headers,
2395
+ body: xml,
2396
+ },
2397
+ function (err, data) {
2398
+ if (err) return callback(err);
2399
+ callback(null, {
2400
+ statusCode: data.statusCode,
2401
+ headers: data.headers,
2402
+ });
2403
+ }
2404
+ );
2405
+ }
2406
+
2407
+ /**
2408
+ * Options Object请求实现跨域访问的预请求。即发出一个 OPTIONS 请求给服务器以确认是否可以进行跨域操作。
2409
+ * @param {Object} params 参数对象,必须
2410
+ * @param {String} params.Bucket Bucket名称,必须
2411
+ * @param {String} params.Region 地域名称,必须
2412
+ * @param {String} params.Key object名称,必须
2413
+ * @param {Function} callback 回调函数,必须
2414
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
2415
+ * @return {Object} data 返回的数据
2416
+ */
2417
+ function optionsObject(params, callback) {
2418
+ var headers = params.Headers;
2419
+ headers['Origin'] = params['Origin'];
2420
+ headers['Access-Control-Request-Method'] = params['AccessControlRequestMethod'];
2421
+ headers['Access-Control-Request-Headers'] = params['AccessControlRequestHeaders'];
2422
+
2423
+ submitRequest.call(
2424
+ this,
2425
+ {
2426
+ Action: 'name/cos:OptionsObject',
2427
+ method: 'OPTIONS',
2428
+ Bucket: params.Bucket,
2429
+ Region: params.Region,
2430
+ Key: params.Key,
2431
+ headers: headers,
2432
+ },
2433
+ function (err, data) {
2434
+ if (err) {
2435
+ if (err.statusCode && err.statusCode === 403) {
2436
+ return callback(null, {
2437
+ OptionsForbidden: true,
2438
+ statusCode: err.statusCode,
2439
+ });
2440
+ }
2441
+ return callback(err);
2442
+ }
2443
+
2444
+ var headers = data.headers || {};
2445
+ callback(null, {
2446
+ AccessControlAllowOrigin: headers['access-control-allow-origin'],
2447
+ AccessControlAllowMethods: headers['access-control-allow-methods'],
2448
+ AccessControlAllowHeaders: headers['access-control-allow-headers'],
2449
+ AccessControlExposeHeaders: headers['access-control-expose-headers'],
2450
+ AccessControlMaxAge: headers['access-control-max-age'],
2451
+ statusCode: data.statusCode,
2452
+ headers: data.headers,
2453
+ });
2454
+ }
2455
+ );
2456
+ }
2457
+
2458
+ /**
2459
+ * @param {Object} 参数列表
2460
+ * @param {String} Bucket Bucket 名称
2461
+ * @param {String} Region 地域名称
2462
+ * @param {String} Key 文件名称
2463
+ * @param {String} CopySource 源文件URL绝对路径,可以通过versionid子资源指定历史版本
2464
+ * @param {String} ACL 允许用户自定义文件权限。有效值:private,public-read默认值:private。
2465
+ * @param {String} GrantRead 赋予被授权者读的权限,格式 x-cos-grant-read: uin=" ",uin=" ",当需要给子账户授权时,uin="RootAcountID/SubAccountID",当需要给根账户授权时,uin="RootAcountID"。
2466
+ * @param {String} GrantWrite 赋予被授权者写的权限,格式 x-cos-grant-write: uin=" ",uin=" ",当需要给子账户授权时,uin="RootAcountID/SubAccountID",当需要给根账户授权时,uin="RootAcountID"。
2467
+ * @param {String} GrantFullControl 赋予被授权者读写权限,格式 x-cos-grant-full-control: uin=" ",uin=" ",当需要给子账户授权时,uin="RootAcountID/SubAccountID",当需要给根账户授权时,uin="RootAcountID"。
2468
+ * @param {String} MetadataDirective 是否拷贝元数据,枚举值:Copy, Replaced,默认值Copy。假如标记为Copy,忽略Header中的用户元数据信息直接复制;假如标记为Replaced,按Header信息修改元数据。当目标路径和原路径一致,即用户试图修改元数据时,必须为Replaced
2469
+ * @param {String} CopySourceIfModifiedSince 当Object在指定时间后被修改,则执行操作,否则返回412。可与x-cos-copy-source-If-None-Match一起使用,与其他条件联合使用返回冲突。
2470
+ * @param {String} CopySourceIfUnmodifiedSince 当Object在指定时间后未被修改,则执行操作,否则返回412。可与x-cos-copy-source-If-Match一起使用,与其他条件联合使用返回冲突。
2471
+ * @param {String} CopySourceIfMatch 当Object的ETag和给定一致时,则执行操作,否则返回412。可与x-cos-copy-source-If-Unmodified-Since一起使用,与其他条件联合使用返回冲突。
2472
+ * @param {String} CopySourceIfNoneMatch 当Object的ETag和给定不一致时,则执行操作,否则返回412。可与x-cos-copy-source-If-Modified-Since一起使用,与其他条件联合使用返回冲突。
2473
+ * @param {String} StorageClass 存储级别,枚举值:存储级别,枚举值:Standard, Standard_IA,Archive;默认值:Standard
2474
+ * @param {String} CacheControl 指定所有缓存机制在整个请求/响应链中必须服从的指令。
2475
+ * @param {String} ContentDisposition MIME 协议的扩展,MIME 协议指示 MIME 用户代理如何显示附加的文件
2476
+ * @param {String} ContentEncoding HTTP 中用来对「采用何种编码格式传输正文」进行协定的一对头部字段
2477
+ * @param {String} ContentLength 设置响应消息的实体内容的大小,单位为字节
2478
+ * @param {String} ContentType RFC 2616 中定义的 HTTP 请求内容类型(MIME),例如text/plain
2479
+ * @param {String} Expect 请求的特定的服务器行为
2480
+ * @param {String} Expires 响应过期的日期和时间
2481
+ * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须
2482
+ * @param {String} ContentLanguage 指定内容语言
2483
+ * @param {String} x-cos-meta-* 允许用户自定义的头部信息,将作为 Object 元数据返回。大小限制2K。
2484
+ */
2485
+ function putObjectCopy(params, callback) {
2486
+ // 特殊处理 Cache-Control
2487
+ var headers = params.Headers;
2488
+ if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = '';
2489
+
2490
+ var CopySource = params.CopySource || '';
2491
+ var m = util.getSourceParams.call(this, CopySource);
2492
+ if (!m) {
2493
+ callback(util.error(new Error('CopySource format error')));
2494
+ return;
2495
+ }
2496
+
2497
+ var SourceBucket = m.Bucket;
2498
+ var SourceRegion = m.Region;
2499
+ var SourceKey = decodeURIComponent(m.Key);
2500
+
2501
+ submitRequest.call(
2502
+ this,
2503
+ {
2504
+ Scope: [
2505
+ {
2506
+ action: 'name/cos:GetObject',
2507
+ bucket: SourceBucket,
2508
+ region: SourceRegion,
2509
+ prefix: SourceKey,
2510
+ },
2511
+ {
2512
+ action: 'name/cos:PutObject',
2513
+ bucket: params.Bucket,
2514
+ region: params.Region,
2515
+ prefix: params.Key,
2516
+ },
2517
+ ],
2518
+ method: 'PUT',
2519
+ Bucket: params.Bucket,
2520
+ Region: params.Region,
2521
+ Key: params.Key,
2522
+ VersionId: params.VersionId,
2523
+ headers: params.Headers,
2524
+ },
2525
+ function (err, data) {
2526
+ if (err) return callback(err);
2527
+ var result = util.clone(data.CopyObjectResult || {});
2528
+ util.extend(result, {
2529
+ statusCode: data.statusCode,
2530
+ headers: data.headers,
2531
+ });
2532
+ callback(null, result);
2533
+ }
2534
+ );
2535
+ }
2536
+
2537
+ function uploadPartCopy(params, callback) {
2538
+ var CopySource = params.CopySource || '';
2539
+ var m = util.getSourceParams.call(this, CopySource);
2540
+ if (!m) {
2541
+ callback(util.error(new Error('CopySource format error')));
2542
+ return;
2543
+ }
2544
+
2545
+ var SourceBucket = m.Bucket;
2546
+ var SourceRegion = m.Region;
2547
+ var SourceKey = decodeURIComponent(m.Key);
2548
+
2549
+ submitRequest.call(
2550
+ this,
2551
+ {
2552
+ Scope: [
2553
+ {
2554
+ action: 'name/cos:GetObject',
2555
+ bucket: SourceBucket,
2556
+ region: SourceRegion,
2557
+ prefix: SourceKey,
2558
+ },
2559
+ {
2560
+ action: 'name/cos:PutObject',
2561
+ bucket: params.Bucket,
2562
+ region: params.Region,
2563
+ prefix: params.Key,
2564
+ },
2565
+ ],
2566
+ method: 'PUT',
2567
+ Bucket: params.Bucket,
2568
+ Region: params.Region,
2569
+ Key: params.Key,
2570
+ VersionId: params.VersionId,
2571
+ qs: {
2572
+ partNumber: params['PartNumber'],
2573
+ uploadId: params['UploadId'],
2574
+ },
2575
+ headers: params.Headers,
2576
+ },
2577
+ function (err, data) {
2578
+ if (err) return callback(err);
2579
+ var result = util.clone(data.CopyPartResult || {});
2580
+ util.extend(result, {
2581
+ statusCode: data.statusCode,
2582
+ headers: data.headers,
2583
+ });
2584
+ callback(null, result);
2585
+ }
2586
+ );
2587
+ }
2588
+
2589
+ function deleteMultipleObject(params, callback) {
2590
+ var Objects = params.Objects || [];
2591
+ var Quiet = params.Quiet;
2592
+ Objects = util.isArray(Objects) ? Objects : [Objects];
2593
+
2594
+ var xml = util.json2xml({ Delete: { Object: Objects, Quiet: Quiet || false } });
2595
+
2596
+ var headers = params.Headers;
2597
+ headers['Content-Type'] = 'application/xml';
2598
+ headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
2599
+
2600
+ var Scope = util.map(Objects, function (v) {
2601
+ return {
2602
+ action: 'name/cos:DeleteObject',
2603
+ bucket: params.Bucket,
2604
+ region: params.Region,
2605
+ prefix: v.Key,
2606
+ };
2607
+ });
2608
+
2609
+ submitRequest.call(
2610
+ this,
2611
+ {
2612
+ Scope: Scope,
2613
+ method: 'POST',
2614
+ Bucket: params.Bucket,
2615
+ Region: params.Region,
2616
+ body: xml,
2617
+ action: 'delete',
2618
+ headers: headers,
2619
+ },
2620
+ function (err, data) {
2621
+ if (err) return callback(err);
2622
+ var DeleteResult = data.DeleteResult || {};
2623
+ var Deleted = DeleteResult.Deleted || [];
2624
+ var Errors = DeleteResult.Error || [];
2625
+
2626
+ Deleted = util.isArray(Deleted) ? Deleted : [Deleted];
2627
+ Errors = util.isArray(Errors) ? Errors : [Errors];
2628
+
2629
+ var result = util.clone(DeleteResult);
2630
+ util.extend(result, {
2631
+ Error: Errors,
2632
+ Deleted: Deleted,
2633
+ statusCode: data.statusCode,
2634
+ headers: data.headers,
2635
+ });
2636
+ callback(null, result);
2637
+ }
2638
+ );
2639
+ }
2640
+
2641
+ function restoreObject(params, callback) {
2642
+ var headers = params.Headers;
2643
+ if (!params['RestoreRequest']) {
2644
+ callback(util.error(new Error('missing param RestoreRequest')));
2645
+ return;
2646
+ }
2647
+
2648
+ var RestoreRequest = params.RestoreRequest || {};
2649
+ var xml = util.json2xml({ RestoreRequest: RestoreRequest });
2650
+
2651
+ headers['Content-Type'] = 'application/xml';
2652
+ headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
2653
+
2654
+ submitRequest.call(
2655
+ this,
2656
+ {
2657
+ Action: 'name/cos:RestoreObject',
2658
+ method: 'POST',
2659
+ Bucket: params.Bucket,
2660
+ Region: params.Region,
2661
+ Key: params.Key,
2662
+ VersionId: params.VersionId,
2663
+ body: xml,
2664
+ action: 'restore',
2665
+ headers: headers,
2666
+ },
2667
+ callback
2668
+ );
2669
+ }
2670
+
2671
+ /**
2672
+ * 设置 Object 的标签
2673
+ * @param {Object} params 参数对象,必须
2674
+ * @param {String} params.Bucket Object名称,必须
2675
+ * @param {String} params.Region 地域名称,必须
2676
+ * @param {Array} params.TagSet 标签设置,必须
2677
+ * @param {Function} callback 回调函数,必须
2678
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/42998
2679
+ * @return {Object} data 返回数据
2680
+ */
2681
+ function putObjectTagging(params, callback) {
2682
+ var Tagging = params['Tagging'] || {};
2683
+ var Tags = Tagging.TagSet || Tagging.Tags || params['Tags'] || [];
2684
+ Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]);
2685
+ var xml = util.json2xml({ Tagging: { TagSet: { Tag: Tags } } });
2686
+
2687
+ var headers = params.Headers;
2688
+ headers['Content-Type'] = 'application/xml';
2689
+ headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
2690
+
2691
+ submitRequest.call(
2692
+ this,
2693
+ {
2694
+ Action: 'name/cos:PutObjectTagging',
2695
+ method: 'PUT',
2696
+ Bucket: params.Bucket,
2697
+ Key: params.Key,
2698
+ Region: params.Region,
2699
+ body: xml,
2700
+ action: 'tagging',
2701
+ headers: headers,
2702
+ VersionId: params.VersionId,
2703
+ },
2704
+ function (err, data) {
2705
+ if (err && err.statusCode === 204) {
2706
+ return callback(null, { statusCode: err.statusCode });
2707
+ } else if (err) {
2708
+ return callback(err);
2709
+ }
2710
+ callback(null, {
2711
+ statusCode: data.statusCode,
2712
+ headers: data.headers,
2713
+ });
2714
+ }
2715
+ );
2716
+ }
2717
+
2718
+ /**
2719
+ * 获取 Object 的标签设置
2720
+ * @param {Object} params 参数对象,必须
2721
+ * @param {String} params.Bucket Bucket名称,必须
2722
+ * @param {String} params.Region 地域名称,必须
2723
+ * @param {Function} callback 回调函数,必须
2724
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/42998
2725
+ * @return {Object} data 返回数据
2726
+ */
2727
+ function getObjectTagging(params, callback) {
2728
+ submitRequest.call(
2729
+ this,
2730
+ {
2731
+ Action: 'name/cos:GetObjectTagging',
2732
+ method: 'GET',
2733
+ Key: params.Key,
2734
+ Bucket: params.Bucket,
2735
+ Region: params.Region,
2736
+ headers: params.Headers,
2737
+ action: 'tagging',
2738
+ VersionId: params.VersionId,
2739
+ },
2740
+ function (err, data) {
2741
+ if (err) {
2742
+ if (err.statusCode === 404 && err.error && (err.error === 'Not Found' || err.error.Code === 'NoSuchTagSet')) {
2743
+ var result = {
2744
+ Tags: [],
2745
+ statusCode: err.statusCode,
2746
+ };
2747
+ err.headers && (result.headers = err.headers);
2748
+ callback(null, result);
2749
+ } else {
2750
+ callback(err);
2751
+ }
2752
+ return;
2753
+ }
2754
+ var Tags = [];
2755
+ try {
2756
+ Tags = data.Tagging.TagSet.Tag || [];
2757
+ } catch (e) {}
2758
+ Tags = util.clone(util.isArray(Tags) ? Tags : [Tags]);
2759
+ callback(null, {
2760
+ Tags: Tags,
2761
+ statusCode: data.statusCode,
2762
+ headers: data.headers,
2763
+ });
2764
+ }
2765
+ );
2766
+ }
2767
+
2768
+ /**
2769
+ * 删除 Object 的 标签设置
2770
+ * @param {Object} params 参数对象,必须
2771
+ * @param {String} params.Bucket Object名称,必须
2772
+ * @param {String} params.Region 地域名称,必须
2773
+ * @param {Function} callback 回调函数,必须
2774
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/42998
2775
+ * @return {Object} data 返回的数据
2776
+ */
2777
+ function deleteObjectTagging(params, callback) {
2778
+ submitRequest.call(
2779
+ this,
2780
+ {
2781
+ Action: 'name/cos:DeleteObjectTagging',
2782
+ method: 'DELETE',
2783
+ Bucket: params.Bucket,
2784
+ Region: params.Region,
2785
+ Key: params.Key,
2786
+ headers: params.Headers,
2787
+ action: 'tagging',
2788
+ VersionId: params.VersionId,
2789
+ },
2790
+ function (err, data) {
2791
+ if (err && err.statusCode === 204) {
2792
+ return callback(null, { statusCode: err.statusCode });
2793
+ } else if (err) {
2794
+ return callback(err);
2795
+ }
2796
+ callback(null, {
2797
+ statusCode: data.statusCode,
2798
+ headers: data.headers,
2799
+ });
2800
+ }
2801
+ );
2802
+ }
2803
+
2804
+ /**
2805
+ * 使用 SQL 语句从指定对象(CSV 格式或者 JSON 格式)中检索内容
2806
+ * @param {Object} params 参数对象,必须
2807
+ * @param {String} params.Bucket Object名称,必须
2808
+ * @param {String} params.Region 地域名称,必须
2809
+ * @param {Object} params.SelectRequest 地域名称,必须
2810
+ * @param {Function} callback 回调函数,必须
2811
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/42998
2812
+ * @return {Object} data 返回的数据
2813
+ */
2814
+ function selectObjectContent(params, callback) {
2815
+ var SelectType = params['SelectType'];
2816
+ if (!SelectType) return callback(util.error(new Error('missing param SelectType')));
2817
+
2818
+ var SelectRequest = params['SelectRequest'] || {};
2819
+ var xml = util.json2xml({ SelectRequest: SelectRequest });
2820
+
2821
+ var headers = params.Headers;
2822
+ headers['Content-Type'] = 'application/xml';
2823
+ headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
2824
+
2825
+ var outputStream;
2826
+ var selectResult = {};
2827
+ var SelectStream = require('./select-stream');
2828
+ if (params.ReturnStream && params.DataType === 'raw') {
2829
+ // 流 && raw 直接原样数据吐回
2830
+ outputStream = new Stream.PassThrough();
2831
+ } else {
2832
+ // 包含 params.ReturnStream || !params.ReturnStream
2833
+ outputStream = new SelectStream();
2834
+ outputStream.on('message:progress', function (progress) {
2835
+ if (typeof params.onProgress === 'function') params.onProgress(progress);
2836
+ });
2837
+ outputStream.on('message:stats', function (stats) {
2838
+ selectResult.stats = stats;
2839
+ });
2840
+ outputStream.on('message:error', function (error) {
2841
+ selectResult.error = error;
2842
+ });
2843
+ }
2844
+ submitRequest.call(
2845
+ this,
2846
+ {
2847
+ Action: 'name/cos:GetObject',
2848
+ method: 'POST',
2849
+ Bucket: params.Bucket,
2850
+ Region: params.Region,
2851
+ Key: params.Key,
2852
+ headers: params.Headers,
2853
+ action: 'select',
2854
+ qs: {
2855
+ 'select-type': params['SelectType'],
2856
+ },
2857
+ VersionId: params.VersionId,
2858
+ body: xml,
2859
+ rawBody: true,
2860
+ outputStream: outputStream,
2861
+ },
2862
+ function (err, data) {
2863
+ if (err && err.statusCode === 204) {
2864
+ return callback(null, { statusCode: err.statusCode });
2865
+ } else if (err) {
2866
+ if (outputStream) outputStream.emit('error', err);
2867
+ return callback(err);
2868
+ } else if (selectResult.error) {
2869
+ return callback(
2870
+ util.extend(selectResult.error, {
2871
+ statusCode: data.statusCode,
2872
+ headers: data.headers,
2873
+ })
2874
+ );
2875
+ }
2876
+ var result = {
2877
+ statusCode: data.statusCode,
2878
+ headers: data.headers,
2879
+ };
2880
+ // 只要流里有解析出 stats,就返回 Stats
2881
+ if (selectResult.stats) result.Stats = selectResult.stats;
2882
+ // 只要有 records,就返回 Payload
2883
+ if (selectResult.records) result.Payload = Buffer.concat(selectResult.records);
2884
+ callback(null, result);
2885
+ }
2886
+ );
2887
+ if (!params.ReturnStream && params.DataType !== 'raw') {
2888
+ selectResult.records = [];
2889
+ outputStream.pipe(
2890
+ new Stream.Writable({
2891
+ write: function (chunk, encoding, callback) {
2892
+ selectResult.records.push(chunk);
2893
+ callback();
2894
+ },
2895
+ writev: function (chunks, encoding, callback) {
2896
+ chunks.forEach(function (item) {
2897
+ selectResult.records.push(chunks);
2898
+ });
2899
+ callback();
2900
+ },
2901
+ })
2902
+ );
2903
+ outputStream.pipe(outputStream);
2904
+ }
2905
+ if (params.ReturnStream) return outputStream;
2906
+ }
2907
+
2908
+ /**
2909
+ * 使用 SQL 语句从指定对象(CSV 格式或者 JSON 格式)中检索内容
2910
+ * @param {Object} params 参数对象,必须
2911
+ * @param {String} params.Bucket Object名称,必须
2912
+ * @param {String} params.Region 地域名称,必须
2913
+ * @param {Object} params.SelectRequest 地域名称,必须
2914
+ * @param {Function} callback 回调函数,必须
2915
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/42998
2916
+ * @return {Object} data 返回的数据
2917
+ * @return {Object} Stream 返回值
2918
+ */
2919
+ function selectObjectContentStream(params, callback) {
2920
+ params.ReturnStream = true;
2921
+ return selectObjectContent.call(this, params, callback);
2922
+ }
2923
+
2924
+ // 分块上传
2925
+
2926
+ /**
2927
+ * 初始化分块上传
2928
+ * @param {Object} params 参数对象,必须
2929
+ * @param {String} params.Bucket Bucket名称,必须
2930
+ * @param {String} params.Region 地域名称,必须
2931
+ * @param {String} params.Key object名称,必须
2932
+ * @param {String} params.UploadId object名称,必须
2933
+ * @param {String} params.CacheControl RFC 2616 中定义的缓存策略,将作为 Object 元数据保存,非必须
2934
+ * @param {String} params.ContentDisposition RFC 2616 中定义的文件名称,将作为 Object 元数据保存 ,非必须
2935
+ * @param {String} params.ContentEncoding RFC 2616 中定义的编码格式,将作为 Object 元数据保存,非必须
2936
+ * @param {String} params.ContentType RFC 2616 中定义的内容类型(MIME),将作为 Object 元数据保存,非必须
2937
+ * @param {String} params.Expires RFC 2616 中定义的过期时间,将作为 Object 元数据保存,非必须
2938
+ * @param {String} params.ACL 允许用户自定义文件权限,非必须
2939
+ * @param {String} params.GrantRead 赋予被授权者读的权限 ,非必须
2940
+ * @param {String} params.GrantWrite 赋予被授权者写的权限 ,非必须
2941
+ * @param {String} params.GrantFullControl 赋予被授权者读写权限 ,非必须
2942
+ * @param {String} params.StorageClass 设置Object的存储级别,枚举值:Standard,Standard_IA,Archive,非必须
2943
+ * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须
2944
+ * @param {Function} callback 回调函数,必须
2945
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
2946
+ * @return {Object} data 返回的数据
2947
+ */
2948
+ function multipartInit(params, callback) {
2949
+ // 特殊处理 Cache-Control
2950
+ var headers = params.Headers;
2951
+
2952
+ // 特殊处理 Cache-Control、Content-Type
2953
+ if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = '';
2954
+ if (!headers['Content-Type'] && !headers['content-type'])
2955
+ headers['Content-Type'] = (params.Body && params.Body.type) || '';
2956
+
2957
+ submitRequest.call(
2958
+ this,
2959
+ {
2960
+ Action: 'name/cos:InitiateMultipartUpload',
2961
+ method: 'POST',
2962
+ Bucket: params.Bucket,
2963
+ Region: params.Region,
2964
+ Key: params.Key,
2965
+ action: 'uploads',
2966
+ headers: params.Headers,
2967
+ qs: params.Query,
2968
+ },
2969
+ function (err, data) {
2970
+ if (err) return callback(err);
2971
+ data = util.clone(data || {});
2972
+ if (data && data.InitiateMultipartUploadResult) {
2973
+ return callback(
2974
+ null,
2975
+ util.extend(data.InitiateMultipartUploadResult, {
2976
+ statusCode: data.statusCode,
2977
+ headers: data.headers,
2978
+ })
2979
+ );
2980
+ }
2981
+ callback(null, data);
2982
+ }
2983
+ );
2984
+ }
2985
+
2986
+ /**
2987
+ * 分块上传
2988
+ * @param {Object} params 参数对象,必须
2989
+ * @param {String} params.Bucket Bucket名称,必须
2990
+ * @param {String} params.Region 地域名称,必须
2991
+ * @param {String} params.Key object名称,必须
2992
+ * @param {Buffer || Stream || String} params.Body 上传文件对象或字符串
2993
+ * @param {String} params.ContentLength RFC 2616 中定义的 HTTP 请求内容长度(字节),非必须
2994
+ * @param {String} params.Expect 当使用 Expect: 100-continue 时,在收到服务端确认后,才会发送请求内容,非必须
2995
+ * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须
2996
+ * @param {String} params.ContentSha1 RFC 3174 中定义的 160-bit 内容 SHA-1 算法校验值,非必须
2997
+ * @param {Function} callback 回调函数,必须
2998
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
2999
+ * @return {Object} data 返回的数据
3000
+ * @return {Object} data.ETag 返回的文件分块 sha1 值
3001
+ */
3002
+ function multipartUpload(params, callback) {
3003
+ var self = this;
3004
+ util.getFileSize('multipartUpload', params, function () {
3005
+ util.getBodyMd5(self.options.UploadCheckContentMd5, params.Body, function (md5) {
3006
+ if (md5) params.Headers['Content-MD5'] = util.binaryBase64(md5);
3007
+ submitRequest.call(
3008
+ self,
3009
+ {
3010
+ Action: 'name/cos:UploadPart',
3011
+ TaskId: params.TaskId,
3012
+ method: 'PUT',
3013
+ Bucket: params.Bucket,
3014
+ Region: params.Region,
3015
+ Key: params.Key,
3016
+ qs: {
3017
+ partNumber: params['PartNumber'],
3018
+ uploadId: params['UploadId'],
3019
+ },
3020
+ headers: params.Headers,
3021
+ onProgress: params.onProgress,
3022
+ body: params.Body || null,
3023
+ },
3024
+ function (err, data) {
3025
+ if (err) return callback(err);
3026
+ callback(null, {
3027
+ ETag: util.attr(data.headers, 'etag', ''),
3028
+ statusCode: data.statusCode,
3029
+ headers: data.headers,
3030
+ });
3031
+ }
3032
+ );
3033
+ });
3034
+ });
3035
+ }
3036
+
3037
+ /**
3038
+ * 完成分块上传
3039
+ * @param {Object} params 参数对象,必须
3040
+ * @param {String} params.Bucket Bucket名称,必须
3041
+ * @param {String} params.Region 地域名称,必须
3042
+ * @param {String} params.Key object名称,必须
3043
+ * @param {Array} params.Parts 分块信息列表,必须
3044
+ * @param {String} params.Parts[i].PartNumber 块编号,必须
3045
+ * @param {String} params.Parts[i].ETag 分块的 sha1 校验值
3046
+ * @param {Function} callback 回调函数,必须
3047
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
3048
+ * @return {Object} data 返回的数据
3049
+ * @return {Object} data.CompleteMultipartUpload 完成分块上传后的文件信息,包括Location, Bucket, Key 和 ETag
3050
+ */
3051
+ function multipartComplete(params, callback) {
3052
+ var self = this;
3053
+
3054
+ var UploadId = params.UploadId;
3055
+
3056
+ var Parts = params['Parts'];
3057
+
3058
+ for (var i = 0, len = Parts.length; i < len; i++) {
3059
+ if (Parts[i]['ETag'].indexOf('"') === 0) {
3060
+ continue;
3061
+ }
3062
+ Parts[i]['ETag'] = '"' + Parts[i]['ETag'] + '"';
3063
+ }
3064
+
3065
+ var xml = util.json2xml({ CompleteMultipartUpload: { Part: Parts } });
3066
+ // CSP/ceph CompleteMultipartUpload 接口 body 写死了限制 1MB,这里醉倒 10000 片时,xml 字符串去掉空格853KB
3067
+ xml = xml.replace(/\n\s*/g, '');
3068
+
3069
+ var headers = params.Headers;
3070
+ headers['Content-Type'] = 'application/xml';
3071
+ headers['Content-MD5'] = util.binaryBase64(util.md5(xml));
3072
+
3073
+ submitRequest.call(
3074
+ this,
3075
+ {
3076
+ Action: 'name/cos:CompleteMultipartUpload',
3077
+ method: 'POST',
3078
+ Bucket: params.Bucket,
3079
+ Region: params.Region,
3080
+ Key: params.Key,
3081
+ qs: {
3082
+ uploadId: UploadId,
3083
+ },
3084
+ body: xml,
3085
+ headers: headers,
3086
+ },
3087
+ function (err, data) {
3088
+ if (err) return callback(err);
3089
+ var url = getUrl({
3090
+ ForcePathStyle: self.options.ForcePathStyle,
3091
+ protocol: self.options.Protocol,
3092
+ domain: self.options.Domain,
3093
+ bucket: params.Bucket,
3094
+ region: params.Region,
3095
+ object: params.Key,
3096
+ isLocation: true,
3097
+ });
3098
+ var res = data.CompleteMultipartUploadResult || {};
3099
+ if (res.ProcessResults) {
3100
+ if (res && res.ProcessResults) {
3101
+ res.UploadResult = {
3102
+ OriginalInfo: {
3103
+ Key: res.Key,
3104
+ Location: url,
3105
+ ETag: res.ETag,
3106
+ ImageInfo: res.ImageInfo,
3107
+ },
3108
+ ProcessResults: res.ProcessResults,
3109
+ };
3110
+ delete res.ImageInfo;
3111
+ delete res.ProcessResults;
3112
+ }
3113
+ }
3114
+ var result = util.extend(res, {
3115
+ Location: url,
3116
+ statusCode: data.statusCode,
3117
+ headers: data.headers,
3118
+ });
3119
+ callback(null, result);
3120
+ }
3121
+ );
3122
+ }
3123
+
3124
+ /**
3125
+ * 分块上传任务列表查询
3126
+ * @param {Object} params 参数对象,必须
3127
+ * @param {String} params.Bucket Bucket名称,必须
3128
+ * @param {String} params.Region 地域名称,必须
3129
+ * @param {String} params.Delimiter 定界符为一个符号,如果有Prefix,则将Prefix到delimiter之间的相同路径归为一类,定义为Common Prefix,然后列出所有Common Prefix。如果没有Prefix,则从路径起点开始,非必须
3130
+ * @param {String} params.EncodingType 规定返回值的编码方式,非必须
3131
+ * @param {String} params.Prefix 前缀匹配,用来规定返回的文件前缀地址,非必须
3132
+ * @param {String} params.MaxUploads 单次返回最大的条目数量,默认1000,非必须
3133
+ * @param {String} params.KeyMarker 与upload-id-marker一起使用 </Br>当upload-id-marker未被指定时,ObjectName字母顺序大于key-marker的条目将被列出 </Br>当upload-id-marker被指定时,ObjectName字母顺序大于key-marker的条目被列出,ObjectName字母顺序等于key-marker同时UploadId大于upload-id-marker的条目将被列出,非必须
3134
+ * @param {String} params.UploadIdMarker 与key-marker一起使用 </Br>当key-marker未被指定时,upload-id-marker将被忽略 </Br>当key-marker被指定时,ObjectName字母顺序大于key-marker的条目被列出,ObjectName字母顺序等于key-marker同时UploadId大于upload-id-marker的条目将被列出,非必须
3135
+ * @param {Function} callback 回调函数,必须
3136
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
3137
+ * @return {Object} data 返回的数据
3138
+ * @return {Object} data.ListMultipartUploadsResult 分块上传任务信息
3139
+ */
3140
+ function multipartList(params, callback) {
3141
+ var reqParams = {};
3142
+
3143
+ reqParams['delimiter'] = params['Delimiter'];
3144
+ reqParams['encoding-type'] = params['EncodingType'];
3145
+ reqParams['prefix'] = params['Prefix'] || '';
3146
+
3147
+ reqParams['max-uploads'] = params['MaxUploads'];
3148
+
3149
+ reqParams['key-marker'] = params['KeyMarker'];
3150
+ reqParams['upload-id-marker'] = params['UploadIdMarker'];
3151
+
3152
+ reqParams = util.clearKey(reqParams);
3153
+
3154
+ submitRequest.call(
3155
+ this,
3156
+ {
3157
+ Action: 'name/cos:ListMultipartUploads',
3158
+ ResourceKey: reqParams['prefix'],
3159
+ method: 'GET',
3160
+ Bucket: params.Bucket,
3161
+ Region: params.Region,
3162
+ headers: params.Headers,
3163
+ qs: reqParams,
3164
+ action: 'uploads',
3165
+ },
3166
+ function (err, data) {
3167
+ if (err) return callback(err);
3168
+
3169
+ if (data && data.ListMultipartUploadsResult) {
3170
+ var Upload = data.ListMultipartUploadsResult.Upload || [];
3171
+ Upload = util.isArray(Upload) ? Upload : [Upload];
3172
+ data.ListMultipartUploadsResult.Upload = Upload;
3173
+ }
3174
+ var result = util.clone(data.ListMultipartUploadsResult || {});
3175
+ util.extend(result, {
3176
+ statusCode: data.statusCode,
3177
+ headers: data.headers,
3178
+ });
3179
+ callback(null, result);
3180
+ }
3181
+ );
3182
+ }
3183
+
3184
+ /**
3185
+ * 上传的分块列表查询
3186
+ * @param {Object} params 参数对象,必须
3187
+ * @param {String} params.Bucket Bucket名称,必须
3188
+ * @param {String} params.Region 地域名称,必须
3189
+ * @param {String} params.Key object名称,必须
3190
+ * @param {String} params.UploadId 标示本次分块上传的ID,必须
3191
+ * @param {String} params.EncodingType 规定返回值的编码方式,非必须
3192
+ * @param {String} params.MaxParts 单次返回最大的条目数量,默认1000,非必须
3193
+ * @param {String} params.PartNumberMarker 默认以UTF-8二进制顺序列出条目,所有列出条目从marker开始,非必须
3194
+ * @param {Function} callback 回调函数,必须
3195
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
3196
+ * @return {Object} data 返回的数据
3197
+ * @return {Object} data.ListMultipartUploadsResult 分块信息
3198
+ */
3199
+ function multipartListPart(params, callback) {
3200
+ var reqParams = {};
3201
+
3202
+ reqParams['uploadId'] = params['UploadId'];
3203
+ reqParams['encoding-type'] = params['EncodingType'];
3204
+ reqParams['max-parts'] = params['MaxParts'];
3205
+ reqParams['part-number-marker'] = params['PartNumberMarker'];
3206
+
3207
+ submitRequest.call(
3208
+ this,
3209
+ {
3210
+ Action: 'name/cos:ListParts',
3211
+ method: 'GET',
3212
+ Bucket: params.Bucket,
3213
+ Region: params.Region,
3214
+ Key: params.Key,
3215
+ headers: params.Headers,
3216
+ qs: reqParams,
3217
+ },
3218
+ function (err, data) {
3219
+ if (err) return callback(err);
3220
+ var ListPartsResult = data.ListPartsResult || {};
3221
+ var Part = ListPartsResult.Part || [];
3222
+ Part = util.isArray(Part) ? Part : [Part];
3223
+
3224
+ ListPartsResult.Part = Part;
3225
+ var result = util.clone(ListPartsResult);
3226
+ util.extend(result, {
3227
+ statusCode: data.statusCode,
3228
+ headers: data.headers,
3229
+ });
3230
+ callback(null, result);
3231
+ }
3232
+ );
3233
+ }
3234
+
3235
+ /**
3236
+ * 抛弃分块上传
3237
+ * @param {Object} params 参数对象,必须
3238
+ * @param {String} params.Bucket Bucket名称,必须
3239
+ * @param {String} params.Region 地域名称,必须
3240
+ * @param {String} params.Key object名称,必须
3241
+ * @param {String} params.UploadId 标示本次分块上传的ID,必须
3242
+ * @param {Function} callback 回调函数,必须
3243
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
3244
+ * @return {Object} data 返回的数据
3245
+ */
3246
+ function multipartAbort(params, callback) {
3247
+ var reqParams = {};
3248
+
3249
+ reqParams['uploadId'] = params['UploadId'];
3250
+ submitRequest.call(
3251
+ this,
3252
+ {
3253
+ Action: 'name/cos:AbortMultipartUpload',
3254
+ method: 'DELETE',
3255
+ Bucket: params.Bucket,
3256
+ Region: params.Region,
3257
+ Key: params.Key,
3258
+ headers: params.Headers,
3259
+ qs: reqParams,
3260
+ },
3261
+ function (err, data) {
3262
+ if (err) return callback(err);
3263
+ callback(null, {
3264
+ statusCode: data.statusCode,
3265
+ headers: data.headers,
3266
+ });
3267
+ }
3268
+ );
3269
+ }
3270
+
3271
+ /**
3272
+ * 追加上传
3273
+ * @param {Object} params 参数对象,必须
3274
+ * @param {String} params.Bucket Bucket名称,必须
3275
+ * @param {String} params.Region 地域名称,必须
3276
+ * @param {String} params.Key object名称,必须
3277
+ * @param {{Buffer || ReadStream || String}} params.Body 上传文件对象或字符串
3278
+ * @param {Number} params.Position 追加操作的起始点,单位为字节,必须
3279
+ * @param {String} params.CacheControl RFC 2616 中定义的缓存策略,将作为 Object 元数据保存,非必须
3280
+ * @param {String} params.ContentDisposition RFC 2616 中定义的文件名称,将作为 Object 元数据保存,非必须
3281
+ * @param {String} params.ContentEncoding RFC 2616 中定义的编码格式,将作为 Object 元数据保存,非必须
3282
+ * @param {String} params.ContentLength RFC 2616 中定义的 HTTP 请求内容长度(字节),必须
3283
+ * @param {String} params.ContentType RFC 2616 中定义的内容类型(MIME),将作为 Object 元数据保存,非必须
3284
+ * @param {String} params.Expect 当使用 Expect: 100-continue 时,在收到服务端确认后,才会发送请求内容,非必须
3285
+ * @param {String} params.Expires RFC 2616 中定义的过期时间,将作为 Object 元数据保存,非必须
3286
+ * @param {String} params.ACL 允许用户自定义文件权限,有效值:private | public-read,非必须
3287
+ * @param {String} params.GrantRead 赋予被授权者读取对象的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,非必须
3288
+ * @param {String} params.GrantReadAcp 赋予被授权者读取对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,非必须
3289
+ * @param {String} params.GrantWriteAcp 赋予被授权者写入对象的访问控制列表(ACL)的权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,非必须
3290
+ * @param {String} params.GrantFullControl 赋予被授权者操作对象的所有权限,格式:id="[OwnerUin]",可使用半角逗号(,)分隔多组被授权者,非必须
3291
+ * @param {String} params.StorageClass 设置对象的存储级别,枚举值:STANDARD、STANDARD_IA、ARCHIVE,默认值:STANDARD,非必须
3292
+ * @param {String} params.x-cos-meta-* 允许用户自定义的头部信息,将作为对象的元数据保存。大小限制2KB,非必须
3293
+ * @param {String} params.ContentSha1 RFC 3174 中定义的 160-bit 内容 SHA-1 算法校验,非必须
3294
+ * @param {String} params.ServerSideEncryption 支持按照指定的加密算法进行服务端数据加密,格式 x-cos-server-side-encryption: "AES256",非必须
3295
+ * @param {Function} callback 回调函数,必须
3296
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
3297
+ * @return {Object} data 返回的数据
3298
+ */
3299
+ function appendObject(params, callback) {
3300
+ // 特殊处理 Cache-Control、Content-Type,避免代理更改这两个字段导致写入到 Object 属性里
3301
+ var headers = params.Headers;
3302
+ if (!headers['Cache-Control'] && !headers['cache-control']) headers['Cache-Control'] = '';
3303
+
3304
+ submitRequest.call(
3305
+ this,
3306
+ {
3307
+ Action: 'name/cos:AppendObject',
3308
+ method: 'POST',
3309
+ Bucket: params.Bucket,
3310
+ Region: params.Region,
3311
+ action: 'append',
3312
+ Key: params.Key,
3313
+ body: params.Body,
3314
+ qs: {
3315
+ position: params.Position,
3316
+ },
3317
+ headers: params.Headers,
3318
+ },
3319
+ function (err, data) {
3320
+ if (err) return callback(err);
3321
+ callback(null, data);
3322
+ }
3323
+ );
3324
+ }
3325
+
3326
+ /**
3327
+ * cos 内置请求
3328
+ * @param {Object} params 参数对象,必须
3329
+ * @param {String} params.Bucket Bucket名称,必须
3330
+ * @param {String} params.Region 地域名称,必须
3331
+ * @param {String} params.Key object名称,必须
3332
+ * @param {Function} callback 回调函数,必须
3333
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
3334
+ * @return {Object} data 返回的数据
3335
+ */
3336
+ function request(params, callback) {
3337
+ var Query = params.Query || {};
3338
+ // 处理 url
3339
+ if (params.Url) {
3340
+ var m = params.Url.match(/^https?:\/\/([^/]+)(\/[^?#]*)?(\?[^#]*)?(#.*)?$/);
3341
+ var urlPath = (m && m[2]) || '';
3342
+ if (urlPath && !params.Key) params.Key = urlPath.substr(1);
3343
+ }
3344
+ submitRequest.call(
3345
+ this,
3346
+ {
3347
+ method: params.Method,
3348
+ Bucket: params.Bucket,
3349
+ Region: params.Region,
3350
+ Key: params.Key,
3351
+ action: params.Action,
3352
+ headers: params.Headers,
3353
+ qs: Query,
3354
+ body: params.Body,
3355
+ url: params.Url,
3356
+ rawBody: params.RawBody,
3357
+ },
3358
+ function (err, data) {
3359
+ if (err) return callback(err);
3360
+ if (data && data.body) {
3361
+ data.Body = data.body;
3362
+ delete data.body;
3363
+ }
3364
+ callback(err, data);
3365
+ }
3366
+ );
3367
+ }
3368
+
3369
+ /**
3370
+ * 获取签名
3371
+ * @param {Object} params 参数对象,必须
3372
+ * @param {String} params.Method 请求方法,必须
3373
+ * @param {String} params.Key object名称,必须
3374
+ * @param {String} params.Expires 名超时时间,单位秒,可选
3375
+ * @return {String} data 返回签名字符串
3376
+ */
3377
+ function getAuth(params) {
3378
+ var self = this;
3379
+ return util.getAuth({
3380
+ SecretId: params.SecretId || this.options.SecretId || '',
3381
+ SecretKey: params.SecretKey || this.options.SecretKey || '',
3382
+ Bucket: params.Bucket,
3383
+ Region: params.Region,
3384
+ Method: params.Method,
3385
+ Key: params.Key,
3386
+ Query: params.Query,
3387
+ Headers: params.Headers,
3388
+ Expires: params.Expires,
3389
+ UseRawKey: self.options.UseRawKey,
3390
+ SystemClockOffset: self.options.SystemClockOffset,
3391
+ });
3392
+ }
3393
+
3394
+ function getV4Auth(params) {
3395
+ return util.getV4Auth({
3396
+ SecretId: params.SecretId || this.options.SecretId || '',
3397
+ SecretKey: params.SecretKey || this.options.SecretKey || '',
3398
+ Bucket: params.Bucket,
3399
+ Key: params.Key,
3400
+ Expires: params.Expires,
3401
+ });
3402
+ }
3403
+
3404
+ /**
3405
+ * 获取文件下载链接
3406
+ * @param {Object} params 参数对象,必须
3407
+ * @param {String} params.Bucket Bucket名称,必须
3408
+ * @param {String} params.Region 地域名称,必须
3409
+ * @param {String} params.Key object名称,必须
3410
+ * @param {String} params.Method 请求的方法,可选
3411
+ * @param {String} params.Expires 签名超时时间,单位秒,可选
3412
+ * @param {Function} callback 回调函数,必须
3413
+ * @return {Object} err 请求失败的错误,如果请求成功,则为空。https://cloud.tencent.com/document/product/436/7730
3414
+ * @return {Object} data 返回的数据
3415
+ */
3416
+ function getObjectUrl(params, callback) {
3417
+ var self = this;
3418
+ var useAccelerate = params.UseAccelerate === undefined ? self.options.UseAccelerate : params.UseAccelerate;
3419
+ var url = getUrl({
3420
+ ForcePathStyle: self.options.ForcePathStyle,
3421
+ protocol: params.Protocol || self.options.Protocol,
3422
+ domain: params.Domain || self.options.Domain,
3423
+ bucket: params.Bucket,
3424
+ region: useAccelerate ? 'accelerate' : params.Region,
3425
+ object: params.Key,
3426
+ });
3427
+
3428
+ var queryParamsStr = '';
3429
+ if (params.Query) {
3430
+ queryParamsStr += util.obj2str(params.Query);
3431
+ }
3432
+ if (params.QueryString) {
3433
+ queryParamsStr += (queryParamsStr ? '&' : '') + params.QueryString;
3434
+ }
3435
+
3436
+ var syncUrl = url;
3437
+ if (params.Sign !== undefined && !params.Sign) {
3438
+ queryParamsStr && (syncUrl += '?' + queryParamsStr);
3439
+ callback(null, { Url: syncUrl });
3440
+ return syncUrl;
3441
+ }
3442
+
3443
+ // 签名加上 Host,避免跨桶访问
3444
+ var SignHost = getSignHost.call(this, {
3445
+ Bucket: params.Bucket,
3446
+ Region: params.Region,
3447
+ UseAccelerate: params.UseAccelerate,
3448
+ Url: url,
3449
+ });
3450
+ var AuthData = getAuthorizationAsync.call(
3451
+ this,
3452
+ {
3453
+ Action: (params.Method || '').toUpperCase() === 'PUT' ? 'name/cos:PutObject' : 'name/cos:GetObject',
3454
+ Bucket: params.Bucket || '',
3455
+ Region: params.Region || '',
3456
+ Method: params.Method || 'get',
3457
+ Key: params.Key,
3458
+ Expires: params.Expires,
3459
+ Headers: params.Headers,
3460
+ Query: params.Query,
3461
+ SignHost: SignHost,
3462
+ ForceSignHost: params.ForceSignHost === false ? false : self.options.ForceSignHost, // getObjectUrl支持传参ForceSignHost
3463
+ },
3464
+ function (err, AuthData) {
3465
+ if (!callback) return;
3466
+ if (err) {
3467
+ callback(err);
3468
+ return;
3469
+ }
3470
+
3471
+ // 兼容万象url qUrlParamList需要再encode一次
3472
+ var replaceUrlParamList = function (url) {
3473
+ var urlParams = url.match(/q-url-param-list.*?(?=&)/g)[0];
3474
+ var encodedParams =
3475
+ 'q-url-param-list=' + encodeURIComponent(urlParams.replace(/q-url-param-list=/, '')).toLowerCase();
3476
+ var reg = new RegExp(urlParams, 'g');
3477
+ var replacedUrl = url.replace(reg, encodedParams);
3478
+ return replacedUrl;
3479
+ };
3480
+
3481
+ var signUrl = url;
3482
+ signUrl +=
3483
+ '?' +
3484
+ (AuthData.Authorization.indexOf('q-signature') > -1
3485
+ ? replaceUrlParamList(AuthData.Authorization)
3486
+ : 'sign=' + encodeURIComponent(AuthData.Authorization));
3487
+ AuthData.SecurityToken && (signUrl += '&x-cos-security-token=' + AuthData.SecurityToken);
3488
+ AuthData.ClientIP && (signUrl += '&clientIP=' + AuthData.ClientIP);
3489
+ AuthData.ClientUA && (signUrl += '&clientUA=' + AuthData.ClientUA);
3490
+ AuthData.Token && (signUrl += '&token=' + AuthData.Token);
3491
+ queryParamsStr && (signUrl += '&' + queryParamsStr);
3492
+ setTimeout(function () {
3493
+ callback(null, { Url: signUrl });
3494
+ });
3495
+ }
3496
+ );
3497
+
3498
+ if (AuthData) {
3499
+ syncUrl +=
3500
+ '?' + AuthData.Authorization + (AuthData.SecurityToken ? '&x-cos-security-token=' + AuthData.SecurityToken : '');
3501
+ queryParamsStr && (syncUrl += '&' + queryParamsStr);
3502
+ } else {
3503
+ queryParamsStr && (syncUrl += '?' + queryParamsStr);
3504
+ }
3505
+ return syncUrl;
3506
+ }
3507
+
3508
+ /**
3509
+ * 私有方法
3510
+ */
3511
+ function decodeAcl(AccessControlPolicy) {
3512
+ var result = {
3513
+ GrantFullControl: [],
3514
+ GrantWrite: [],
3515
+ GrantRead: [],
3516
+ GrantReadAcp: [],
3517
+ GrantWriteAcp: [],
3518
+ ACL: '',
3519
+ };
3520
+ var GrantMap = {
3521
+ FULL_CONTROL: 'GrantFullControl',
3522
+ WRITE: 'GrantWrite',
3523
+ READ: 'GrantRead',
3524
+ READ_ACP: 'GrantReadAcp',
3525
+ WRITE_ACP: 'GrantWriteAcp',
3526
+ };
3527
+ var AccessControlList = (AccessControlPolicy && AccessControlPolicy.AccessControlList) || {};
3528
+ var Grant = AccessControlList.Grant;
3529
+ if (Grant) {
3530
+ Grant = util.isArray(Grant) ? Grant : [Grant];
3531
+ }
3532
+ var PublicAcl = { READ: 0, WRITE: 0, FULL_CONTROL: 0 };
3533
+ Grant &&
3534
+ Grant.length &&
3535
+ util.each(Grant, function (item) {
3536
+ if (
3537
+ item.Grantee.ID === 'qcs::cam::anyone:anyone' ||
3538
+ item.Grantee.URI === 'http://cam.qcloud.com/groups/global/AllUsers'
3539
+ ) {
3540
+ PublicAcl[item.Permission] = 1;
3541
+ } else if (item.Grantee.ID !== AccessControlPolicy.Owner.ID) {
3542
+ result[GrantMap[item.Permission]].push('id="' + item.Grantee.ID + '"');
3543
+ }
3544
+ });
3545
+ if (PublicAcl.FULL_CONTROL || (PublicAcl.WRITE && PublicAcl.READ)) {
3546
+ result.ACL = 'public-read-write';
3547
+ } else if (PublicAcl.READ) {
3548
+ result.ACL = 'public-read';
3549
+ } else {
3550
+ result.ACL = 'private';
3551
+ }
3552
+ util.each(GrantMap, function (item) {
3553
+ result[item] = uniqGrant(result[item].join(','));
3554
+ });
3555
+ return result;
3556
+ }
3557
+
3558
+ // Grant 去重
3559
+ function uniqGrant(str) {
3560
+ var arr = str.split(',');
3561
+ var exist = {};
3562
+ var i, item;
3563
+ for (i = 0; i < arr.length; ) {
3564
+ item = arr[i].trim();
3565
+ if (exist[item]) {
3566
+ arr.splice(i, 1);
3567
+ } else {
3568
+ exist[item] = true;
3569
+ arr[i] = item;
3570
+ i++;
3571
+ }
3572
+ }
3573
+ return arr.join(',');
3574
+ }
3575
+
3576
+ // 生成操作 url
3577
+ function getUrl(params) {
3578
+ var longBucket = params.bucket;
3579
+ var shortBucket = longBucket.substr(0, longBucket.lastIndexOf('-'));
3580
+ var appId = longBucket.substr(longBucket.lastIndexOf('-') + 1);
3581
+ var domain = params.domain;
3582
+ var region = params.region;
3583
+ var object = params.object;
3584
+ // 兼容不带冒号的http、https
3585
+ if (['http', 'https'].includes(params.protocol)) {
3586
+ params.protocol = params.protocol + ':';
3587
+ }
3588
+ var protocol = params.protocol || (util.isBrowser && location.protocol === 'http:' ? 'http:' : 'https:');
3589
+ if (!domain) {
3590
+ if (['cn-south', 'cn-south-2', 'cn-north', 'cn-east', 'cn-southwest', 'sg'].indexOf(region) > -1) {
3591
+ domain = '{Region}.myqcloud.com';
3592
+ } else {
3593
+ domain = 'cos.{Region}.myqcloud.com';
3594
+ }
3595
+ if (!params.ForcePathStyle) {
3596
+ domain = '{Bucket}.' + domain;
3597
+ }
3598
+ }
3599
+ domain = domain
3600
+ .replace(/\{\{AppId\}\}/gi, appId)
3601
+ .replace(/\{\{Bucket\}\}/gi, shortBucket)
3602
+ .replace(/\{\{Region\}\}/gi, region)
3603
+ .replace(/\{\{.*?\}\}/gi, '');
3604
+ domain = domain
3605
+ .replace(/\{AppId\}/gi, appId)
3606
+ .replace(/\{BucketName\}/gi, shortBucket)
3607
+ .replace(/\{Bucket\}/gi, longBucket)
3608
+ .replace(/\{Region\}/gi, region)
3609
+ .replace(/\{.*?\}/gi, '');
3610
+ if (!/^[a-zA-Z]+:\/\//.test(domain)) {
3611
+ domain = protocol + '//' + domain;
3612
+ }
3613
+
3614
+ // 去掉域名最后的斜杆
3615
+ if (domain.slice(-1) === '/') {
3616
+ domain = domain.slice(0, -1);
3617
+ }
3618
+ var url = domain;
3619
+
3620
+ if (params.ForcePathStyle) {
3621
+ url += '/' + longBucket;
3622
+ }
3623
+ url += '/';
3624
+ if (object) {
3625
+ url += util.camSafeUrlEncode(object).replace(/%2F/g, '/');
3626
+ }
3627
+
3628
+ if (params.isLocation) {
3629
+ url = url.replace(/^https?:\/\//, '');
3630
+ }
3631
+ return url;
3632
+ }
3633
+
3634
+ var getSignHost = function (opt) {
3635
+ if (!opt.Bucket || !opt.Region) return '';
3636
+ var useAccelerate = opt.UseAccelerate === undefined ? this.options.UseAccelerate : opt.UseAccelerate;
3637
+ var url =
3638
+ opt.Url ||
3639
+ getUrl({
3640
+ ForcePathStyle: this.options.ForcePathStyle,
3641
+ protocol: this.options.Protocol,
3642
+ domain: this.options.Domain,
3643
+ bucket: opt.Bucket,
3644
+ region: useAccelerate ? 'accelerate' : opt.Region,
3645
+ });
3646
+ var urlHost = url.replace(/^https?:\/\/([^/]+)(\/.*)?$/, '$1');
3647
+ var standardHostReg = new RegExp('^([a-z\\d-]+-\\d+\\.)?(cos|cosv6|ci|pic)\\.([a-z\\d-]+)\\.myqcloud\\.com$');
3648
+ if (standardHostReg.test(urlHost)) return urlHost;
3649
+ return '';
3650
+ };
3651
+
3652
+ // 异步获取签名
3653
+ function getAuthorizationAsync(params, callback) {
3654
+ var headers = util.clone(params.Headers);
3655
+ var headerHost = '';
3656
+ util.each(headers, function (v, k) {
3657
+ (v === '' || ['content-type', 'cache-control'].indexOf(k.toLowerCase()) > -1) && delete headers[k];
3658
+ if (k.toLowerCase() === 'host') headerHost = v;
3659
+ });
3660
+
3661
+ // ForceSignHost明确传入false才不加入host签名
3662
+ var forceSignHost = params.ForceSignHost === false ? false : true;
3663
+
3664
+ // Host 加入签名计算
3665
+ if (!headerHost && params.SignHost && forceSignHost) headers.Host = params.SignHost;
3666
+
3667
+ // 获取凭证的回调,避免用户 callback 多次
3668
+ var cbDone = false;
3669
+ var cb = function (err, AuthData) {
3670
+ if (cbDone) return;
3671
+ cbDone = true;
3672
+ if (AuthData && AuthData.XCosSecurityToken && !AuthData.SecurityToken) {
3673
+ AuthData = util.clone(AuthData);
3674
+ AuthData.SecurityToken = AuthData.XCosSecurityToken;
3675
+ delete AuthData.XCosSecurityToken;
3676
+ }
3677
+ callback && callback(err, AuthData);
3678
+ };
3679
+
3680
+ var self = this;
3681
+ var Bucket = params.Bucket || '';
3682
+ var Region = params.Region || '';
3683
+
3684
+ // PathName
3685
+ var KeyName = params.Key || '';
3686
+ if (self.options.ForcePathStyle && Bucket) {
3687
+ KeyName = Bucket + '/' + KeyName;
3688
+ }
3689
+ var Pathname = '/' + KeyName;
3690
+
3691
+ // Action、ResourceKey
3692
+ var StsData = {};
3693
+ var Scope = params.Scope;
3694
+ if (!Scope) {
3695
+ var Action = params.Action || '';
3696
+ var ResourceKey = params.ResourceKey || params.Key || '';
3697
+ Scope = params.Scope || [
3698
+ {
3699
+ action: Action,
3700
+ bucket: Bucket,
3701
+ region: Region,
3702
+ prefix: ResourceKey,
3703
+ },
3704
+ ];
3705
+ }
3706
+ var ScopeKey = util.md5(JSON.stringify(Scope));
3707
+
3708
+ // STS
3709
+ self._StsCache = self._StsCache || [];
3710
+ (function () {
3711
+ var i, AuthData;
3712
+ for (i = self._StsCache.length - 1; i >= 0; i--) {
3713
+ AuthData = self._StsCache[i];
3714
+ var compareTime = Math.round(util.getSkewTime(self.options.SystemClockOffset) / 1000) + 30;
3715
+ if ((AuthData.StartTime && compareTime < AuthData.StartTime) || compareTime >= AuthData.ExpiredTime) {
3716
+ self._StsCache.splice(i, 1);
3717
+ continue;
3718
+ }
3719
+ if (!AuthData.ScopeLimit || (AuthData.ScopeLimit && AuthData.ScopeKey === ScopeKey)) {
3720
+ StsData = AuthData;
3721
+ break;
3722
+ }
3723
+ }
3724
+ })();
3725
+
3726
+ var calcAuthByTmpKey = function () {
3727
+ var KeyTime = '';
3728
+ if (StsData.StartTime && params.Expires)
3729
+ KeyTime = StsData.StartTime + ';' + (StsData.StartTime + params.Expires * 1);
3730
+ else if (StsData.StartTime && StsData.ExpiredTime) KeyTime = StsData.StartTime + ';' + StsData.ExpiredTime;
3731
+ var Authorization = util.getAuth({
3732
+ SecretId: StsData.TmpSecretId,
3733
+ SecretKey: StsData.TmpSecretKey,
3734
+ Method: params.Method,
3735
+ Pathname: Pathname,
3736
+ Query: params.Query,
3737
+ Headers: headers,
3738
+ Expires: params.Expires,
3739
+ UseRawKey: self.options.UseRawKey,
3740
+ SystemClockOffset: self.options.SystemClockOffset,
3741
+ KeyTime: KeyTime,
3742
+ ForceSignHost: forceSignHost,
3743
+ });
3744
+ var AuthData = {
3745
+ Authorization: Authorization,
3746
+ SecurityToken: StsData.SecurityToken || StsData.XCosSecurityToken || '',
3747
+ Token: StsData.Token || '',
3748
+ ClientIP: StsData.ClientIP || '',
3749
+ ClientUA: StsData.ClientUA || '',
3750
+ };
3751
+ cb(null, AuthData);
3752
+ };
3753
+ var checkAuthError = function (AuthData) {
3754
+ if (AuthData.Authorization) {
3755
+ // 检查签名格式
3756
+ var formatAllow = false;
3757
+ var auth = AuthData.Authorization;
3758
+ if (auth) {
3759
+ if (auth.indexOf(' ') > -1) {
3760
+ formatAllow = false;
3761
+ } else if (
3762
+ auth.indexOf('q-sign-algorithm=') > -1 &&
3763
+ auth.indexOf('q-ak=') > -1 &&
3764
+ auth.indexOf('q-sign-time=') > -1 &&
3765
+ auth.indexOf('q-key-time=') > -1 &&
3766
+ auth.indexOf('q-url-param-list=') > -1
3767
+ ) {
3768
+ formatAllow = true;
3769
+ } else {
3770
+ try {
3771
+ auth = Buffer.from(auth, 'base64').toString();
3772
+ if (
3773
+ auth.indexOf('a=') > -1 &&
3774
+ auth.indexOf('k=') > -1 &&
3775
+ auth.indexOf('t=') > -1 &&
3776
+ auth.indexOf('r=') > -1 &&
3777
+ auth.indexOf('b=') > -1
3778
+ ) {
3779
+ formatAllow = true;
3780
+ }
3781
+ } catch (e) {}
3782
+ }
3783
+ }
3784
+ if (!formatAllow) return util.error(new Error('getAuthorization callback params format error'));
3785
+ } else {
3786
+ if (!AuthData.TmpSecretId) return util.error(new Error('getAuthorization callback params missing "TmpSecretId"'));
3787
+ if (!AuthData.TmpSecretKey)
3788
+ return util.error(new Error('getAuthorization callback params missing "TmpSecretKey"'));
3789
+ if (!AuthData.SecurityToken && !AuthData.XCosSecurityToken)
3790
+ return util.error(new Error('getAuthorization callback params missing "SecurityToken"'));
3791
+ if (!AuthData.ExpiredTime) return util.error(new Error('getAuthorization callback params missing "ExpiredTime"'));
3792
+ if (AuthData.ExpiredTime && AuthData.ExpiredTime.toString().length !== 10)
3793
+ return util.error(new Error('getAuthorization callback params "ExpiredTime" should be 10 digits'));
3794
+ if (AuthData.StartTime && AuthData.StartTime.toString().length !== 10)
3795
+ return util.error(new Error('getAuthorization callback params "StartTime" should be 10 StartTime'));
3796
+ }
3797
+ return false;
3798
+ };
3799
+
3800
+ // 先判断是否有临时密钥
3801
+ if (StsData.ExpiredTime && StsData.ExpiredTime - util.getSkewTime(self.options.SystemClockOffset) / 1000 > 60) {
3802
+ // 如果缓存的临时密钥有效,并还有超过60秒有效期就直接使用
3803
+ calcAuthByTmpKey();
3804
+ } else if (self.options.getAuthorization) {
3805
+ // 外部计算签名或获取临时密钥
3806
+ self.options.getAuthorization.call(
3807
+ self,
3808
+ {
3809
+ Bucket: Bucket,
3810
+ Region: Region,
3811
+ Method: params.Method,
3812
+ Key: KeyName,
3813
+ Pathname: Pathname,
3814
+ Query: params.Query,
3815
+ Headers: headers,
3816
+ Scope: Scope,
3817
+ SystemClockOffset: self.options.SystemClockOffset,
3818
+ ForceSignHost: forceSignHost,
3819
+ },
3820
+ function (AuthData) {
3821
+ if (typeof AuthData === 'string') AuthData = { Authorization: AuthData };
3822
+ var AuthError = checkAuthError(AuthData);
3823
+ if (AuthError) return cb(AuthError);
3824
+ if (AuthData.Authorization) {
3825
+ cb(null, AuthData);
3826
+ } else {
3827
+ StsData = AuthData || {};
3828
+ StsData.Scope = Scope;
3829
+ StsData.ScopeKey = ScopeKey;
3830
+ self._StsCache.push(StsData);
3831
+ calcAuthByTmpKey();
3832
+ }
3833
+ }
3834
+ );
3835
+ } else if (self.options.getSTS) {
3836
+ // 外部获取临时密钥
3837
+ self.options.getSTS.call(
3838
+ self,
3839
+ {
3840
+ Bucket: Bucket,
3841
+ Region: Region,
3842
+ },
3843
+ function (data) {
3844
+ StsData = data || {};
3845
+ StsData.Scope = Scope;
3846
+ StsData.ScopeKey = ScopeKey;
3847
+ if (!StsData.TmpSecretId) StsData.TmpSecretId = StsData.SecretId;
3848
+ if (!StsData.TmpSecretKey) StsData.TmpSecretKey = StsData.SecretKey;
3849
+ var AuthError = checkAuthError(StsData);
3850
+ if (AuthError) return cb(AuthError);
3851
+ self._StsCache.push(StsData);
3852
+ calcAuthByTmpKey();
3853
+ }
3854
+ );
3855
+ } else {
3856
+ // 内部计算获取签名
3857
+ return (function () {
3858
+ var Authorization = util.getAuth({
3859
+ SecretId: params.SecretId || self.options.SecretId,
3860
+ SecretKey: params.SecretKey || self.options.SecretKey,
3861
+ Method: params.Method,
3862
+ Pathname: Pathname,
3863
+ Query: params.Query,
3864
+ Headers: headers,
3865
+ Expires: params.Expires,
3866
+ UseRawKey: self.options.UseRawKey,
3867
+ SystemClockOffset: self.options.SystemClockOffset,
3868
+ ForceSignHost: forceSignHost,
3869
+ });
3870
+ var AuthData = {
3871
+ Authorization: Authorization,
3872
+ SecurityToken: self.options.SecurityToken || self.options.XCosSecurityToken,
3873
+ };
3874
+ cb(null, AuthData);
3875
+ return AuthData;
3876
+ })();
3877
+ }
3878
+ return '';
3879
+ }
3880
+
3881
+ // 调整时间偏差
3882
+ function allowRetry(err) {
3883
+ var allowRetry = false;
3884
+ var isTimeError = false;
3885
+ var serverDate = (err.headers && (err.headers.date || err.headers.Date)) || (err.error && err.error.ServerTime);
3886
+ try {
3887
+ var errorCode = err.error.Code;
3888
+ var errorMessage = err.error.Message;
3889
+ if (
3890
+ errorCode === 'RequestTimeTooSkewed' ||
3891
+ (errorCode === 'AccessDenied' && errorMessage === 'Request has expired')
3892
+ ) {
3893
+ isTimeError = true;
3894
+ }
3895
+ } catch (e) {}
3896
+ if (err) {
3897
+ if (isTimeError && serverDate) {
3898
+ var serverTime = Date.parse(serverDate);
3899
+ if (
3900
+ this.options.CorrectClockSkew &&
3901
+ Math.abs(util.getSkewTime(this.options.SystemClockOffset) - serverTime) >= 30000
3902
+ ) {
3903
+ console.error('error: Local time is too skewed.');
3904
+ this.options.SystemClockOffset = serverTime - Date.now();
3905
+ allowRetry = true;
3906
+ }
3907
+ } else if (Math.floor(err.statusCode / 100) === 5) {
3908
+ allowRetry = true;
3909
+ } else if (err.code === 'ECONNRESET') {
3910
+ allowRetry = true;
3911
+ }
3912
+ }
3913
+ return allowRetry;
3914
+ }
3915
+
3916
+ // 获取签名并发起请求
3917
+ function submitRequest(params, callback) {
3918
+ var self = this;
3919
+
3920
+ // 处理 headers
3921
+ !params.headers && (params.headers = {});
3922
+ params.headers['User-Agent'] = self.options.UserAgent || 'cos-nodejs-sdk-v5-' + pkg.version;
3923
+
3924
+ // 处理 query
3925
+ !params.qs && (params.qs = {});
3926
+ params.VersionId && (params.qs.versionId = params.VersionId);
3927
+ params.qs = util.clearKey(params.qs);
3928
+
3929
+ // 清理 undefined 和 null 字段
3930
+ params.headers && (params.headers = util.clearKey(params.headers));
3931
+ params.qs && (params.qs = util.clearKey(params.qs));
3932
+
3933
+ var Query = util.clone(params.qs);
3934
+ params.action && (Query[params.action] = '');
3935
+
3936
+ var SignHost =
3937
+ params.SignHost || getSignHost.call(this, { Bucket: params.Bucket, Region: params.Region, Url: params.url });
3938
+ var next = function (tryTimes) {
3939
+ var oldClockOffset = self.options.SystemClockOffset;
3940
+ getAuthorizationAsync.call(
3941
+ self,
3942
+ {
3943
+ Bucket: params.Bucket || '',
3944
+ Region: params.Region || '',
3945
+ Method: params.method,
3946
+ Key: params.Key,
3947
+ Query: Query,
3948
+ Headers: params.headers,
3949
+ SignHost: SignHost,
3950
+ Action: params.Action,
3951
+ ResourceKey: params.ResourceKey,
3952
+ Scope: params.Scope,
3953
+ ForceSignHost: self.options.ForceSignHost,
3954
+ },
3955
+ function (err, AuthData) {
3956
+ if (err) return callback(err);
3957
+ params.AuthData = AuthData;
3958
+ _submitRequest.call(self, params, function (err, data) {
3959
+ if (
3960
+ err &&
3961
+ !(params.body && params.body.pipe) &&
3962
+ !params.outputStream &&
3963
+ tryTimes < 2 &&
3964
+ (oldClockOffset !== self.options.SystemClockOffset || allowRetry.call(self, err))
3965
+ ) {
3966
+ if (params.headers) {
3967
+ delete params.headers.Authorization;
3968
+ delete params.headers['token'];
3969
+ delete params.headers['clientIP'];
3970
+ delete params.headers['clientUA'];
3971
+ params.headers['x-cos-security-token'] && delete params.headers['x-cos-security-token'];
3972
+ params.headers['x-ci-security-token'] && delete params.headers['x-ci-security-token'];
3973
+ }
3974
+ next(tryTimes + 1);
3975
+ } else {
3976
+ callback(err, data);
3977
+ }
3978
+ });
3979
+ }
3980
+ );
3981
+ };
3982
+ next(1);
3983
+ }
3984
+
3985
+ // 发起请求
3986
+ function _submitRequest(params, callback) {
3987
+ var self = this;
3988
+ var TaskId = params.TaskId;
3989
+ if (TaskId && !self._isRunningTask(TaskId)) return;
3990
+
3991
+ var bucket = params.Bucket;
3992
+ var region = params.Region;
3993
+ var object = params.Key;
3994
+ var method = params.method || 'GET';
3995
+ var url = params.url || params.Url;
3996
+ var body = params.body;
3997
+ var rawBody = params.rawBody;
3998
+
3999
+ // 处理 readStream and body
4000
+ var readStream;
4001
+ if (body && typeof body.pipe === 'function') {
4002
+ readStream = body;
4003
+ body = null;
4004
+ }
4005
+
4006
+ // url
4007
+
4008
+ if (this.options.UseAccelerate) {
4009
+ region = 'accelerate';
4010
+ }
4011
+ url =
4012
+ url ||
4013
+ getUrl({
4014
+ ForcePathStyle: self.options.ForcePathStyle,
4015
+ protocol: self.options.Protocol,
4016
+ domain: self.options.Domain,
4017
+ bucket: bucket,
4018
+ region: region,
4019
+ object: object,
4020
+ });
4021
+ if (params.action) {
4022
+ url = url + '?' + params.action;
4023
+ }
4024
+ if (params.qsStr) {
4025
+ if (url.indexOf('?') > -1) {
4026
+ url = url + '&' + params.qsStr;
4027
+ } else {
4028
+ url = url + '?' + params.qsStr;
4029
+ }
4030
+ }
4031
+
4032
+ var opt = {
4033
+ method: method,
4034
+ url: url,
4035
+ headers: params.headers,
4036
+ qs: params.qs,
4037
+ body: body,
4038
+ };
4039
+
4040
+ // 兼容ci接口
4041
+ var token = 'x-cos-security-token';
4042
+ if (util.isCIHost(url)) {
4043
+ token = 'x-ci-security-token';
4044
+ }
4045
+
4046
+ // 获取签名
4047
+ opt.headers.Authorization = params.AuthData.Authorization;
4048
+ params.AuthData.Token && (opt.headers['token'] = params.AuthData.Token);
4049
+ params.AuthData.ClientIP && (opt.headers['clientIP'] = params.AuthData.ClientIP);
4050
+ params.AuthData.ClientUA && (opt.headers['clientUA'] = params.AuthData.ClientUA);
4051
+ params.AuthData.SecurityToken && (opt.headers[token] = params.AuthData.SecurityToken);
4052
+
4053
+ // 清理 undefined 和 null 字段
4054
+ opt.headers && (opt.headers = util.clearKey(opt.headers));
4055
+ opt = util.clearKey(opt);
4056
+
4057
+ var Ip = this.options.Ip;
4058
+ if (Ip) {
4059
+ opt.url = opt.url.replace(/^(https?:\/\/)([^\/]+)/, function (str, pre, Host) {
4060
+ opt.headers.Host = Host;
4061
+ return pre + Ip;
4062
+ });
4063
+ }
4064
+ if (this.options.StrictSsl !== true) {
4065
+ opt.strictSSL = this.options.StrictSsl;
4066
+ }
4067
+ if (this.options.Proxy) {
4068
+ opt.proxy = this.options.Proxy;
4069
+ }
4070
+ if (typeof this.options.Tunnel === 'boolean') {
4071
+ opt.tunnel = this.options.Tunnel;
4072
+ }
4073
+ if (this.options.Timeout) {
4074
+ opt.timeout = this.options.Timeout;
4075
+ }
4076
+ if (this.options.KeepAlive) {
4077
+ opt.forever = true;
4078
+ }
4079
+ if (!this.options.FollowRedirect) {
4080
+ opt.followRedirect = false;
4081
+ }
4082
+
4083
+ // 修复 Content-Type: false 的 Bug,原因 request 模块会获取 request('mime-types).lookup(readStream.path) 作为 Content-Type
4084
+ // 问题代码位置:https://github.com/request/request/blob/v2.88.1/request.js#L500
4085
+ if (readStream) {
4086
+ var hasContentType = false;
4087
+ util.each(opt.headers, function (val, key) {
4088
+ if (key.toLowerCase() === 'content-type') hasContentType = true;
4089
+ });
4090
+ if (
4091
+ !hasContentType && // 1. not set Content-Type
4092
+ readStream.readable &&
4093
+ readStream.path &&
4094
+ readStream.mode && // 2. isFileReadStream
4095
+ !mime.lookup(readStream.path) // 3. mime return false
4096
+ ) {
4097
+ opt.headers['Content-Type'] = 'application/octet-stream';
4098
+ }
4099
+ }
4100
+
4101
+ // 特殊处理内容到写入流的情况,等待流 finish 后才 callback
4102
+ if (params.outputStream) callback = util.callbackAfterStreamFinish(params.outputStream, callback);
4103
+
4104
+ self.emit('before-send', opt);
4105
+ var sender = REQUEST(opt);
4106
+ var retResponse;
4107
+ var hasReturned;
4108
+ var cb = function (err, data) {
4109
+ TaskId && self.off('inner-kill-task', killTask);
4110
+ if (hasReturned) return;
4111
+ hasReturned = true;
4112
+ var attrs = {};
4113
+ retResponse && retResponse.statusCode && (attrs.statusCode = retResponse.statusCode);
4114
+ retResponse && retResponse.headers && (attrs.headers = retResponse.headers);
4115
+ if (err) {
4116
+ err = util.extend(err || {}, attrs);
4117
+ callback(err, null);
4118
+ } else {
4119
+ data = util.extend(data || {}, attrs);
4120
+ callback(null, data);
4121
+ }
4122
+ if (sender) {
4123
+ sender.removeAllListeners && sender.removeAllListeners();
4124
+ sender.on('error', function () {});
4125
+ sender = null;
4126
+ }
4127
+ };
4128
+ // 在 request 分配的 socket 上挂载 _lastBytesWritten 属性,记录该 socket 已经发送的字节数
4129
+ var markLastBytesWritten = function () {
4130
+ try {
4131
+ Object.defineProperty(sender.req.connection, '_lastBytesWritten', {
4132
+ enumerable: true,
4133
+ configurable: true,
4134
+ writable: true,
4135
+ value: sender.req.connection.bytesWritten,
4136
+ });
4137
+ } catch (e) {}
4138
+ };
4139
+
4140
+ sender.on('error', function (err) {
4141
+ markLastBytesWritten();
4142
+ cb(util.error(err));
4143
+ });
4144
+ sender.on('response', function (response) {
4145
+ retResponse = response;
4146
+ var responseContentLength = response.headers['content-length'] || 0;
4147
+ var chunkList = [];
4148
+ var statusCode = response.statusCode;
4149
+ var statusSuccess = Math.floor(statusCode / 100) === 2; // 200 202 204 206
4150
+ if (statusSuccess && params.outputStream) {
4151
+ sender.on('end', function () {
4152
+ cb(null, {});
4153
+ });
4154
+ } else if (responseContentLength >= process.binding('buffer').kMaxLength && opt.method !== 'HEAD') {
4155
+ cb(
4156
+ util.error(
4157
+ new Error(
4158
+ 'file size large than ' +
4159
+ process.binding('buffer').kMaxLength +
4160
+ ', please use "Output" Stream to getObject.'
4161
+ )
4162
+ )
4163
+ );
4164
+ } else {
4165
+ var dataHandler = function (chunk) {
4166
+ chunkList.push(chunk);
4167
+ };
4168
+ var endHandler = function () {
4169
+ try {
4170
+ var bodyBuf = Buffer.concat(chunkList);
4171
+ } catch (e) {
4172
+ cb(util.error(e));
4173
+ return;
4174
+ }
4175
+ var body = bodyBuf.toString();
4176
+
4177
+ // 不对 body 进行转换,body 直接挂载返回
4178
+ if (rawBody && statusSuccess) return cb(null, { body: bodyBuf });
4179
+
4180
+ // 解析 xml body
4181
+ var json = {};
4182
+ try {
4183
+ json = (body && body.indexOf('<') > -1 && body.indexOf('>') > -1 && util.xml2json(body)) || {};
4184
+ } catch (e) {}
4185
+
4186
+ // 处理返回值
4187
+ var xmlError = json && json.Error;
4188
+ if (statusSuccess) {
4189
+ // 正确返回,状态码 2xx 时,body 不会有 Error
4190
+ cb(null, json);
4191
+ } else if (xmlError) {
4192
+ // 正常返回了 xml body,且有 Error 节点
4193
+ cb(util.error(new Error(xmlError.Message), { code: xmlError.Code, error: xmlError }));
4194
+ } else if (statusCode) {
4195
+ // 有错误的状态码
4196
+ cb(util.error(new Error(response.statusMessage), { code: '' + statusCode }));
4197
+ } else {
4198
+ // 无状态码,或者获取不到状态码
4199
+ cb(util.error(new Error('statusCode error')));
4200
+ }
4201
+ chunkList = null;
4202
+ };
4203
+ sender.on('data', dataHandler);
4204
+ sender.on('end', endHandler);
4205
+ }
4206
+ });
4207
+
4208
+ // kill task
4209
+ var killTask = function (data) {
4210
+ if (data.TaskId === TaskId) {
4211
+ readStream && readStream.isSdkCreated && readStream.close && readStream.close(); // 如果是 SDK 里从 FilePath 创建的读流,要主动取消
4212
+ sender && sender.abort && sender.abort();
4213
+ self.off('inner-kill-task', killTask);
4214
+ }
4215
+ };
4216
+ TaskId && self.on('inner-kill-task', killTask);
4217
+
4218
+ // 请求结束时,在 request 分配的 socket 上挂载 _lastBytesWritten 属性,记录该 socket 已经发送的字节数
4219
+ sender.once('end', function () {
4220
+ markLastBytesWritten();
4221
+ });
4222
+
4223
+ // upload progress
4224
+ if (params.onProgress && typeof params.onProgress === 'function') {
4225
+ var contentLength = opt.headers['Content-Length'];
4226
+ var time0 = Date.now();
4227
+ var size0 = 0;
4228
+ sender.on('drain', function () {
4229
+ var time1 = Date.now();
4230
+ var loaded = 0;
4231
+ try {
4232
+ // 已经上传的字节数 = socket当前累计发送的字节数 - 头部长度 - socket以前发送的字节数
4233
+ loaded =
4234
+ sender.req.connection.bytesWritten -
4235
+ sender.req._header.length -
4236
+ (sender.req.connection._lastBytesWritten || 0);
4237
+ } catch (e) {}
4238
+ var total = contentLength;
4239
+ var speed = parseInt(((loaded - size0) / ((time1 - time0) / 1000)) * 100) / 100 || 0;
4240
+ var percent = parseInt((loaded / total) * 100) / 100 || 0;
4241
+ time0 = time1;
4242
+ size0 = loaded;
4243
+ params.onProgress({
4244
+ loaded: loaded,
4245
+ total: total,
4246
+ speed: speed,
4247
+ percent: percent,
4248
+ });
4249
+ });
4250
+ }
4251
+ // download progress
4252
+ if (params.onDownloadProgress && typeof params.onDownloadProgress === 'function') {
4253
+ var time0 = Date.now();
4254
+ var size0 = 0;
4255
+ var loaded = 0;
4256
+ var total = 0;
4257
+ sender.on('response', function (res) {
4258
+ total = res.headers['content-length'];
4259
+ sender.on('data', function (chunk) {
4260
+ loaded += chunk.length;
4261
+ var time1 = Date.now();
4262
+ var speed = parseInt(((loaded - size0) / ((time1 - time0) / 1000)) * 100) / 100 || 0;
4263
+ var percent = parseInt((loaded / total) * 100) / 100 || 0;
4264
+ time0 = time1;
4265
+ size0 = loaded;
4266
+ params.onDownloadProgress({
4267
+ loaded: loaded,
4268
+ total: total,
4269
+ speed: speed,
4270
+ percent: percent,
4271
+ });
4272
+ });
4273
+ });
4274
+ }
4275
+
4276
+ // pipe 输入
4277
+ if (readStream) {
4278
+ readStream.on('error', function (err) {
4279
+ sender && sender.abort && sender.abort();
4280
+ cb(err);
4281
+ });
4282
+ readStream.pipe(sender);
4283
+ }
4284
+ // pipe 输出
4285
+ if (params.outputStream) {
4286
+ params.outputStream.on('error', function (err) {
4287
+ sender && sender.abort && sender.abort();
4288
+ cb(err);
4289
+ });
4290
+ sender.pipe(params.outputStream);
4291
+ }
4292
+
4293
+ return sender;
4294
+ }
4295
+
4296
+ var API_MAP = {
4297
+ // Bucket 相关方法
4298
+ getService: getService, // Bucket
4299
+ putBucket: putBucket,
4300
+ headBucket: headBucket, // Bucket
4301
+ getBucket: getBucket,
4302
+ deleteBucket: deleteBucket,
4303
+ putBucketAcl: putBucketAcl, // BucketACL
4304
+ getBucketAcl: getBucketAcl,
4305
+ putBucketCors: putBucketCors, // BucketCors
4306
+ getBucketCors: getBucketCors,
4307
+ deleteBucketCors: deleteBucketCors,
4308
+ getBucketLocation: getBucketLocation, // BucketLocation
4309
+ getBucketPolicy: getBucketPolicy, // BucketPolicy
4310
+ putBucketPolicy: putBucketPolicy,
4311
+ deleteBucketPolicy: deleteBucketPolicy,
4312
+ putBucketTagging: putBucketTagging, // BucketTagging
4313
+ getBucketTagging: getBucketTagging,
4314
+ deleteBucketTagging: deleteBucketTagging,
4315
+ putBucketLifecycle: putBucketLifecycle, // BucketLifecycle
4316
+ getBucketLifecycle: getBucketLifecycle,
4317
+ deleteBucketLifecycle: deleteBucketLifecycle,
4318
+ putBucketVersioning: putBucketVersioning, // BucketVersioning
4319
+ getBucketVersioning: getBucketVersioning,
4320
+ putBucketReplication: putBucketReplication, // BucketReplication
4321
+ getBucketReplication: getBucketReplication,
4322
+ deleteBucketReplication: deleteBucketReplication,
4323
+ putBucketWebsite: putBucketWebsite, // BucketWebsite
4324
+ getBucketWebsite: getBucketWebsite,
4325
+ deleteBucketWebsite: deleteBucketWebsite,
4326
+ putBucketReferer: putBucketReferer, // BucketReferer
4327
+ getBucketReferer: getBucketReferer,
4328
+ putBucketDomain: putBucketDomain, // BucketDomain
4329
+ getBucketDomain: getBucketDomain,
4330
+ deleteBucketDomain: deleteBucketDomain,
4331
+ putBucketOrigin: putBucketOrigin, // BucketOrigin
4332
+ getBucketOrigin: getBucketOrigin,
4333
+ deleteBucketOrigin: deleteBucketOrigin,
4334
+ putBucketLogging: putBucketLogging, // BucketLogging
4335
+ getBucketLogging: getBucketLogging,
4336
+ putBucketInventory: putBucketInventory, // BucketInventory
4337
+ getBucketInventory: getBucketInventory,
4338
+ listBucketInventory: listBucketInventory,
4339
+ deleteBucketInventory: deleteBucketInventory,
4340
+ putBucketAccelerate: putBucketAccelerate,
4341
+ getBucketAccelerate: getBucketAccelerate,
4342
+ putBucketEncryption: putBucketEncryption,
4343
+ getBucketEncryption: getBucketEncryption,
4344
+ deleteBucketEncryption: deleteBucketEncryption,
4345
+
4346
+ // Object 相关方法
4347
+ getObject: getObject,
4348
+ getObjectStream: getObjectStream,
4349
+ headObject: headObject,
4350
+ listObjectVersions: listObjectVersions,
4351
+ putObject: putObject,
4352
+ deleteObject: deleteObject,
4353
+ getObjectAcl: getObjectAcl,
4354
+ putObjectAcl: putObjectAcl,
4355
+ optionsObject: optionsObject,
4356
+ putObjectCopy: putObjectCopy,
4357
+ deleteMultipleObject: deleteMultipleObject,
4358
+ restoreObject: restoreObject,
4359
+ putObjectTagging: putObjectTagging,
4360
+ getObjectTagging: getObjectTagging,
4361
+ deleteObjectTagging: deleteObjectTagging,
4362
+ selectObjectContent: selectObjectContent,
4363
+ selectObjectContentStream: selectObjectContentStream,
4364
+ appendObject: appendObject,
4365
+
4366
+ // 分块上传相关方法
4367
+ uploadPartCopy: uploadPartCopy,
4368
+ multipartInit: multipartInit,
4369
+ multipartUpload: multipartUpload,
4370
+ multipartComplete: multipartComplete,
4371
+ multipartList: multipartList,
4372
+ multipartListPart: multipartListPart,
4373
+ multipartAbort: multipartAbort,
4374
+
4375
+ // 工具方法
4376
+ request: request,
4377
+ getObjectUrl: getObjectUrl,
4378
+ getAuth: getAuth,
4379
+ getV4Auth: getV4Auth,
4380
+ };
4381
+
4382
+ function warnOldApi(apiName, fn, proto) {
4383
+ util.each(['Cors', 'Acl'], function (suffix) {
4384
+ if (apiName.slice(-suffix.length) === suffix) {
4385
+ var oldName = apiName.slice(0, -suffix.length) + suffix.toUpperCase();
4386
+ var apiFn = util.apiWrapper(apiName, fn);
4387
+ var warned = false;
4388
+ proto[oldName] = function () {
4389
+ !warned &&
4390
+ console.warn('warning: cos.' + oldName + ' has been deprecated. Please Use cos.' + apiName + ' instead.');
4391
+ warned = true;
4392
+ apiFn.apply(this, arguments);
4393
+ };
4394
+ }
4395
+ });
4396
+ }
4397
+
4398
+ module.exports.init = function (COS, task) {
4399
+ task.transferToTaskMethod(API_MAP, 'putObject');
4400
+ util.each(API_MAP, function (fn, apiName) {
4401
+ COS.prototype[apiName] = util.apiWrapper(apiName, fn);
4402
+ warnOldApi(apiName, fn, COS.prototype);
4403
+ });
4404
+ };