@@ -9,11 +9,44 @@ const S3Error = require('../s3_errors').S3Error;
9
9
10
10
const true_regex = / t r u e / i;
11
11
12
- // parse lifecycle rule filter
13
- function parse_filter ( filter ) {
14
- if ( filter ?. length > 1 && ! filter ?. And ) {
12
+ // validates lifecycle rule
13
+ function validate_lifecycle_rule ( rule ) {
14
+
15
+ if ( rule . ID ?. length === 1 && rule . ID [ 0 ] . length > s3_const . MAX_RULE_ID_LENGTH ) {
16
+ dbg . error ( 'Rule should not have ID length exceed allowed limit of ' , s3_const . MAX_RULE_ID_LENGTH , ' characters' , rule ) ;
17
+ throw new S3Error ( { ...S3Error . InvalidArgument , message : `ID length should not exceed allowed limit of ${ s3_const . MAX_RULE_ID_LENGTH } ` } ) ;
18
+ }
19
+
20
+ if ( ! rule . Status || rule . Status . length !== 1 ||
21
+ ( rule . Status [ 0 ] !== s3_const . LIFECYCLE_STATUS . STAT_ENABLED && rule . Status [ 0 ] !== s3_const . LIFECYCLE_STATUS . STAT_DISABLED ) ) {
22
+ dbg . error ( `Rule should have a status value of "${ s3_const . LIFECYCLE_STATUS . STAT_ENABLED } " or "${ s3_const . LIFECYCLE_STATUS . STAT_DISABLED } ".` , rule ) ;
23
+ throw new S3Error ( S3Error . MalformedXML ) ;
24
+ }
25
+
26
+ if ( rule . Filter ?. length === 1 && Object . keys ( rule . Filter [ 0 ] ) . length > 1 && ! rule . Filter [ 0 ] ?. And ) {
27
+ dbg . error ( 'Rule should combine multiple filters using "And"' , rule ) ;
28
+ throw new S3Error ( S3Error . MalformedXML ) ;
29
+ }
30
+
31
+ if ( rule . Expiration ?. length === 1 && Object . keys ( rule . Expiration [ 0 ] ) . length > 1 ) {
32
+ dbg . error ( 'Rule should specify only one expiration field: Days, Date, or ExpiredObjectDeleteMarker' , rule ) ;
15
33
throw new S3Error ( S3Error . MalformedXML ) ;
16
34
}
35
+
36
+ if ( rule . AbortIncompleteMultipartUpload ?. length === 1 && rule . Filter ?. length === 1 ) {
37
+ if ( rule . Filter [ 0 ] ?. Tag ) {
38
+ dbg . error ( 'Rule should not include AbortIncompleteMultipartUpload with Tags' , rule ) ;
39
+ throw new S3Error ( { ...S3Error . InvalidArgument , message : 'AbortIncompleteMultipartUpload cannot be specified with Tags' } ) ;
40
+ }
41
+ if ( rule . Filter [ 0 ] ?. ObjectSizeGreaterThan || rule . Filter [ 0 ] ?. ObjectSizeLessThan ) {
42
+ dbg . error ( 'Rule should not include AbortIncompleteMultipartUpload with Object Size' , rule ) ;
43
+ throw new S3Error ( { ...S3Error . InvalidArgument , message : 'AbortIncompleteMultipartUpload cannot be specified with Object Size' } ) ;
44
+ }
45
+ }
46
+ }
47
+
48
+ // parse lifecycle rule filter
49
+ function parse_filter ( filter ) {
17
50
const current_rule_filter = { } ;
18
51
if ( filter . Tag ?. length === 1 ) {
19
52
const tag = filter . Tag [ 0 ] ;
@@ -97,13 +130,11 @@ async function put_bucket_lifecycle(req) {
97
130
filter : { } ,
98
131
} ;
99
132
133
+ // validate rule
134
+ validate_lifecycle_rule ( rule ) ;
135
+
100
136
if ( rule . ID ?. length === 1 ) {
101
- if ( rule . ID [ 0 ] . length > s3_const . MAX_RULE_ID_LENGTH ) {
102
- dbg . error ( 'Rule should not have ID length exceed allowed limit of ' , s3_const . MAX_RULE_ID_LENGTH , ' characters' , rule ) ;
103
- throw new S3Error ( { ...S3Error . InvalidArgument , message : `ID length should not exceed allowed limit of ${ s3_const . MAX_RULE_ID_LENGTH } ` } ) ;
104
- } else {
105
- current_rule . id = rule . ID [ 0 ] ;
106
- }
137
+ current_rule . id = rule . ID [ 0 ] ;
107
138
} else {
108
139
// Generate a random ID if missing
109
140
current_rule . id = crypto . randomUUID ( ) ;
@@ -116,11 +147,6 @@ async function put_bucket_lifecycle(req) {
116
147
}
117
148
id_set . add ( current_rule . id ) ;
118
149
119
- if ( ! rule . Status || rule . Status . length !== 1 ||
120
- ( rule . Status [ 0 ] !== s3_const . LIFECYCLE_STATUS . STAT_ENABLED && rule . Status [ 0 ] !== s3_const . LIFECYCLE_STATUS . STAT_DISABLED ) ) {
121
- dbg . error ( `Rule should have a status value of "${ s3_const . LIFECYCLE_STATUS . STAT_ENABLED } " or "${ s3_const . LIFECYCLE_STATUS . STAT_DISABLED } ".` , rule ) ;
122
- throw new S3Error ( S3Error . MalformedXML ) ;
123
- }
124
150
current_rule . status = rule . Status [ 0 ] ;
125
151
126
152
if ( rule . Prefix ) {
@@ -140,18 +166,11 @@ async function put_bucket_lifecycle(req) {
140
166
}
141
167
142
168
if ( rule . Expiration ?. length === 1 ) {
143
- if ( rule . Expiration . length > 1 ) {
144
- throw new S3Error ( S3Error . MalformedXML ) ;
145
- }
146
169
current_rule . expiration = parse_expiration ( rule . Expiration [ 0 ] ) ;
147
170
reject_empty_field ( current_rule . expiration ) ;
148
171
}
149
172
150
173
if ( rule . AbortIncompleteMultipartUpload ?. length === 1 ) {
151
- if ( rule . Filter ?. Tag || rule . Filter ?. ObjectSizeGreaterThan || rule . Filter ?. ObjectSizeLessThan ) {
152
- dbg . error ( 'Rule should not include AbortIncompleteMultipartUpload with Tags or ObjectSize filters' , rule ) ;
153
- throw new S3Error ( { ...S3Error . InvalidArgument , message : 'AbortIncompleteMultipartUpload cannot be specified with Tags' } ) ;
154
- }
155
174
current_rule . abort_incomplete_multipart_upload = _ . omitBy ( {
156
175
days_after_initiation : parse_lifecycle_field ( rule . AbortIncompleteMultipartUpload [ 0 ] . DaysAfterInitiation ) ,
157
176
} , _ . isUndefined ) ;
0 commit comments