Skip to content

Commit 9ad101e

Browse files
authored
Merge pull request #8481 from dannyzaken/danny-fixes
lifecycle fixes
2 parents 0b9e0d1 + 3972487 commit 9ad101e

File tree

3 files changed

+64
-0
lines changed

3 files changed

+64
-0
lines changed

src/endpoint/s3/ops/s3_get_bucket_lifecycle.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ async function get_bucket_lifecycle(req) {
4747
current_rule.Expiration = {
4848
Days: rule.expiration.days,
4949
Date: rule.expiration.date ? new Date(rule.expiration.date).toISOString() : undefined,
50+
ExpiredObjectDeleteMarker: rule.expiration.expired_object_delete_marker,
5051
};
5152
_.omitBy(current_rule.Expiration, _.isUndefined);
5253
}

src/endpoint/s3/ops/s3_put_bucket_lifecycle.js

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,13 @@ function parse_filter(filter) {
4646
return current_rule_filter;
4747
}
4848

49+
function reject_empty_field(field) {
50+
if (_.isEmpty(field)) {
51+
dbg.error('Invalid field - empty', field);
52+
throw new S3Error(S3Error.MalformedXML);
53+
}
54+
}
55+
4956
// parse lifecycle rule expiration
5057
function parse_expiration(expiration) {
5158
const output_expiration = {};
@@ -111,12 +118,14 @@ async function put_bucket_lifecycle(req) {
111118

112119
if (rule.Expiration?.length === 1) {
113120
current_rule.expiration = parse_expiration(rule.Expiration[0]);
121+
reject_empty_field(current_rule.expiration);
114122
}
115123

116124
if (rule.AbortIncompleteMultipartUpload?.length === 1) {
117125
current_rule.abort_incomplete_multipart_upload = _.omitBy({
118126
days_after_initiation: parse_lifecycle_field(rule.AbortIncompleteMultipartUpload[0].DaysAfterInitiation),
119127
}, _.isUndefined);
128+
reject_empty_field(current_rule.abort_incomplete_multipart_upload);
120129
}
121130

122131
if (rule.Transition?.length === 1) {
@@ -125,13 +134,15 @@ async function put_bucket_lifecycle(req) {
125134
date: parse_lifecycle_field(rule.Transition[0].Date, s => new Date(s)),
126135
days: parse_lifecycle_field(rule.Transition[0].Days),
127136
}, _.isUndefined);
137+
reject_empty_field(current_rule.transition);
128138
}
129139

130140
if (rule.NoncurrentVersionExpiration?.length === 1) {
131141
current_rule.noncurrent_version_expiration = _.omitBy({
132142
noncurrent_days: parse_lifecycle_field(rule.NoncurrentVersionExpiration[0].NoncurrentDays),
133143
newer_noncurrent_versions: parse_lifecycle_field(rule.NoncurrentVersionExpiration[0].NewerNoncurrentVersions),
134144
}, _.isUndefined);
145+
reject_empty_field(current_rule.noncurrent_version_expiration);
135146
}
136147

137148
if (rule.NoncurrentVersionTransition?.length === 1) {
@@ -140,6 +151,7 @@ async function put_bucket_lifecycle(req) {
140151
noncurrent_days: parse_lifecycle_field(rule.NoncurrentVersionTransition[0].NoncurrentDays),
141152
newer_noncurrent_versions: parse_lifecycle_field(rule.NoncurrentVersionTransition[0].NewerNoncurrentVersions),
142153
}, _.isUndefined);
154+
reject_empty_field(current_rule.noncurrent_version_transition);
143155
}
144156

145157
return current_rule;

src/test/unit_tests/test_s3_ops.js

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -403,6 +403,57 @@ mocha.describe('s3_ops', function() {
403403
assert.strictEqual(res.Rules[0].NoncurrentVersionExpiration.NoncurrentDays, 1);
404404
});
405405

406+
mocha.it('should put and get bucket lifecycle with expired object delete marker', async function() {
407+
// put bucket lifecycle
408+
const params = {
409+
Bucket: "lifecycle-bucket",
410+
LifecycleConfiguration: {
411+
Rules: [{
412+
ID: 'rule1',
413+
Status: 'Enabled',
414+
Prefix: 'prefix1-expired-object-delete-marker',
415+
Expiration: {
416+
ExpiredObjectDeleteMarker: true
417+
}
418+
}]
419+
}
420+
};
421+
await s3.putBucketLifecycleConfiguration(params);
422+
423+
// get bucket lifecycle
424+
const res = await s3.getBucketLifecycleConfiguration({ Bucket: "lifecycle-bucket" });
425+
assert.strictEqual(res.Rules.length, 1);
426+
assert.strictEqual(res.Rules[0].ID, 'rule1');
427+
assert.strictEqual(res.Rules[0].Status, 'Enabled');
428+
assert.strictEqual(res.Rules[0].Prefix, 'prefix1-expired-object-delete-marker');
429+
assert.strictEqual(res.Rules[0].Expiration.ExpiredObjectDeleteMarker, true);
430+
});
431+
432+
mocha.it('should reject put bucket lifecycle with empty fields', async function() {
433+
const lifecycle_fields = ['Expiration', 'NoncurrentVersionExpiration', 'AbortIncompleteMultipartUpload'];
434+
for (const field of lifecycle_fields) {
435+
const params = {
436+
Bucket: "lifecycle-bucket",
437+
LifecycleConfiguration: {
438+
Rules: [{
439+
ID: 'rule1',
440+
Status: 'Enabled',
441+
Prefix: `prefix1-empty-${field}`,
442+
}]
443+
}
444+
};
445+
params.LifecycleConfiguration.Rules[0][field] = {};
446+
try {
447+
await s3.putBucketLifecycleConfiguration(params);
448+
assert.fail(`should reject put bucket lifecycle with empty ${field}`);
449+
} catch (err) {
450+
assert.strictEqual(err.Code, 'MalformedXML', `should reject put bucket lifecycle with empty ${field}`);
451+
assert.strictEqual(err.$metadata.httpStatusCode, 400);
452+
}
453+
}
454+
});
455+
456+
406457
mocha.after(async function() {
407458
await s3.deleteBucket({ Bucket: "lifecycle-bucket" });
408459
});

0 commit comments

Comments
 (0)