| const assert = require('assert'); | |
| const { isArray } = require('./common/utils/isArray'); | |
| const { checkBucketName: _checkBucketName } = require('../lib/common/utils/checkBucketName'); | |
| const { formatTag } = require('../lib/common/utils/formatTag'); | |
| 
 | |
| const proto = exports; | |
| 
 | |
| function toArray(obj) { | |
|   if (!obj) return []; | |
|   if (isArray(obj)) return obj; | |
|   return [obj]; | |
| } | |
| 
 | |
| /** | |
|  * Bucket opertaions | |
|  */ | |
| 
 | |
| proto.listBuckets = async function listBuckets(query = {}, options = {}) { | |
|   // prefix, marker, max-keys | |
|  | |
|   const { subres = {} } = query; | |
|   const rest = {}; | |
|   for (const key in query) { | |
|     if (key !== 'subres') { | |
|       rest[key] = query[key]; | |
|     } | |
|   } | |
|   const params = this._bucketRequestParams('GET', '', Object.assign(subres, options.subres), options); | |
| 
 | |
|   params.query = rest; | |
| 
 | |
|   const result = await this.request(params); | |
| 
 | |
|   if (result.status === 200) { | |
|     const data = await this.parseXML(result.data); | |
|     let buckets = data.Buckets || null; | |
|     if (buckets) { | |
|       if (buckets.Bucket) { | |
|         buckets = buckets.Bucket; | |
|       } | |
|       if (!isArray(buckets)) { | |
|         buckets = [buckets]; | |
|       } | |
|       buckets = buckets.map(item => ({ | |
|         name: item.Name, | |
|         region: item.Location, | |
|         creationDate: item.CreationDate, | |
|         storageClass: item.StorageClass, | |
|         StorageClass: item.StorageClass, | |
|         tag: formatTag(item) | |
|       })); | |
|     } | |
|     return { | |
|       buckets, | |
|       owner: { | |
|         id: data.Owner.ID, | |
|         displayName: data.Owner.DisplayName | |
|       }, | |
|       isTruncated: data.IsTruncated === 'true', | |
|       nextMarker: data.NextMarker || null, | |
|       res: result.res | |
|     }; | |
|   } | |
| 
 | |
|   throw await this.requestError(result); | |
| }; | |
| 
 | |
| proto.useBucket = function useBucket(name) { | |
|   _checkBucketName(name); | |
|   return this.setBucket(name); | |
| }; | |
| 
 | |
| proto.setBucket = function useBucket(name) { | |
|   _checkBucketName(name); | |
|   this.options.bucket = name; | |
|   return this; | |
| }; | |
| 
 | |
| proto.getBucket = function getBucket() { | |
|   return this.options.bucket; | |
| }; | |
| 
 | |
| proto.getBucketLocation = async function getBucketLocation(name, options) { | |
|   _checkBucketName(name); | |
|   name = name || this.getBucket(); | |
|   const params = this._bucketRequestParams('GET', name, 'location', options); | |
|   params.successStatuses = [200]; | |
|   params.xmlResponse = true; | |
|   const result = await this.request(params); | |
|   return { | |
|     location: result.data, | |
|     res: result.res | |
|   }; | |
| }; | |
| 
 | |
| proto.getBucketInfo = async function getBucketInfo(name, options) { | |
|   _checkBucketName(name); | |
|   name = name || this.getBucket(); | |
|   const params = this._bucketRequestParams('GET', name, 'bucketInfo', options); | |
|   params.successStatuses = [200]; | |
|   params.xmlResponse = true; | |
|   const result = await this.request(params); | |
|   return { | |
|     bucket: result.data.Bucket, | |
|     res: result.res | |
|   }; | |
| }; | |
| 
 | |
| proto.deleteBucket = async function deleteBucket(name, options) { | |
|   _checkBucketName(name); | |
|   const params = this._bucketRequestParams('DELETE', name, '', options); | |
|   const result = await this.request(params); | |
|   if (result.status === 200 || result.status === 204) { | |
|     return { | |
|       res: result.res | |
|     }; | |
|   } | |
|   throw await this.requestError(result); | |
| }; | |
| 
 | |
