@@ -6,22 +6,22 @@ const { v4: uuid } = require('uuid');
66const dbg = require ( '../../../util/debug_module' ) ( __filename ) ;
77const S3Error = require ( '../s3_errors' ) . S3Error ;
88
9+ const true_regex = / t r u e / i;
10+
911// parse lifecycle rule filter
1012function parse_filter ( filter ) {
1113 const current_rule_filter = { } ;
12- if ( filter . Tag && filter . Tag . length === 1 ) {
14+ if ( filter . Tag ? .length === 1 ) {
1315 const tag = filter . Tag [ 0 ] ;
1416 current_rule_filter . tags = [ { key : tag . Key [ 0 ] , value : tag . Value [ 0 ] } ] ;
1517 }
16- if ( filter . Prefix && filter . Prefix . length === 1 ) {
18+ if ( filter . Prefix ? .length === 1 ) {
1719 current_rule_filter . prefix = filter . Prefix [ 0 ] ;
1820 }
19- if ( filter . ObjectSizeGreaterThan &&
20- filter . ObjectSizeGreaterThan . length === 1 ) {
21+ if ( filter . ObjectSizeGreaterThan ?. length === 1 ) {
2122 current_rule_filter . object_size_greater_than = parseInt ( filter . ObjectSizeGreaterThan [ 0 ] , 10 ) ;
2223 }
23- if ( filter . ObjectSizeLessThan &&
24- filter . ObjectSizeLessThan . length === 1 ) {
24+ if ( filter . ObjectSizeLessThan ?. length === 1 ) {
2525 current_rule_filter . object_size_less_than = parseInt ( filter . ObjectSizeLessThan [ 0 ] , 10 ) ;
2626 }
2727 if ( current_rule_filter . object_size_greater_than !== undefined &&
@@ -30,21 +30,16 @@ function parse_filter(filter) {
3030 dbg . error ( 'Invalid size range: filter' , filter , 'size range: object_size_greater_than' , current_rule_filter . object_size_greater_than , '>= object_size_less_than' , current_rule_filter . object_size_less_than ) ;
3131 throw new S3Error ( S3Error . InvalidArgument ) ;
3232 }
33- if ( filter . And &&
34- filter . And . length === 1 ) {
35-
33+ if ( filter . And ?. length === 1 ) {
3634 current_rule_filter . and = true ;
37- if ( filter . And [ 0 ] . Prefix &&
38- filter . And [ 0 ] . Prefix . length === 1 ) {
39- current_rule_filter . prefix = filter . And [ 0 ] . Prefix [ 0 ] ;
35+ if ( filter . And [ 0 ] . Prefix ?. length === 1 ) {
36+ current_rule_filter . prefix = filter . And [ 0 ] . Prefix [ 0 ] ;
4037 }
41- current_rule_filter . tags = _ . map ( filter . And [ 0 ] . Tag , tag => ( { key : tag . Key [ 0 ] , value : tag . Value [ 0 ] } ) ) ;
42- if ( filter . And [ 0 ] . ObjectSizeGreaterThan &&
43- filter . And [ 0 ] . ObjectSizeGreaterThan . length === 1 ) {
38+ current_rule_filter . tags = _ . map ( filter . And [ 0 ] . Tag , tag => ( { key : tag . Key [ 0 ] , value : tag . Value [ 0 ] } ) ) ;
39+ if ( filter . And [ 0 ] . ObjectSizeGreaterThan ?. length === 1 ) {
4440 current_rule_filter . object_size_greater_than = parseInt ( filter . And [ 0 ] . ObjectSizeGreaterThan [ 0 ] , 10 ) ;
4541 }
46- if ( filter . And [ 0 ] . ObjectSizeLessThan &&
47- filter . And [ 0 ] . ObjectSizeLessThan . length === 1 ) {
42+ if ( filter . And [ 0 ] . ObjectSizeLessThan ?. length === 1 ) {
4843 current_rule_filter . object_size_less_than = parseInt ( filter . And [ 0 ] . ObjectSizeLessThan [ 0 ] , 10 ) ;
4944 }
5045 }
@@ -54,24 +49,28 @@ function parse_filter(filter) {
5449// parse lifecycle rule expiration
5550function parse_expiration ( expiration ) {
5651 const output_expiration = { } ;
57- if ( expiration . Days && expiration . Days . length === 1 ) {
52+ if ( expiration . Days ? .length === 1 ) {
5853 output_expiration . days = parseInt ( expiration . Days [ 0 ] , 10 ) ;
5954 if ( output_expiration . days < 1 ) {
6055 dbg . error ( 'Minimum value for expiration days is 1, actual' , expiration . Days ,
6156 'converted' , output_expiration . days ) ;
6257 throw new S3Error ( S3Error . InvalidArgument ) ;
6358 }
64- } else if ( expiration . Date && expiration . Date . length === 1 ) {
59+ } else if ( expiration . Date ? .length === 1 ) {
6560 output_expiration . date = ( new Date ( expiration . Date [ 0 ] ) ) . getTime ( ) ;
66- } else if ( expiration . ExpiredObjectDeleteMarker &&
67- expiration . ExpiredObjectDeleteMarker . length === 1 &&
68- expiration . ExpiredObjectDeleteMarker [ 0 ] === 'true' ) {
69- dbg . error ( 'ExpiredObjectDeleteMarker is not implemented, expiration:' , expiration ) ;
70- throw new S3Error ( S3Error . NotImplemented ) ;
61+ } else if ( expiration . ExpiredObjectDeleteMarker ?. length === 1 ) {
62+ output_expiration . expired_object_delete_marker = true_regex . test ( expiration . ExpiredObjectDeleteMarker [ 0 ] ) ;
7163 }
7264 return output_expiration ;
7365}
7466
67+ function parse_lifecycle_field ( field , field_parser = parseInt ) {
68+ if ( field ?. length === 1 ) {
69+ return field_parser ( field [ 0 ] ) ;
70+ }
71+ return undefined ;
72+ }
73+
7574/**
7675 * http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTlifecycle.html
7776 */
@@ -81,53 +80,65 @@ async function put_bucket_lifecycle(req) {
8180 filter : { } ,
8281 } ;
8382
84- if ( rule . ID && rule . ID . length === 1 ) {
83+ if ( rule . ID ? .length === 1 ) {
8584 current_rule . id = rule . ID [ 0 ] ;
8685 } else {
8786 // Generate a random ID if missing
8887 current_rule . id = uuid ( ) ;
8988 }
9089
91- if ( ! ( rule . Status && rule . Status . length === 1 ) ) {
90+ if ( rule . Status ?. length !== 1 ) {
9291 dbg . error ( 'Rule should have status' , rule ) ;
9392 throw new S3Error ( S3Error . InvalidArgument ) ;
9493 }
9594 current_rule . status = rule . Status [ 0 ] ;
9695
9796 if ( rule . Prefix ) {
98- dbg . error ( 'Rule should not have prefix, it should be filter.prefix' , rule ) ;
99- throw new S3Error ( S3Error . InvalidArgument ) ;
100- }
97+ if ( rule . Filter ?. length === 1 ) {
98+ dbg . error ( 'Rule should not have prefix together with a filter' , rule ) ;
99+ throw new S3Error ( S3Error . InvalidArgument ) ;
100+ }
101+ current_rule . filter . prefix = rule . Prefix [ 0 ] ;
101102
102- if ( ! ( rule . Filter && rule . Filter . length === 1 ) ) {
103- dbg . error ( 'Rule should have filter' , rule ) ;
104- throw new S3Error ( S3Error . InvalidArgument ) ;
103+ } else {
104+ if ( rule . Filter ?. length !== 1 ) {
105+ dbg . error ( 'Rule should have filter' , rule ) ;
106+ throw new S3Error ( S3Error . InvalidArgument ) ;
107+ }
108+ current_rule . filter = parse_filter ( rule . Filter [ 0 ] ) ;
105109 }
106- current_rule . filter = parse_filter ( rule . Filter [ 0 ] ) ;
107110
108- // Since other actions are not implemented, Expiration
109- // is expected here
110- if ( ! ( rule . Expiration && rule . Expiration . length === 1 ) ) {
111- dbg . error ( 'Rule is expected to have expiration' , rule ) ;
112- throw new S3Error ( S3Error . NotImplemented ) ;
111+ if ( rule . Expiration ?. length === 1 ) {
112+ current_rule . expiration = parse_expiration ( rule . Expiration [ 0 ] ) ;
113113 }
114- current_rule . expiration = parse_expiration ( rule . Expiration [ 0 ] ) ;
115114
116- if ( rule . AbortIncompleteMultipartUpload ) {
117- dbg . error ( 'AbortIncompleteMultipartUpload is not implemented, rule:' , rule ) ;
118- throw new S3Error ( S3Error . NotImplemented ) ;
115+ if ( rule . AbortIncompleteMultipartUpload ?. length === 1 ) {
116+ current_rule . abort_incomplete_multipart_upload = _ . omitBy ( {
117+ days_after_initiation : parse_lifecycle_field ( rule . AbortIncompleteMultipartUpload [ 0 ] . DaysAfterInitiation ) ,
118+ } , _ . isUndefined ) ;
119119 }
120- if ( rule . Transition ) {
121- dbg . error ( 'Transition is not implemented, rule:' , rule ) ;
122- throw new S3Error ( S3Error . NotImplemented ) ;
120+
121+ if ( rule . Transition ?. length === 1 ) {
122+ current_rule . transition = _ . omitBy ( {
123+ storage_class : parse_lifecycle_field ( rule . Transition [ 0 ] . StorageClass , String ) ,
124+ date : parse_lifecycle_field ( rule . Transition [ 0 ] . Date , s => new Date ( s ) ) ,
125+ days : parse_lifecycle_field ( rule . Transition [ 0 ] . Days ) ,
126+ } , _ . isUndefined ) ;
123127 }
124- if ( rule . NoncurrentVersionExpiration ) {
125- dbg . error ( 'NoncurrentVersionExpiration is not implemented, rule:' , rule ) ;
126- throw new S3Error ( S3Error . NotImplemented ) ;
128+
129+ if ( rule . NoncurrentVersionExpiration ?. length === 1 ) {
130+ current_rule . noncurrent_version_expiration = _ . omitBy ( {
131+ noncurrent_days : parse_lifecycle_field ( rule . NoncurrentVersionExpiration [ 0 ] . NoncurrentDays ) ,
132+ newer_noncurrent_versions : parse_lifecycle_field ( rule . NoncurrentVersionExpiration [ 0 ] . NewerNoncurrentVersions ) ,
133+ } , _ . isUndefined ) ;
127134 }
128- if ( rule . NoncurrentVersionTransition ) {
129- dbg . error ( 'NoncurrentVersionTransition is not implemented, rule:' , rule ) ;
130- throw new S3Error ( S3Error . NotImplemented ) ;
135+
136+ if ( rule . NoncurrentVersionTransition ?. length === 1 ) {
137+ current_rule . noncurrent_version_transition = _ . omitBy ( {
138+ storage_class : parse_lifecycle_field ( rule . NoncurrentVersionTransition [ 0 ] . StorageClass , String ) ,
139+ noncurrent_days : parse_lifecycle_field ( rule . NoncurrentVersionTransition [ 0 ] . NoncurrentDays ) ,
140+ newer_noncurrent_versions : parse_lifecycle_field ( rule . NoncurrentVersionTransition [ 0 ] . NewerNoncurrentVersions ) ,
141+ } , _ . isUndefined ) ;
131142 }
132143
133144 return current_rule ;
0 commit comments