bucket.js 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345
  1. const assert = require('assert');
  2. const { isArray } = require('./common/utils/isArray');
  3. const { checkBucketName: _checkBucketName } = require('../lib/common/utils/checkBucketName');
  4. const { formatTag } = require('../lib/common/utils/formatTag');
  5. const proto = exports;
  6. function toArray(obj) {
  7. if (!obj) return [];
  8. if (isArray(obj)) return obj;
  9. return [obj];
  10. }
  11. /**
  12. * Bucket opertaions
  13. */
  14. proto.listBuckets = async function listBuckets(query = {}, options = {}) {
  15. // prefix, marker, max-keys
  16. const { subres = {} } = query;
  17. const rest = {};
  18. for (const key in query) {
  19. if (key !== 'subres') {
  20. rest[key] = query[key];
  21. }
  22. }
  23. const params = this._bucketRequestParams(
  24. 'GET',
  25. '',
  26. Object.assign(subres, options.subres),
  27. options
  28. );
  29. params.query = rest;
  30. const result = await this.request(params);
  31. if (result.status === 200) {
  32. const data = await this.parseXML(result.data);
  33. let buckets = data.Buckets || null;
  34. if (buckets) {
  35. if (buckets.Bucket) {
  36. buckets = buckets.Bucket;
  37. }
  38. if (!isArray(buckets)) {
  39. buckets = [buckets];
  40. }
  41. buckets = buckets.map(item => ({
  42. name: item.Name,
  43. region: item.Location,
  44. creationDate: item.CreationDate,
  45. storageClass: item.StorageClass,
  46. StorageClass: item.StorageClass,
  47. tag: formatTag(item)
  48. }));
  49. }
  50. return {
  51. buckets,
  52. owner: {
  53. id: data.Owner.ID,
  54. displayName: data.Owner.DisplayName
  55. },
  56. isTruncated: data.IsTruncated === 'true',
  57. nextMarker: data.NextMarker || null,
  58. res: result.res
  59. };
  60. }
  61. throw await this.requestError(result);
  62. };
  63. proto.useBucket = function useBucket(name) {
  64. _checkBucketName(name);
  65. return this.setBucket(name);
  66. };
  67. proto.setBucket = function useBucket(name) {
  68. _checkBucketName(name);
  69. this.options.bucket = name;
  70. return this;
  71. };
  72. proto.getBucket = function getBucket() {
  73. return this.options.bucket;
  74. };
  75. proto.getBucketLocation = async function getBucketLocation(name, options) {
  76. _checkBucketName(name);
  77. name = name || this.getBucket();
  78. const params = this._bucketRequestParams('GET', name, 'location', options);
  79. params.successStatuses = [200];
  80. params.xmlResponse = true;
  81. const result = await this.request(params);
  82. return {
  83. location: result.data,
  84. res: result.res
  85. };
  86. };
  87. proto.getBucketInfo = async function getBucketInfo(name, options) {
  88. _checkBucketName(name);
  89. name = name || this.getBucket();
  90. const params = this._bucketRequestParams('GET', name, 'bucketInfo', options);
  91. params.successStatuses = [200];
  92. params.xmlResponse = true;
  93. const result = await this.request(params);
  94. return {
  95. bucket: result.data.Bucket,
  96. res: result.res
  97. };
  98. };
  99. proto.deleteBucket = async function deleteBucket(name, options) {
  100. _checkBucketName(name);
  101. const params = this._bucketRequestParams('DELETE', name, '', options);
  102. const result = await this.request(params);
  103. if (result.status === 200 || result.status === 204) {
  104. return {
  105. res: result.res
  106. };
  107. }
  108. throw await this.requestError(result);
  109. };
  110. // acl
  111. proto.putBucketACL = async function putBucketACL(name, acl, options) {
  112. _checkBucketName(name);
  113. const params = this._bucketRequestParams('PUT', name, 'acl', options);
  114. params.headers = {
  115. 'x-oss-acl': acl
  116. };
  117. params.successStatuses = [200];
  118. const result = await this.request(params);
  119. return {
  120. bucket: (result.headers.location && result.headers.location.substring(1)) || null,
  121. res: result.res
  122. };
  123. };
  124. proto.getBucketACL = async function getBucketACL(name, options) {
  125. _checkBucketName(name);
  126. const params = this._bucketRequestParams('GET', name, 'acl', options);
  127. params.successStatuses = [200];
  128. params.xmlResponse = true;
  129. const result = await this.request(params);
  130. return {
  131. acl: result.data.AccessControlList.Grant,
  132. owner: {
  133. id: result.data.Owner.ID,
  134. displayName: result.data.Owner.DisplayName
  135. },
  136. res: result.res
  137. };
  138. };
  139. // logging
  140. proto.putBucketLogging = async function putBucketLogging(name, prefix, options) {
  141. _checkBucketName(name);
  142. const params = this._bucketRequestParams('PUT', name, 'logging', options);
  143. let xml = `${'<?xml version="1.0" encoding="UTF-8"?>\n<BucketLoggingStatus>\n' +
  144. '<LoggingEnabled>\n<TargetBucket>'}${name}</TargetBucket>\n`;
  145. if (prefix) {
  146. xml += `<TargetPrefix>${prefix}</TargetPrefix>\n`;
  147. }
  148. xml += '</LoggingEnabled>\n</BucketLoggingStatus>';
  149. params.content = xml;
  150. params.mime = 'xml';
  151. params.successStatuses = [200];
  152. const result = await this.request(params);
  153. return {
  154. res: result.res
  155. };
  156. };
  157. proto.getBucketLogging = async function getBucketLogging(name, options) {
  158. _checkBucketName(name);
  159. const params = this._bucketRequestParams('GET', name, 'logging', options);
  160. params.successStatuses = [200];
  161. params.xmlResponse = true;
  162. const result = await this.request(params);
  163. const enable = result.data.LoggingEnabled;
  164. return {
  165. enable: !!enable,
  166. prefix: (enable && enable.TargetPrefix) || null,
  167. res: result.res
  168. };
  169. };
  170. proto.deleteBucketLogging = async function deleteBucketLogging(name, options) {
  171. _checkBucketName(name);
  172. const params = this._bucketRequestParams('DELETE', name, 'logging', options);
  173. params.successStatuses = [204, 200];
  174. const result = await this.request(params);
  175. return {
  176. res: result.res
  177. };
  178. };
  179. proto.putBucketCORS = async function putBucketCORS(name, rules, options) {
  180. _checkBucketName(name);
  181. rules = rules || [];
  182. assert(rules.length, 'rules is required');
  183. rules.forEach((rule) => {
  184. assert(rule.allowedOrigin, 'allowedOrigin is required');
  185. assert(rule.allowedMethod, 'allowedMethod is required');
  186. });
  187. const params = this._bucketRequestParams('PUT', name, 'cors', options);
  188. let xml = '<?xml version="1.0" encoding="UTF-8"?>\n<CORSConfiguration>';
  189. const parseOrigin = (val) => {
  190. xml += `<AllowedOrigin>${val}</AllowedOrigin>`;
  191. };
  192. const parseMethod = (val) => {
  193. xml += `<AllowedMethod>${val}</AllowedMethod>`;
  194. };
  195. const parseHeader = (val) => {
  196. xml += `<AllowedHeader>${val}</AllowedHeader>`;
  197. };
  198. const parseExposeHeader = (val) => {
  199. xml += `<ExposeHeader>${val}</ExposeHeader>`;
  200. };
  201. for (let i = 0, l = rules.length; i < l; i++) {
  202. const rule = rules[i];
  203. xml += '<CORSRule>';
  204. toArray(rule.allowedOrigin).forEach(parseOrigin);
  205. toArray(rule.allowedMethod).forEach(parseMethod);
  206. toArray(rule.allowedHeader).forEach(parseHeader);
  207. toArray(rule.exposeHeader).forEach(parseExposeHeader);
  208. if (rule.maxAgeSeconds) {
  209. xml += `<MaxAgeSeconds>${rule.maxAgeSeconds}</MaxAgeSeconds>`;
  210. }
  211. xml += '</CORSRule>';
  212. }
  213. xml += '</CORSConfiguration>';
  214. params.content = xml;
  215. params.mime = 'xml';
  216. params.successStatuses = [200];
  217. const result = await this.request(params);
  218. return {
  219. res: result.res
  220. };
  221. };
  222. proto.getBucketCORS = async function getBucketCORS(name, options) {
  223. _checkBucketName(name);
  224. const params = this._bucketRequestParams('GET', name, 'cors', options);
  225. params.successStatuses = [200];
  226. params.xmlResponse = true;
  227. const result = await this.request(params);
  228. const rules = [];
  229. if (result.data && result.data.CORSRule) {
  230. let { CORSRule } = result.data;
  231. if (!isArray(CORSRule)) CORSRule = [CORSRule];
  232. CORSRule.forEach((rule) => {
  233. const r = {};
  234. Object.keys(rule).forEach((key) => {
  235. r[key.slice(0, 1).toLowerCase() + key.slice(1, key.length)] = rule[key];
  236. });
  237. rules.push(r);
  238. });
  239. }
  240. return {
  241. rules,
  242. res: result.res
  243. };
  244. };
  245. proto.deleteBucketCORS = async function deleteBucketCORS(name, options) {
  246. _checkBucketName(name);
  247. const params = this._bucketRequestParams('DELETE', name, 'cors', options);
  248. params.successStatuses = [204];
  249. const result = await this.request(params);
  250. return {
  251. res: result.res
  252. };
  253. };
  254. // referer
  255. proto.putBucketReferer = async function putBucketReferer(name, allowEmpty, referers, options) {
  256. _checkBucketName(name);
  257. const params = this._bucketRequestParams('PUT', name, 'referer', options);
  258. let xml = '<?xml version="1.0" encoding="UTF-8"?>\n<RefererConfiguration>\n';
  259. xml += ` <AllowEmptyReferer>${allowEmpty ? 'true' : 'false'}</AllowEmptyReferer>\n`;
  260. if (referers && referers.length > 0) {
  261. xml += ' <RefererList>\n';
  262. for (let i = 0; i < referers.length; i++) {
  263. xml += ` <Referer>${referers[i]}</Referer>\n`;
  264. }
  265. xml += ' </RefererList>\n';
  266. } else {
  267. xml += ' <RefererList />\n';
  268. }
  269. xml += '</RefererConfiguration>';
  270. params.content = xml;
  271. params.mime = 'xml';
  272. params.successStatuses = [200];
  273. const result = await this.request(params);
  274. return {
  275. res: result.res
  276. };
  277. };
  278. proto.getBucketReferer = async function getBucketReferer(name, options) {
  279. _checkBucketName(name);
  280. const params = this._bucketRequestParams('GET', name, 'referer', options);
  281. params.successStatuses = [200];
  282. params.xmlResponse = true;
  283. const result = await this.request(params);
  284. let referers = result.data.RefererList.Referer || null;
  285. if (referers) {
  286. if (!isArray(referers)) {
  287. referers = [referers];
  288. }
  289. }
  290. return {
  291. allowEmpty: result.data.AllowEmptyReferer === 'true',
  292. referers,
  293. res: result.res
  294. };
  295. };
  296. proto.deleteBucketReferer = async function deleteBucketReferer(name, options) {
  297. _checkBucketName(name);
  298. return await this.putBucketReferer(name, true, null, options);
  299. };
  300. // private apis
  301. proto._bucketRequestParams = function _bucketRequestParams(method, bucket, subres, options) {
  302. return {
  303. method,
  304. bucket,
  305. subres,
  306. timeout: options && options.timeout,
  307. ctx: options && options.ctx
  308. };
  309. };