| // acl | |
|  | |
| proto.putBucketACL = async function putBucketACL(name, acl, options) { | |
|   _checkBucketName(name); | |
|   const params = this._bucketRequestParams('PUT', name, 'acl', options); | |
|   params.headers = { | |
|     'x-oss-acl': acl | |
|   }; | |
|   params.successStatuses = [200]; | |
|   const result = await this.request(params); | |
|   return { | |
|     bucket: (result.headers.location && result.headers.location.substring(1)) || null, | |
|     res: result.res | |
|   }; | |
| }; | |
| 
 | |
| proto.getBucketACL = async function getBucketACL(name, options) { | |
|   _checkBucketName(name); | |
|   const params = this._bucketRequestParams('GET', name, 'acl', options); | |
|   params.successStatuses = [200]; | |
|   params.xmlResponse = true; | |
|   const result = await this.request(params); | |
|   return { | |
|     acl: result.data.AccessControlList.Grant, | |
|     owner: { | |
|       id: result.data.Owner.ID, | |
|       displayName: result.data.Owner.DisplayName | |
|     }, | |
|     res: result.res | |
|   }; | |
| }; | |
| 
 | |
| // logging | |
|  | |
| proto.putBucketLogging = async function putBucketLogging(name, prefix, options) { | |
|   _checkBucketName(name); | |
|   const params = this._bucketRequestParams('PUT', name, 'logging', options); | |
|   let xml = `${'<?xml version="1.0" encoding="UTF-8"?>\n<BucketLoggingStatus>\n<LoggingEnabled>\n<TargetBucket>'}${name}</TargetBucket>\n`; | |
|   if (prefix) { | |
|     xml += `<TargetPrefix>${prefix}</TargetPrefix>\n`; | |
|   } | |
|   xml += '</LoggingEnabled>\n</BucketLoggingStatus>'; | |
|   params.content = xml; | |
|   params.mime = 'xml'; | |
|   params.successStatuses = [200]; | |
|   const result = await this.request(params); | |
|   return { | |
|     res: result.res | |
|   }; | |
| }; | |
| 
 | |
| proto.getBucketLogging = async function getBucketLogging(name, options) { | |
|   _checkBucketName(name); | |
|   const params = this._bucketRequestParams('GET', name, 'logging', options); | |
|   params.successStatuses = [200]; | |
|   params.xmlResponse = true; | |
|   const result = await this.request(params); | |
|   const enable = result.data.LoggingEnabled; | |
|   return { | |
|     enable: !!enable, | |
|     prefix: (enable && enable.TargetPrefix) || null, | |
|     res: result.res | |
|   }; | |
| }; | |
| 
 | |
| proto.deleteBucketLogging = async function deleteBucketLogging(name, options) { | |
|   _checkBucketName(name); | |
|   const params = this._bucketRequestParams('DELETE', name, 'logging', options); | |
|   params.successStatuses = [204, 200]; | |
|   const result = await this.request(params); | |
|   return { | |
|     res: result.res | |
|   }; | |
| }; | |
| 
 | |
| proto.putBucketCORS = async function putBucketCORS(name, rules, options) { | |
|   _checkBucketName(name); | |
|   rules = rules || []; | |
|   assert(rules.length, 'rules is required'); | |
|   rules.forEach(rule => { | |
|     assert(rule.allowedOrigin, 'allowedOrigin is required'); | |
|     assert(rule.allowedMethod, 'allowedMethod is required'); | |
|   }); | |
| 
 | |
|   const params = this._bucketRequestParams('PUT', name, 'cors', options); | |
|   let xml = '<?xml version="1.0" encoding="UTF-8"?>\n<CORSConfiguration>'; | |
|   const parseOrigin = val => { | |
|     xml += `<AllowedOrigin>${val}</AllowedOrigin>`; | |
|   }; | |
|   const parseMethod = val => { | |
|     xml += `<AllowedMethod>${val}</AllowedMethod>`; | |
|   }; | |
|   const parseHeader = val => { | |
|     xml += `<AllowedHeader>${val}</AllowedHeader>`; | |
|   }; | |
|   const parseExposeHeader = val => { | |
|     xml += `<ExposeHeader>${val}</ExposeHeader>`; | |
|   }; | |
|   for (let i = 0, l = rules.length; i < l; i++) { | |
|     const rule = rules[i]; | |
|     xml += '<CORSRule>'; | |
| 
 | |
|     toArray(rule.allowedOrigin).forEach(parseOrigin); | |
|     toArray(rule.allowedMethod).forEach(parseMethod); | |
|     toArray(rule.allowedHeader).forEach(parseHeader); | |
|     toArray(rule.exposeHeader).forEach(parseExposeHeader); | |
|     if (rule.maxAgeSeconds) { | |
|       xml += `<MaxAgeSeconds>${rule.maxAgeSeconds}</MaxAgeSeconds>`; | |
|     } | |
|     xml += '</CORSRule>'; | |
|   } | |
|   xml += '</CORSConfiguration>'; | |
|   params.content = xml; | |
|   params.mime = 'xml'; | |
|   params.successStatuses = [200]; | |
|   const result = await this.request(params); | |
|   return { | |
|     res: result.res | |
|   }; | |
| }; | |
| 
 | |
