@@ -6,22 +6,22 @@ const { v4: uuid } = require('uuid');
6
6
const dbg = require ( '../../../util/debug_module' ) ( __filename ) ;
7
7
const S3Error = require ( '../s3_errors' ) . S3Error ;
8
8
9
+ const true_regex = / t r u e / i;
10
+
9
11
// parse lifecycle rule filter
10
12
function parse_filter ( filter ) {
11
13
const current_rule_filter = { } ;
12
- if ( filter . Tag && filter . Tag . length === 1 ) {
14
+ if ( filter . Tag ? .length === 1 ) {
13
15
const tag = filter . Tag [ 0 ] ;
14
16
current_rule_filter . tags = [ { key : tag . Key [ 0 ] , value : tag . Value [ 0 ] } ] ;
15
17
}
16
- if ( filter . Prefix && filter . Prefix . length === 1 ) {
18
+ if ( filter . Prefix ? .length === 1 ) {
17
19
current_rule_filter . prefix = filter . Prefix [ 0 ] ;
18
20
}
19
- if ( filter . ObjectSizeGreaterThan &&
20
- filter . ObjectSizeGreaterThan . length === 1 ) {
21
+ if ( filter . ObjectSizeGreaterThan ?. length === 1 ) {
21
22
current_rule_filter . object_size_greater_than = parseInt ( filter . ObjectSizeGreaterThan [ 0 ] , 10 ) ;
22
23
}
23
- if ( filter . ObjectSizeLessThan &&
24
- filter . ObjectSizeLessThan . length === 1 ) {
24
+ if ( filter . ObjectSizeLessThan ?. length === 1 ) {
25
25
current_rule_filter . object_size_less_than = parseInt ( filter . ObjectSizeLessThan [ 0 ] , 10 ) ;
26
26
}
27
27
if ( current_rule_filter . object_size_greater_than !== undefined &&
@@ -30,21 +30,16 @@ function parse_filter(filter) {
30
30
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 ) ;
31
31
throw new S3Error ( S3Error . InvalidArgument ) ;
32
32
}
33
- if ( filter . And &&
34
- filter . And . length === 1 ) {
35
-
33
+ if ( filter . And ?. length === 1 ) {
36
34
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 ] ;
40
37
}
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 ) {
44
40
current_rule_filter . object_size_greater_than = parseInt ( filter . And [ 0 ] . ObjectSizeGreaterThan [ 0 ] , 10 ) ;
45
41
}
46
- if ( filter . And [ 0 ] . ObjectSizeLessThan &&
47
- filter . And [ 0 ] . ObjectSizeLessThan . length === 1 ) {
42
+ if ( filter . And [ 0 ] . ObjectSizeLessThan ?. length === 1 ) {
48
43
current_rule_filter . object_size_less_than = parseInt ( filter . And [ 0 ] . ObjectSizeLessThan [ 0 ] , 10 ) ;
49
44
}
50
45
}
@@ -54,24 +49,28 @@ function parse_filter(filter) {
54
49
// parse lifecycle rule expiration
55
50
function parse_expiration ( expiration ) {
56
51
const output_expiration = { } ;
57
- if ( expiration . Days && expiration . Days . length === 1 ) {
52
+ if ( expiration . Days ? .length === 1 ) {
58
53
output_expiration . days = parseInt ( expiration . Days [ 0 ] , 10 ) ;
59
54
if ( output_expiration . days < 1 ) {
60
55
dbg . error ( 'Minimum value for expiration days is 1, actual' , expiration . Days ,
61
56
'converted' , output_expiration . days ) ;
62
57
throw new S3Error ( S3Error . InvalidArgument ) ;
63
58
}
64
- } else if ( expiration . Date && expiration . Date . length === 1 ) {
59
+ } else if ( expiration . Date ? .length === 1 ) {
65
60
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 ] ) ;
71
63
}
72
64
return output_expiration ;
73
65
}
74
66
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
+
75
74
/**
76
75
* http://docs.aws.amazon.com/AmazonS3/latest/API/RESTBucketPUTlifecycle.html
77
76
*/
@@ -81,53 +80,65 @@ async function put_bucket_lifecycle(req) {
81
80
filter : { } ,
82
81
} ;
83
82
84
- if ( rule . ID && rule . ID . length === 1 ) {
83
+ if ( rule . ID ? .length === 1 ) {
85
84
current_rule . id = rule . ID [ 0 ] ;
86
85
} else {
87
86
// Generate a random ID if missing
88
87
current_rule . id = uuid ( ) ;
89
88
}
90
89
91
- if ( ! ( rule . Status && rule . Status . length === 1 ) ) {
90
+ if ( rule . Status ?. length !== 1 ) {
92
91
dbg . error ( 'Rule should have status' , rule ) ;
93
92
throw new S3Error ( S3Error . InvalidArgument ) ;
94
93
}
95
94
current_rule . status = rule . Status [ 0 ] ;
96
95
97
96
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 ] ;
101
102
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 ] ) ;
105
109
}
106
- current_rule . filter = parse_filter ( rule . Filter [ 0 ] ) ;
107
110
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 ] ) ;
113
113
}
114
- current_rule . expiration = parse_expiration ( rule . Expiration [ 0 ] ) ;
115
114
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 ) ;
119
119
}
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 ) ;
123
127
}
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 ) ;
127
134
}
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 ) ;
131
142
}
132
143
133
144
return current_rule ;
0 commit comments