diff --git a/lib/api/bucketGet.js b/lib/api/bucketGet.js
index d4e7e1b81b..4651f89f0e 100644
--- a/lib/api/bucketGet.js
+++ b/lib/api/bucketGet.js
@@ -8,14 +8,9 @@ const escapeForXml = s3middleware.escapeForXml;
const { pushMetric } = require('../utapi/utilities');
const versionIdUtils = versioning.VersionID;
const monitoring = require('../utilities/monitoringHandler');
-const { generateToken, decryptToken }
- = require('../api/apiUtils/object/continueToken');
+const { generateToken, decryptToken } = require('../api/apiUtils/object/continueToken');
-// do not url encode the continuation tokens
-const skipUrlEncoding = new Set([
- 'ContinuationToken',
- 'NextContinuationToken',
-]);
+const xmlParamsToSkipUrlEncoding = new Set(['ContinuationToken', 'NextContinuationToken',]);
/* Sample XML response for GET bucket objects V2:
@@ -122,17 +117,16 @@ function processVersions(bucketName, listParams, list) {
{ tag: 'IsTruncated', value: isTruncated },
];
- const escapeXmlFn = listParams.encoding === 'url' ?
- querystring.escape : escapeForXml;
+ const escapeXmlFn = listParams.encoding === 'url' ? querystring.escape : escapeForXml;
xmlParams.forEach(p => {
if (p.value) {
const val = p.tag !== 'NextVersionIdMarker' || p.value === 'null' ?
- p.value : versionIdUtils.encode(p.value);
+ p.value :
+ versionIdUtils.encode(p.value);
xml.push(`<${p.tag}>${escapeXmlFn(val)}${p.tag}>`);
}
});
- let lastKey = listParams.keyMarker ?
- escapeXmlFn(listParams.keyMarker) : undefined;
+ let lastKey = listParams.keyMarker ? escapeXmlFn(listParams.keyMarker) : undefined;
list.Versions.forEach(item => {
const v = item.value;
const objectKey = escapeXmlFn(item.key);
@@ -143,7 +137,8 @@ function processVersions(bucketName, listParams, list) {
`${objectKey}`,
'',
(v.IsNull || v.VersionId === undefined) ?
- 'null' : versionIdUtils.encode(v.VersionId),
+ 'null'
+ : versionIdUtils.encode(v.VersionId),
'',
`${isLatest}`,
`${v.LastModified}`,
@@ -182,31 +177,19 @@ function processMasterVersions(bucketName, listParams, list) {
];
if (listParams.v2) {
- xmlParams.push(
- { tag: 'StartAfter', value: listParams.startAfter || '' });
- xmlParams.push(
- { tag: 'FetchOwner', value: `${listParams.fetchOwner}` });
- xmlParams.push({
- tag: 'ContinuationToken',
- value: generateToken(listParams.continuationToken) || '',
- });
- xmlParams.push({
- tag: 'NextContinuationToken',
- value: generateToken(list.NextContinuationToken),
- });
- xmlParams.push({
- tag: 'KeyCount',
- value: list.Contents ? list.Contents.length : 0,
- });
+ xmlParams.push({ tag: 'StartAfter', value: listParams.startAfter || '' });
+ xmlParams.push({ tag: 'FetchOwner', value: `${listParams.fetchOwner}` });
+ xmlParams.push({ tag: 'ContinuationToken', value: generateToken(listParams.continuationToken) || '', });
+ xmlParams.push({ tag: 'NextContinuationToken', value: generateToken(list.NextContinuationToken), });
+ xmlParams.push({ tag: 'KeyCount', value: list.Contents ? list.Contents.length : 0, });
} else {
xmlParams.push({ tag: 'Marker', value: listParams.marker || '' });
xmlParams.push({ tag: 'NextMarker', value: list.NextMarker });
}
- const escapeXmlFn = listParams.encoding === 'url' ?
- querystring.escape : escapeForXml;
+ const escapeXmlFn = listParams.encoding === 'url' ? querystring.escape : escapeForXml;
xmlParams.forEach(p => {
- if (p.value && skipUrlEncoding.has(p.tag)) {
+ if (p.value && xmlParamsToSkipUrlEncoding.has(p.tag)) {
xml.push(`<${p.tag}>${p.value}${p.tag}>`);
} else if (p.value || p.tag === 'KeyCount' || p.tag === 'MaxKeys') {
xml.push(`<${p.tag}>${escapeXmlFn(p.value)}${p.tag}>`);
@@ -246,15 +229,14 @@ function processMasterVersions(bucketName, listParams, list) {
);
});
list.CommonPrefixes.forEach(item => {
- const val = escapeXmlFn(item);
- xml.push(`${val}`);
+ xml.push(`${escapeXmlFn(item)}`);
});
xml.push('');
+
return xml.join('');
}
-function handleResult(listParams, requestMaxKeys, encoding, authInfo,
- bucketName, list, corsHeaders, log, callback) {
+function handleResult(listParams, requestMaxKeys, encoding, authInfo, bucketName, list, log) {
// eslint-disable-next-line no-param-reassign
listParams.maxKeys = requestMaxKeys;
// eslint-disable-next-line no-param-reassign
@@ -267,9 +249,24 @@ function handleResult(listParams, requestMaxKeys, encoding, authInfo,
}
pushMetric('listBucket', log, { authInfo, bucket: bucketName });
monitoring.promMetrics('GET', bucketName, '200', 'listBucket');
- return callback(null, res, corsHeaders);
+ return res;
}
+const validateBucket = (params, denials, log) => new Promise(resolve => {
+ standardMetadataValidateBucket(params, denials, log, (error, bucket) => {
+ resolve({ error, bucket });
+ });
+});
+
+const getObjectListing = (bucketName, listParams, log) => new Promise((resolve, reject) => {
+ services.getObjectListing(bucketName, listParams, log, (err, list) => {
+ if (err) {
+ return reject(err);
+ }
+ return resolve(list);
+ });
+});
+
/**
* bucketGet - Return list of objects in bucket, supports v1 & v2
* @param {AuthInfo} authInfo - Instance of AuthInfo class with
@@ -280,92 +277,86 @@ function handleResult(listParams, requestMaxKeys, encoding, authInfo,
* with either error code or xml response body
* @return {undefined}
*/
-function bucketGet(authInfo, request, log, callback) {
- const params = request.query;
- const bucketName = request.bucketName;
- const v2 = params['list-type'];
- if (v2 !== undefined && Number.parseInt(v2, 10) !== 2) {
- return callback(errorInstances.InvalidArgument.customizeDescription('Invalid ' +
- 'List Type specified in Request'));
- }
- if (v2) {
- log.addDefaultFields({
- action: 'ListObjectsV2',
- });
- if (request.serverAccessLog) {
- // eslint-disable-next-line no-param-reassign
- request.serverAccessLog.analyticsAction = 'ListObjectsV2';
+async function bucketGet(authInfo, request, log, callback) {
+ try {
+ const params = request.query;
+ const bucketName = request.bucketName;
+ const v2 = params['list-type'];
+
+ if (v2 !== undefined && Number.parseInt(v2, 10) !== 2) {
+ return callback(errorInstances.InvalidArgument.customizeDescription(
+ 'Invalid List Type specified in Request'
+ ));
}
- } else if (params.versions !== undefined) {
- log.addDefaultFields({
- action: 'ListObjectVersions',
- });
- if (request.serverAccessLog) {
- // eslint-disable-next-line no-param-reassign
- request.serverAccessLog.analyticsAction = 'ListObjectVersions';
+
+ if (v2) {
+ log.addDefaultFields({ action: 'ListObjectsV2', });
+ if (request.serverAccessLog) {
+ // eslint-disable-next-line no-param-reassign
+ request.serverAccessLog.analyticsAction = 'ListObjectsV2';
+ }
+ } else if (params.versions !== undefined) {
+ log.addDefaultFields({ action: 'ListObjectVersions', });
+ if (request.serverAccessLog) {
+ // eslint-disable-next-line no-param-reassign
+ request.serverAccessLog.analyticsAction = 'ListObjectVersions';
+ }
}
- }
- log.debug('processing request', { method: 'bucketGet' });
- const encoding = params['encoding-type'];
- if (encoding !== undefined && encoding !== 'url') {
- monitoring.promMetrics(
- 'GET', bucketName, 400, 'listBucket');
- return callback(errorInstances.InvalidArgument.customizeDescription('Invalid ' +
- 'Encoding Method specified in Request'));
- }
- const requestMaxKeys = params['max-keys'] ?
- Number.parseInt(params['max-keys'], 10) : 1000;
- if (Number.isNaN(requestMaxKeys) || requestMaxKeys < 0) {
- monitoring.promMetrics(
- 'GET', bucketName, 400, 'listBucket');
- return callback(errors.InvalidArgument);
- }
- // AWS only returns 1000 keys even if max keys are greater.
- // Max keys stated in response xml can be greater than actual
- // keys returned.
- const actualMaxKeys = Math.min(constants.listingHardLimit, requestMaxKeys);
+ log.debug('processing request', { method: 'bucketGet' });
+ const encoding = params['encoding-type'];
+ if (encoding !== undefined && encoding !== 'url') {
+ monitoring.promMetrics('GET', bucketName, 400, 'listBucket');
+ return callback(errorInstances.InvalidArgument.customizeDescription(
+ 'Invalid Encoding Method specified in Request'
+ ));
+ }
+ const requestMaxKeys = params['max-keys'] ? Number.parseInt(params['max-keys'], 10) : 1000;
+ if (Number.isNaN(requestMaxKeys) || requestMaxKeys < 0) {
+ monitoring.promMetrics('GET', bucketName, 400, 'listBucket');
+ return callback(errors.InvalidArgument);
+ }
+ const actualMaxKeys = Math.min(constants.listingHardLimit, requestMaxKeys);
- const metadataValParams = {
- authInfo,
- bucketName,
- requestType: request.apiMethods || 'bucketGet',
- request,
- };
- const listParams = {
- listingType: 'DelimiterMaster',
- maxKeys: actualMaxKeys,
- prefix: params.prefix,
- };
+ const metadataValParams = {
+ authInfo,
+ bucketName,
+ requestType: request.apiMethods || 'bucketGet',
+ request,
+ };
+ const listParams = {
+ listingType: 'DelimiterMaster',
+ maxKeys: actualMaxKeys,
+ prefix: params.prefix,
+ };
- if (params.delimiter) {
- listParams.delimiter = params.delimiter;
- }
+ if (params.delimiter) {
+ listParams.delimiter = params.delimiter;
+ }
- if (v2) {
- listParams.v2 = true;
- listParams.startAfter = params['start-after'];
- listParams.continuationToken =
- decryptToken(params['continuation-token']);
- listParams.fetchOwner = params['fetch-owner'] === 'true';
- } else {
- listParams.marker = params.marker;
- }
+ if (v2) {
+ listParams.v2 = true;
+ listParams.startAfter = params['start-after'];
+ listParams.continuationToken = decryptToken(params['continuation-token']);
+ listParams.fetchOwner = params['fetch-owner'] === 'true';
+ } else {
+ listParams.marker = params.marker;
+ }
- standardMetadataValidateBucket(metadataValParams, request.actionImplicitDenies, log, (err, bucket) => {
- const corsHeaders = collectCorsHeaders(request.headers.origin,
- request.method, bucket);
- if (err) {
- log.debug('error processing request', { error: err });
- monitoring.promMetrics(
- 'GET', bucketName, err.code, 'listBucket');
- return callback(err, null, corsHeaders);
+ const { error, bucket } = await validateBucket(metadataValParams, request.actionImplicitDenies, log);
+ const corsHeaders = collectCorsHeaders(request.headers.origin, request.method, bucket);
+
+ if (error) {
+ log.debug('error processing request', { error });
+ monitoring.promMetrics('GET', bucketName, error.code, 'listBucket');
+ return callback(error, null, corsHeaders);
}
if (params.versions !== undefined) {
listParams.listingType = 'DelimiterVersions';
delete listParams.marker;
listParams.keyMarker = params['key-marker'];
listParams.versionIdMarker = params['version-id-marker'] ?
- versionIdUtils.decode(params['version-id-marker']) : undefined;
+ versionIdUtils.decode(params['version-id-marker']) :
+ undefined;
}
if (!requestMaxKeys) {
const emptyList = {
@@ -374,22 +365,25 @@ function bucketGet(authInfo, request, log, callback) {
Versions: [],
IsTruncated: false,
};
- return handleResult(listParams, requestMaxKeys, encoding, authInfo,
- bucketName, emptyList, corsHeaders, log, callback);
+ const res = handleResult(listParams, requestMaxKeys, encoding, authInfo, bucketName, emptyList, log);
+ return callback(null, res, corsHeaders);
}
- return services.getObjectListing(bucketName, listParams, log,
- (err, list) => {
- if (err) {
- log.debug('error processing request', { error: err });
- monitoring.promMetrics(
- 'GET', bucketName, err.code, 'listBucket');
- return callback(err, null, corsHeaders);
- }
- return handleResult(listParams, requestMaxKeys, encoding, authInfo,
- bucketName, list, corsHeaders, log, callback);
- });
- });
- return undefined;
+
+ let list;
+ try {
+ list = await getObjectListing(bucketName, listParams, log);
+ } catch (err) {
+ log.debug('error processing request', { error: err });
+ monitoring.promMetrics('GET', bucketName, err.code, 'listBucket');
+ return callback(err, null, corsHeaders);
+ }
+
+ const res = handleResult(listParams, requestMaxKeys, encoding, authInfo, bucketName, list, log);
+ return callback(null, res, corsHeaders);
+ } catch (err) {
+ log.error('unhandled error in bucketGet', { error: err });
+ return callback(errors.InternalError);
+ }
}
module.exports = {
@@ -397,3 +391,4 @@ module.exports = {
processMasterVersions,
bucketGet,
};
+
diff --git a/lib/api/objectGetLegalHold.js b/lib/api/objectGetLegalHold.js
index 2f165748f3..f8f02a079f 100644
--- a/lib/api/objectGetLegalHold.js
+++ b/lib/api/objectGetLegalHold.js
@@ -1,4 +1,3 @@
-const async = require('async');
const { errors, errorInstances, s3middleware } = require('arsenal');
const { decodeVersionId, getVersionIdResHeader }
@@ -15,26 +14,21 @@ const { convertToXml } = s3middleware.objectLegalHold;
* @param {AuthInfo} authInfo - Instance of AuthInfo class with requester's info
* @param {object} request - http request object
* @param {object} log - Werelogs logger
- * @param {function} callback - callback to server
- * @return {undefined}
+ * @return {Promise