| proto.getBucketCORS = async function getBucketCORS(name, options) { | |
|   _checkBucketName(name); | |
|   const params = this._bucketRequestParams('GET', name, 'cors', options); | |
|   params.successStatuses = [200]; | |
|   params.xmlResponse = true; | |
|   const result = await this.request(params); | |
|   const rules = []; | |
|   if (result.data && result.data.CORSRule) { | |
|     let { CORSRule } = result.data; | |
|     if (!isArray(CORSRule)) CORSRule = [CORSRule]; | |
|     CORSRule.forEach(rule => { | |
|       const r = {}; | |
|       Object.keys(rule).forEach(key => { | |
|         r[key.slice(0, 1).toLowerCase() + key.slice(1, key.length)] = rule[key]; | |
|       }); | |
|       rules.push(r); | |
|     }); | |
|   } | |
|   return { | |
|     rules, | |
|     res: result.res | |
|   }; | |
| }; | |
| 
 | |
| proto.deleteBucketCORS = async function deleteBucketCORS(name, options) { | |
|   _checkBucketName(name); | |
|   const params = this._bucketRequestParams('DELETE', name, 'cors', options); | |
|   params.successStatuses = [204]; | |
|   const result = await this.request(params); | |
|   return { | |
|     res: result.res | |
|   }; | |
| }; | |
| 
 | |
| // referer | |
|  | |
| proto.putBucketReferer = async function putBucketReferer(name, allowEmpty, referers, options) { | |
|   _checkBucketName(name); | |
|   const params = this._bucketRequestParams('PUT', name, 'referer', options); | |
|   let xml = '<?xml version="1.0" encoding="UTF-8"?>\n<RefererConfiguration>\n'; | |
|   xml += `  <AllowEmptyReferer>${allowEmpty ? 'true' : 'false'}</AllowEmptyReferer>\n`; | |
|   if (referers && referers.length > 0) { | |
|     xml += '  <RefererList>\n'; | |
|     for (let i = 0; i < referers.length; i++) { | |
|       xml += `    <Referer>${referers[i]}</Referer>\n`; | |
|     } | |
|     xml += '  </RefererList>\n'; | |
|   } else { | |
|     xml += '  <RefererList />\n'; | |
|   } | |
|   xml += '</RefererConfiguration>'; | |
|   params.content = xml; | |
|   params.mime = 'xml'; | |
|   params.successStatuses = [200]; | |
|   const result = await this.request(params); | |
|   return { | |
|     res: result.res | |
|   }; | |
| }; | |
| 
 | |
| proto.getBucketReferer = async function getBucketReferer(name, options) { | |
|   _checkBucketName(name); | |
|   const params = this._bucketRequestParams('GET', name, 'referer', options); | |
|   params.successStatuses = [200]; | |
|   params.xmlResponse = true; | |
|   const result = await this.request(params); | |
|   let referers = result.data.RefererList.Referer || null; | |
|   if (referers) { | |
|     if (!isArray(referers)) { | |
|       referers = [referers]; | |
|     } | |
|   } | |
|   return { | |
|     allowEmpty: result.data.AllowEmptyReferer === 'true', | |
|     referers, | |
|     res: result.res | |
|   }; | |
| }; | |
| 
 | |
| proto.deleteBucketReferer = async function deleteBucketReferer(name, options) { | |
|   _checkBucketName(name); | |
|   return await this.putBucketReferer(name, true, null, options); | |
| }; | |
| 
 | |
| // private apis | |
|  | |
| proto._bucketRequestParams = function _bucketRequestParams(method, bucket, subres, options) { | |
|   return { | |
|     method, | |
|     bucket, | |
|     subres, | |
|     headers: options && options.headers, | |
|     additionalHeaders: options && options.additionalHeaders, | |
|     timeout: options && options.timeout, | |
|     ctx: options && options.ctx | |
|   }; | |
| };
 |