Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
75 changes: 26 additions & 49 deletions lib/api/bucketGet.js
Original file line number Diff line number Diff line change
Expand Up @@ -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:
<ListBucketResult xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
Expand Down Expand Up @@ -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);
Expand All @@ -143,7 +137,8 @@ function processVersions(bucketName, listParams, list) {
`<Key>${objectKey}</Key>`,
'<VersionId>',
(v.IsNull || v.VersionId === undefined) ?
'null' : versionIdUtils.encode(v.VersionId),
'null'
: versionIdUtils.encode(v.VersionId),
'</VersionId>',
`<IsLatest>${isLatest}</IsLatest>`,
`<LastModified>${v.LastModified}</LastModified>`,
Expand Down Expand Up @@ -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}>`);
Expand Down Expand Up @@ -246,10 +229,10 @@ function processMasterVersions(bucketName, listParams, list) {
);
});
list.CommonPrefixes.forEach(item => {
const val = escapeXmlFn(item);
xml.push(`<CommonPrefixes><Prefix>${val}</Prefix></CommonPrefixes>`);
xml.push(`<CommonPrefixes><Prefix>${escapeXmlFn(item)}</Prefix></CommonPrefixes>`);
});
xml.push('</ListBucketResult>');

return xml.join('');
}

Expand Down Expand Up @@ -298,17 +281,13 @@ function bucketGet(authInfo, request, log, callback) {
'List Type specified in Request'));
}
if (v2) {
log.addDefaultFields({
action: 'ListObjectsV2',
});
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',
});
log.addDefaultFields({ action: 'ListObjectVersions' });
if (request.serverAccessLog) {
// eslint-disable-next-line no-param-reassign
request.serverAccessLog.analyticsAction = 'ListObjectVersions';
Expand All @@ -317,16 +296,14 @@ function bucketGet(authInfo, request, log, callback) {
log.debug('processing request', { method: 'bucketGet' });
const encoding = params['encoding-type'];
if (encoding !== undefined && encoding !== 'url') {
monitoring.promMetrics(
'GET', bucketName, 400, 'listBucket');
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;

const requestMaxKeys = params['max-keys'] ? Number.parseInt(params['max-keys'], 10) : 1000;
if (Number.isNaN(requestMaxKeys) || requestMaxKeys < 0) {
monitoring.promMetrics(
'GET', bucketName, 400, 'listBucket');
monitoring.promMetrics('GET', bucketName, 400, 'listBucket');
return callback(errors.InvalidArgument);
}
// AWS only returns 1000 keys even if max keys are greater.
Expand All @@ -353,8 +330,7 @@ function bucketGet(authInfo, request, log, callback) {
if (v2) {
listParams.v2 = true;
listParams.startAfter = params['start-after'];
listParams.continuationToken =
decryptToken(params['continuation-token']);
listParams.continuationToken = decryptToken(params['continuation-token']);
listParams.fetchOwner = params['fetch-owner'] === 'true';
} else {
listParams.marker = params.marker;
Expand All @@ -374,7 +350,8 @@ function bucketGet(authInfo, request, log, callback) {
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) {
Expand Down
41 changes: 13 additions & 28 deletions lib/api/objectGetLegalHold.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,16 +25,12 @@ function objectGetLegalHold(authInfo, request, log, callback) {

const decodedVidResult = decodeVersionId(query);
if (decodedVidResult instanceof Error) {
log.trace('invalid versionId query', {
versionId: query.versionId,
error: decodedVidResult,
});
log.trace('invalid versionId query', { versionId: query.versionId, error: decodedVidResult });
return process.nextTick(() => callback(decodedVidResult));
}
const versionId = decodedVidResult;

// FIXME pass 'getDeleteMarker: true' option to set
// 'x-amz-delete-marker' header (see S3C-7592)
// FIXME pass 'getDeleteMarker: true' option to set 'x-amz-delete-marker' header (see S3C-7592)
const metadataValParams = {
authInfo,
bucketName,
Expand All @@ -48,34 +44,26 @@ function objectGetLegalHold(authInfo, request, log, callback) {
next => standardMetadataValidateBucketAndObj(metadataValParams, request.actionImplicitDenies, log,
(err, bucket, objectMD) => {
if (err) {
log.trace('request authorization failed',
{ method: 'objectGetLegalHold', error: err });
log.trace('request authorization failed', { method: 'objectGetLegalHold', error: err });
return next(err);
}
if (!objectMD) {
const err = versionId ? errors.NoSuchVersion :
errors.NoSuchKey;
log.trace('error no object metadata found',
{ method: 'objectGetLegalHold', error: err });
const err = versionId ? errors.NoSuchVersion : errors.NoSuchKey;
log.trace('error no object metadata found', { method: 'objectGetLegalHold', error: err });
return next(err, bucket);
}
if (objectMD.isDeleteMarker) {
if (versionId) {
log.trace('requested version is delete marker',
{ method: 'objectGetLegalHold' });
// FIXME we should return a `x-amz-delete-marker: true` header,
// see S3C-7592
log.trace('requested version is delete marker', { method: 'objectGetLegalHold' });
// FIXME we should return a `x-amz-delete-marker: true` header, see S3C-7592
return next(errors.MethodNotAllowed);
}
log.trace('most recent version is delete marker',
{ method: 'objectGetLegalHold' });
// FIXME we should return a `x-amz-delete-marker: true` header,
// see S3C-7592
log.trace('most recent version is delete marker', { method: 'objectGetLegalHold' });
// FIXME we should return a `x-amz-delete-marker: true` header, see S3C-7592
return next(errors.NoSuchKey);
}
if (!bucket.isObjectLockEnabled()) {
log.trace('object lock not enabled on bucket',
{ method: 'objectGetRetention' });
log.trace('object lock not enabled on bucket', { method: 'objectGetRetention' });
return next(errorInstances.InvalidRequest.customizeDescription(
'Bucket is missing Object Lock Configuration'));
}
Expand All @@ -90,11 +78,9 @@ function objectGetLegalHold(authInfo, request, log, callback) {
return next(null, bucket, xml, objectMD);
},
], (err, bucket, xml, objectMD) => {
const additionalResHeaders = collectCorsHeaders(request.headers.origin,
request.method, bucket);
const additionalResHeaders = collectCorsHeaders(request.headers.origin, request.method, bucket);
if (err) {
log.trace('error processing request', { error: err,
method: 'objectGetLegalHold' });
log.trace('error processing request', { error: err, method: 'objectGetLegalHold' });
} else {
pushMetric('getObjectLegalHold', log, {
authInfo,
Expand All @@ -104,8 +90,7 @@ function objectGetLegalHold(authInfo, request, log, callback) {
location: objectMD ? objectMD.dataStoreName : undefined,
});
const verCfg = bucket.getVersioningConfiguration();
additionalResHeaders['x-amz-version-id'] =
getVersionIdResHeader(verCfg, objectMD);
additionalResHeaders['x-amz-version-id'] = getVersionIdResHeader(verCfg, objectMD);
}
return callback(err, xml, additionalResHeaders);
});
Expand Down
Loading