1use rustack_s3_model::{
9 error::S3Error,
10 input::{
11 DeleteBucketCorsInput, DeleteBucketEncryptionInput, DeleteBucketLifecycleInput,
12 DeleteBucketOwnershipControlsInput, DeleteBucketPolicyInput, DeleteBucketTaggingInput,
13 DeleteBucketWebsiteInput, DeletePublicAccessBlockInput,
14 GetBucketAccelerateConfigurationInput, GetBucketAclInput, GetBucketCorsInput,
15 GetBucketEncryptionInput, GetBucketLifecycleConfigurationInput, GetBucketLoggingInput,
16 GetBucketNotificationConfigurationInput, GetBucketOwnershipControlsInput,
17 GetBucketPolicyInput, GetBucketPolicyStatusInput, GetBucketRequestPaymentInput,
18 GetBucketTaggingInput, GetBucketVersioningInput, GetBucketWebsiteInput,
19 GetObjectLockConfigurationInput, GetPublicAccessBlockInput,
20 PutBucketAccelerateConfigurationInput, PutBucketAclInput, PutBucketCorsInput,
21 PutBucketEncryptionInput, PutBucketLifecycleConfigurationInput, PutBucketLoggingInput,
22 PutBucketNotificationConfigurationInput, PutBucketOwnershipControlsInput,
23 PutBucketPolicyInput, PutBucketRequestPaymentInput, PutBucketTaggingInput,
24 PutBucketVersioningInput, PutBucketWebsiteInput, PutObjectLockConfigurationInput,
25 PutPublicAccessBlockInput,
26 },
27 output::{
28 GetBucketAccelerateConfigurationOutput, GetBucketAclOutput, GetBucketCorsOutput,
29 GetBucketEncryptionOutput, GetBucketLifecycleConfigurationOutput, GetBucketLoggingOutput,
30 GetBucketNotificationConfigurationOutput, GetBucketOwnershipControlsOutput,
31 GetBucketPolicyOutput, GetBucketPolicyStatusOutput, GetBucketRequestPaymentOutput,
32 GetBucketTaggingOutput, GetBucketVersioningOutput, GetBucketWebsiteOutput,
33 GetObjectLockConfigurationOutput, GetPublicAccessBlockOutput,
34 PutBucketLifecycleConfigurationOutput, PutObjectLockConfigurationOutput,
35 },
36 types::{
37 BucketAccelerateStatus, BucketVersioningStatus, CORSRule,
38 DefaultRetention as ModelDefaultRetention, ErrorDocument, Grant, Grantee, IndexDocument,
39 ObjectLockConfiguration as ModelObjectLockConfiguration, ObjectLockEnabled,
40 ObjectLockRetentionMode, ObjectLockRule as ModelObjectLockRule, ObjectOwnership,
41 OwnershipControls, OwnershipControlsRule, Payer, Permission, PolicyStatus, Protocol,
42 PublicAccessBlockConfiguration, RedirectAllRequestsTo, ServerSideEncryption,
43 ServerSideEncryptionByDefault, ServerSideEncryptionConfiguration, ServerSideEncryptionRule,
44 Tag,
45 },
46};
47use tracing::debug;
48
49use super::bucket::to_model_owner;
50use crate::{
51 cors::CorsRule,
52 error::S3ServiceError,
53 provider::RustackS3,
54 state::{
55 bucket::{
56 BucketEncryption, CorsRuleConfig, ObjectLockConfiguration, ObjectLockRule,
57 OwnershipControlsConfig, PublicAccessBlockConfig, VersioningStatus, WebsiteConfig,
58 },
59 object::{CannedAcl, Owner as InternalOwner},
60 },
61};
62
63#[allow(clippy::unused_async)]
65impl RustackS3 {
66 pub async fn handle_get_bucket_versioning(
72 &self,
73 input: GetBucketVersioningInput,
74 ) -> Result<GetBucketVersioningOutput, S3Error> {
75 let bucket_name = input.bucket;
76
77 let bucket = self
78 .state
79 .get_bucket(&bucket_name)
80 .map_err(S3ServiceError::into_s3_error)?;
81
82 let status = match *bucket.versioning.read() {
83 VersioningStatus::Enabled => Some(BucketVersioningStatus::from("Enabled")),
84 VersioningStatus::Suspended => Some(BucketVersioningStatus::from("Suspended")),
85 VersioningStatus::Disabled => None,
86 };
87
88 Ok(GetBucketVersioningOutput {
89 mfa_delete: None,
90 status,
91 })
92 }
93
94 pub async fn handle_put_bucket_versioning(
96 &self,
97 input: PutBucketVersioningInput,
98 ) -> Result<(), S3Error> {
99 let bucket_name = input.bucket;
100
101 let bucket = self
102 .state
103 .get_bucket(&bucket_name)
104 .map_err(S3ServiceError::into_s3_error)?;
105
106 let config = input.versioning_configuration;
107 if let Some(status) = config.status {
108 match status.as_str() {
109 "Enabled" => bucket.enable_versioning(),
110 "Suspended" => bucket.suspend_versioning(),
111 _ => {
112 return Err(S3Error::invalid_argument("Invalid versioning status"));
113 }
114 }
115 }
116
117 debug!(bucket = %bucket_name, "put_bucket_versioning completed");
118 Ok(())
119 }
120
121 pub async fn handle_get_bucket_encryption(
127 &self,
128 input: GetBucketEncryptionInput,
129 ) -> Result<GetBucketEncryptionOutput, S3Error> {
130 let bucket_name = input.bucket;
131
132 let bucket = self
133 .state
134 .get_bucket(&bucket_name)
135 .map_err(S3ServiceError::into_s3_error)?;
136
137 let enc = bucket.encryption.read();
138 let enc_config = enc
139 .as_ref()
140 .ok_or(S3ServiceError::ServerSideEncryptionConfigurationNotFoundError)
141 .map_err(S3ServiceError::into_s3_error)?;
142
143 let rule = ServerSideEncryptionRule {
144 apply_server_side_encryption_by_default: Some(ServerSideEncryptionByDefault {
145 kms_master_key_id: enc_config.kms_master_key_id.clone(),
146 sse_algorithm: ServerSideEncryption::from(enc_config.sse_algorithm.as_str()),
147 }),
148 blocked_encryption_types: None,
149 bucket_key_enabled: Some(enc_config.bucket_key_enabled),
150 };
151
152 Ok(GetBucketEncryptionOutput {
153 server_side_encryption_configuration: Some(ServerSideEncryptionConfiguration {
154 rules: vec![rule],
155 }),
156 })
157 }
158
159 pub async fn handle_put_bucket_encryption(
161 &self,
162 input: PutBucketEncryptionInput,
163 ) -> Result<(), S3Error> {
164 let bucket_name = input.bucket;
165
166 let bucket = self
167 .state
168 .get_bucket(&bucket_name)
169 .map_err(S3ServiceError::into_s3_error)?;
170
171 let config = input.server_side_encryption_configuration;
172
173 let rule = config
174 .rules
175 .first()
176 .ok_or_else(|| S3Error::invalid_argument("At least one rule is required"))?;
177
178 let default = rule
179 .apply_server_side_encryption_by_default
180 .as_ref()
181 .ok_or_else(|| {
182 S3Error::invalid_argument("ApplyServerSideEncryptionByDefault is required")
183 })?;
184
185 let enc = BucketEncryption {
186 sse_algorithm: default.sse_algorithm.as_str().to_owned(),
187 kms_master_key_id: default.kms_master_key_id.clone(),
188 bucket_key_enabled: rule.bucket_key_enabled.unwrap_or(false),
189 };
190
191 *bucket.encryption.write() = Some(enc);
192
193 debug!(bucket = %bucket_name, "put_bucket_encryption completed");
194 Ok(())
195 }
196
197 pub async fn handle_delete_bucket_encryption(
199 &self,
200 input: DeleteBucketEncryptionInput,
201 ) -> Result<(), S3Error> {
202 let bucket_name = input.bucket;
203
204 let bucket = self
205 .state
206 .get_bucket(&bucket_name)
207 .map_err(S3ServiceError::into_s3_error)?;
208
209 *bucket.encryption.write() = None;
210
211 debug!(bucket = %bucket_name, "delete_bucket_encryption completed");
212 Ok(())
213 }
214
215 pub async fn handle_get_bucket_cors(
221 &self,
222 input: GetBucketCorsInput,
223 ) -> Result<GetBucketCorsOutput, S3Error> {
224 let bucket_name = input.bucket;
225
226 let bucket = self
227 .state
228 .get_bucket(&bucket_name)
229 .map_err(S3ServiceError::into_s3_error)?;
230
231 let cors_rules = bucket.cors_rules.read();
232 let rules = cors_rules
233 .as_ref()
234 .ok_or(S3ServiceError::NoSuchCorsConfiguration)
235 .map_err(S3ServiceError::into_s3_error)?;
236
237 let s3_rules: Vec<CORSRule> = rules.iter().map(cors_config_to_dto).collect();
238
239 Ok(GetBucketCorsOutput {
240 cors_rules: s3_rules,
241 })
242 }
243
244 pub async fn handle_put_bucket_cors(&self, input: PutBucketCorsInput) -> Result<(), S3Error> {
246 let bucket_name = input.bucket;
247
248 let bucket = self
249 .state
250 .get_bucket(&bucket_name)
251 .map_err(S3ServiceError::into_s3_error)?;
252
253 let cors_config = input.cors_configuration;
254
255 let configs: Vec<CorsRuleConfig> = cors_config
256 .cors_rules
257 .iter()
258 .map(dto_to_cors_config)
259 .collect();
260 let index_rules: Vec<CorsRule> = configs
261 .iter()
262 .map(|c| CorsRule {
263 allowed_origins: c.allowed_origins.clone(),
264 allowed_methods: c.allowed_methods.clone(),
265 allowed_headers: c.allowed_headers.clone(),
266 expose_headers: c.expose_headers.clone(),
267 max_age_seconds: c.max_age_seconds,
268 })
269 .collect();
270
271 *bucket.cors_rules.write() = Some(configs);
272 self.cors_index.set_rules(&bucket_name, index_rules);
273
274 debug!(bucket = %bucket_name, "put_bucket_cors completed");
275 Ok(())
276 }
277
278 pub async fn handle_delete_bucket_cors(
280 &self,
281 input: DeleteBucketCorsInput,
282 ) -> Result<(), S3Error> {
283 let bucket_name = input.bucket;
284
285 let bucket = self
286 .state
287 .get_bucket(&bucket_name)
288 .map_err(S3ServiceError::into_s3_error)?;
289
290 *bucket.cors_rules.write() = None;
291 self.cors_index.delete_rules(&bucket_name);
292
293 debug!(bucket = %bucket_name, "delete_bucket_cors completed");
294 Ok(())
295 }
296
297 pub async fn handle_get_bucket_lifecycle_configuration(
303 &self,
304 input: GetBucketLifecycleConfigurationInput,
305 ) -> Result<GetBucketLifecycleConfigurationOutput, S3Error> {
306 let bucket_name = input.bucket;
307
308 let bucket = self
309 .state
310 .get_bucket(&bucket_name)
311 .map_err(S3ServiceError::into_s3_error)?;
312
313 let lifecycle = bucket.lifecycle.read();
314 let config = lifecycle
315 .as_ref()
316 .ok_or(S3ServiceError::NoSuchLifecycleConfiguration)
317 .map_err(S3ServiceError::into_s3_error)?;
318
319 Ok(GetBucketLifecycleConfigurationOutput {
320 rules: config.rules.clone(),
321 transition_default_minimum_object_size: None,
322 })
323 }
324
325 pub async fn handle_put_bucket_lifecycle_configuration(
327 &self,
328 input: PutBucketLifecycleConfigurationInput,
329 ) -> Result<PutBucketLifecycleConfigurationOutput, S3Error> {
330 let bucket_name = input.bucket;
331
332 let bucket = self
333 .state
334 .get_bucket(&bucket_name)
335 .map_err(S3ServiceError::into_s3_error)?;
336
337 *bucket.lifecycle.write() = input.lifecycle_configuration;
338
339 debug!(bucket = %bucket_name, "put_bucket_lifecycle_configuration completed");
340 Ok(PutBucketLifecycleConfigurationOutput {
341 transition_default_minimum_object_size: None,
342 })
343 }
344
345 pub async fn handle_delete_bucket_lifecycle(
347 &self,
348 input: DeleteBucketLifecycleInput,
349 ) -> Result<(), S3Error> {
350 let bucket_name = input.bucket;
351
352 let bucket = self
353 .state
354 .get_bucket(&bucket_name)
355 .map_err(S3ServiceError::into_s3_error)?;
356
357 *bucket.lifecycle.write() = None;
358
359 debug!(bucket = %bucket_name, "delete_bucket_lifecycle completed");
360 Ok(())
361 }
362
363 pub async fn handle_get_bucket_policy(
369 &self,
370 input: GetBucketPolicyInput,
371 ) -> Result<GetBucketPolicyOutput, S3Error> {
372 let bucket_name = input.bucket;
373
374 let bucket = self
375 .state
376 .get_bucket(&bucket_name)
377 .map_err(S3ServiceError::into_s3_error)?;
378
379 let policy = bucket.policy.read();
380 let policy_str = policy
381 .as_ref()
382 .ok_or(S3ServiceError::NoSuchBucketPolicy)
383 .map_err(S3ServiceError::into_s3_error)?
384 .clone();
385
386 Ok(GetBucketPolicyOutput {
387 policy: Some(policy_str),
388 })
389 }
390
391 pub async fn handle_put_bucket_policy(
393 &self,
394 input: PutBucketPolicyInput,
395 ) -> Result<(), S3Error> {
396 let bucket_name = input.bucket;
397
398 let bucket = self
399 .state
400 .get_bucket(&bucket_name)
401 .map_err(S3ServiceError::into_s3_error)?;
402
403 *bucket.policy.write() = Some(input.policy);
404
405 debug!(bucket = %bucket_name, "put_bucket_policy completed");
406 Ok(())
407 }
408
409 pub async fn handle_delete_bucket_policy(
411 &self,
412 input: DeleteBucketPolicyInput,
413 ) -> Result<(), S3Error> {
414 let bucket_name = input.bucket;
415
416 let bucket = self
417 .state
418 .get_bucket(&bucket_name)
419 .map_err(S3ServiceError::into_s3_error)?;
420
421 *bucket.policy.write() = None;
422
423 debug!(bucket = %bucket_name, "delete_bucket_policy completed");
424 Ok(())
425 }
426
427 pub async fn handle_get_bucket_tagging(
433 &self,
434 input: GetBucketTaggingInput,
435 ) -> Result<GetBucketTaggingOutput, S3Error> {
436 let bucket_name = input.bucket;
437
438 let bucket = self
439 .state
440 .get_bucket(&bucket_name)
441 .map_err(S3ServiceError::into_s3_error)?;
442
443 let tags = bucket.tags.read();
444 if tags.is_empty() {
445 return Err(S3ServiceError::NoSuchTagSet.into_s3_error());
446 }
447
448 let tag_set: Vec<Tag> = tags
449 .iter()
450 .map(|(k, v)| Tag {
451 key: k.clone(),
452 value: v.clone(),
453 })
454 .collect();
455
456 Ok(GetBucketTaggingOutput { tag_set })
457 }
458
459 pub async fn handle_put_bucket_tagging(
461 &self,
462 input: PutBucketTaggingInput,
463 ) -> Result<(), S3Error> {
464 let bucket_name = input.bucket;
465
466 let bucket = self
467 .state
468 .get_bucket(&bucket_name)
469 .map_err(S3ServiceError::into_s3_error)?;
470
471 let tagging = input.tagging;
472
473 let tags: Vec<(String, String)> = tagging
474 .tag_set
475 .into_iter()
476 .map(|t| (t.key, t.value))
477 .collect();
478
479 crate::validation::validate_tags(&tags).map_err(S3ServiceError::into_s3_error)?;
480
481 *bucket.tags.write() = tags;
482
483 debug!(bucket = %bucket_name, "put_bucket_tagging completed");
484 Ok(())
485 }
486
487 pub async fn handle_delete_bucket_tagging(
489 &self,
490 input: DeleteBucketTaggingInput,
491 ) -> Result<(), S3Error> {
492 let bucket_name = input.bucket;
493
494 let bucket = self
495 .state
496 .get_bucket(&bucket_name)
497 .map_err(S3ServiceError::into_s3_error)?;
498
499 *bucket.tags.write() = Vec::new();
500
501 debug!(bucket = %bucket_name, "delete_bucket_tagging completed");
502 Ok(())
503 }
504
505 pub async fn handle_get_bucket_notification_configuration(
511 &self,
512 input: GetBucketNotificationConfigurationInput,
513 ) -> Result<GetBucketNotificationConfigurationOutput, S3Error> {
514 let bucket_name = input.bucket;
515
516 let bucket = self
517 .state
518 .get_bucket(&bucket_name)
519 .map_err(S3ServiceError::into_s3_error)?;
520
521 let notification_configuration = bucket.notification_configuration.read().clone();
522
523 Ok(GetBucketNotificationConfigurationOutput {
524 notification_configuration,
525 })
526 }
527
528 pub async fn handle_put_bucket_notification_configuration(
530 &self,
531 input: PutBucketNotificationConfigurationInput,
532 ) -> Result<(), S3Error> {
533 let bucket_name = input.bucket;
534
535 let bucket = self
536 .state
537 .get_bucket(&bucket_name)
538 .map_err(S3ServiceError::into_s3_error)?;
539
540 *bucket.notification_configuration.write() = Some(input.notification_configuration);
541
542 debug!(bucket = %bucket_name, "put_bucket_notification_configuration completed");
543 Ok(())
544 }
545
546 pub async fn handle_get_bucket_logging(
552 &self,
553 input: GetBucketLoggingInput,
554 ) -> Result<GetBucketLoggingOutput, S3Error> {
555 let bucket_name = input.bucket;
556
557 let _bucket = self
558 .state
559 .get_bucket(&bucket_name)
560 .map_err(S3ServiceError::into_s3_error)?;
561
562 Ok(GetBucketLoggingOutput {
563 logging_enabled: None,
564 })
565 }
566
567 pub async fn handle_put_bucket_logging(
569 &self,
570 input: PutBucketLoggingInput,
571 ) -> Result<(), S3Error> {
572 let bucket_name = input.bucket;
573
574 let bucket = self
575 .state
576 .get_bucket(&bucket_name)
577 .map_err(S3ServiceError::into_s3_error)?;
578
579 *bucket.logging.write() = Some(serde_json::json!({"status": "configured"}));
580
581 debug!(bucket = %bucket_name, "put_bucket_logging completed");
582 Ok(())
583 }
584
585 pub async fn handle_get_public_access_block(
591 &self,
592 input: GetPublicAccessBlockInput,
593 ) -> Result<GetPublicAccessBlockOutput, S3Error> {
594 let bucket_name = input.bucket;
595
596 let bucket = self
597 .state
598 .get_bucket(&bucket_name)
599 .map_err(S3ServiceError::into_s3_error)?;
600
601 let pab = bucket.public_access_block.read();
602 let config = pab
603 .as_ref()
604 .ok_or(S3ServiceError::NoSuchPublicAccessBlockConfiguration)
605 .map_err(S3ServiceError::into_s3_error)?;
606
607 Ok(GetPublicAccessBlockOutput {
608 public_access_block_configuration: Some(PublicAccessBlockConfiguration {
609 block_public_acls: Some(config.block_public_acls),
610 block_public_policy: Some(config.block_public_policy),
611 ignore_public_acls: Some(config.ignore_public_acls),
612 restrict_public_buckets: Some(config.restrict_public_buckets),
613 }),
614 })
615 }
616
617 pub async fn handle_put_public_access_block(
619 &self,
620 input: PutPublicAccessBlockInput,
621 ) -> Result<(), S3Error> {
622 let bucket_name = input.bucket;
623
624 let bucket = self
625 .state
626 .get_bucket(&bucket_name)
627 .map_err(S3ServiceError::into_s3_error)?;
628
629 let config = input.public_access_block_configuration;
630
631 let internal_config = PublicAccessBlockConfig {
632 block_public_acls: config.block_public_acls.unwrap_or(false),
633 ignore_public_acls: config.ignore_public_acls.unwrap_or(false),
634 block_public_policy: config.block_public_policy.unwrap_or(false),
635 restrict_public_buckets: config.restrict_public_buckets.unwrap_or(false),
636 };
637
638 *bucket.public_access_block.write() = Some(internal_config);
639
640 debug!(bucket = %bucket_name, "put_public_access_block completed");
641 Ok(())
642 }
643
644 pub async fn handle_delete_public_access_block(
646 &self,
647 input: DeletePublicAccessBlockInput,
648 ) -> Result<(), S3Error> {
649 let bucket_name = input.bucket;
650
651 let bucket = self
652 .state
653 .get_bucket(&bucket_name)
654 .map_err(S3ServiceError::into_s3_error)?;
655
656 *bucket.public_access_block.write() = None;
657
658 debug!(bucket = %bucket_name, "delete_public_access_block completed");
659 Ok(())
660 }
661
662 pub async fn handle_get_bucket_ownership_controls(
668 &self,
669 input: GetBucketOwnershipControlsInput,
670 ) -> Result<GetBucketOwnershipControlsOutput, S3Error> {
671 let bucket_name = input.bucket;
672
673 let bucket = self
674 .state
675 .get_bucket(&bucket_name)
676 .map_err(S3ServiceError::into_s3_error)?;
677
678 let controls = bucket.ownership_controls.read();
679 let config = controls
680 .as_ref()
681 .ok_or(S3ServiceError::OwnershipControlsNotFoundError)
682 .map_err(S3ServiceError::into_s3_error)?;
683
684 let rule = OwnershipControlsRule {
685 object_ownership: ObjectOwnership::from(config.object_ownership.as_str()),
686 };
687
688 Ok(GetBucketOwnershipControlsOutput {
689 ownership_controls: Some(OwnershipControls { rules: vec![rule] }),
690 })
691 }
692
693 pub async fn handle_put_bucket_ownership_controls(
695 &self,
696 input: PutBucketOwnershipControlsInput,
697 ) -> Result<(), S3Error> {
698 let bucket_name = input.bucket;
699
700 let bucket = self
701 .state
702 .get_bucket(&bucket_name)
703 .map_err(S3ServiceError::into_s3_error)?;
704
705 let controls = input.ownership_controls;
706
707 let rule = controls
708 .rules
709 .first()
710 .ok_or_else(|| S3Error::invalid_argument("At least one rule is required"))?;
711
712 let ownership = rule.object_ownership.as_str().to_owned();
713
714 *bucket.ownership_controls.write() = Some(OwnershipControlsConfig {
715 object_ownership: ownership,
716 });
717
718 debug!(bucket = %bucket_name, "put_bucket_ownership_controls completed");
719 Ok(())
720 }
721
722 pub async fn handle_delete_bucket_ownership_controls(
724 &self,
725 input: DeleteBucketOwnershipControlsInput,
726 ) -> Result<(), S3Error> {
727 let bucket_name = input.bucket;
728
729 let bucket = self
730 .state
731 .get_bucket(&bucket_name)
732 .map_err(S3ServiceError::into_s3_error)?;
733
734 *bucket.ownership_controls.write() = None;
735
736 debug!(bucket = %bucket_name, "delete_bucket_ownership_controls completed");
737 Ok(())
738 }
739
740 pub async fn handle_get_object_lock_configuration(
746 &self,
747 input: GetObjectLockConfigurationInput,
748 ) -> Result<GetObjectLockConfigurationOutput, S3Error> {
749 let bucket_name = input.bucket;
750
751 let bucket = self
752 .state
753 .get_bucket(&bucket_name)
754 .map_err(S3ServiceError::into_s3_error)?;
755
756 if !*bucket.object_lock_enabled.read() {
757 return Err(S3ServiceError::ObjectLockConfigurationNotFoundError.into_s3_error());
758 }
759
760 let lock_config = bucket.object_lock_configuration.read();
761 let rule = lock_config.as_ref().and_then(|c| {
762 c.rule.as_ref().map(|r| ModelObjectLockRule {
763 default_retention: r
764 .default_retention
765 .as_ref()
766 .map(|dr| ModelDefaultRetention {
767 days: dr.days,
768 mode: Some(ObjectLockRetentionMode::from(dr.mode.as_str())),
769 years: dr.years,
770 }),
771 })
772 });
773
774 Ok(GetObjectLockConfigurationOutput {
775 object_lock_configuration: Some(ModelObjectLockConfiguration {
776 object_lock_enabled: Some(ObjectLockEnabled::from("Enabled")),
777 rule,
778 }),
779 })
780 }
781
782 pub async fn handle_put_object_lock_configuration(
784 &self,
785 input: PutObjectLockConfigurationInput,
786 ) -> Result<PutObjectLockConfigurationOutput, S3Error> {
787 let bucket_name = input.bucket;
788
789 let bucket = self
790 .state
791 .get_bucket(&bucket_name)
792 .map_err(S3ServiceError::into_s3_error)?;
793
794 if let Some(config) = input.object_lock_configuration {
795 *bucket.object_lock_enabled.write() = true;
796 bucket.enable_versioning();
797
798 let internal_config = ObjectLockConfiguration {
799 object_lock_enabled: config
800 .object_lock_enabled
801 .as_ref()
802 .map_or_else(|| "Enabled".to_owned(), |e| e.as_str().to_owned()),
803 rule: config.rule.map(|r| ObjectLockRule {
804 default_retention: r.default_retention.map(|dr| {
805 crate::state::bucket::DefaultRetention {
806 mode: dr
807 .mode
808 .as_ref()
809 .map(|m| m.as_str().to_owned())
810 .unwrap_or_default(),
811 days: dr.days,
812 years: dr.years,
813 }
814 }),
815 }),
816 };
817 *bucket.object_lock_configuration.write() = Some(internal_config);
818 }
819
820 debug!(bucket = %bucket_name, "put_object_lock_configuration completed");
821 Ok(PutObjectLockConfigurationOutput {
822 request_charged: None,
823 })
824 }
825
826 pub async fn handle_get_bucket_accelerate_configuration(
832 &self,
833 input: GetBucketAccelerateConfigurationInput,
834 ) -> Result<GetBucketAccelerateConfigurationOutput, S3Error> {
835 let bucket_name = input.bucket;
836
837 let bucket = self
838 .state
839 .get_bucket(&bucket_name)
840 .map_err(S3ServiceError::into_s3_error)?;
841
842 let status = bucket
843 .accelerate
844 .read()
845 .as_ref()
846 .map(|s| BucketAccelerateStatus::from(s.as_str()));
847
848 Ok(GetBucketAccelerateConfigurationOutput {
849 request_charged: None,
850 status,
851 })
852 }
853
854 pub async fn handle_put_bucket_accelerate_configuration(
856 &self,
857 input: PutBucketAccelerateConfigurationInput,
858 ) -> Result<(), S3Error> {
859 let bucket_name = input.bucket;
860
861 let bucket = self
862 .state
863 .get_bucket(&bucket_name)
864 .map_err(S3ServiceError::into_s3_error)?;
865
866 let config = input.accelerate_configuration;
867 let status = config.status.map(|s| s.as_str().to_owned());
868 *bucket.accelerate.write() = status;
869
870 debug!(bucket = %bucket_name, "put_bucket_accelerate_configuration completed");
871 Ok(())
872 }
873
874 pub async fn handle_get_bucket_request_payment(
880 &self,
881 input: GetBucketRequestPaymentInput,
882 ) -> Result<GetBucketRequestPaymentOutput, S3Error> {
883 let bucket_name = input.bucket;
884
885 let bucket = self
886 .state
887 .get_bucket(&bucket_name)
888 .map_err(S3ServiceError::into_s3_error)?;
889
890 let payer = bucket.request_payment.read().clone();
891
892 Ok(GetBucketRequestPaymentOutput {
893 payer: Some(Payer::from(payer.as_str())),
894 })
895 }
896
897 pub async fn handle_put_bucket_request_payment(
899 &self,
900 input: PutBucketRequestPaymentInput,
901 ) -> Result<(), S3Error> {
902 let bucket_name = input.bucket;
903
904 let bucket = self
905 .state
906 .get_bucket(&bucket_name)
907 .map_err(S3ServiceError::into_s3_error)?;
908
909 let config = input.request_payment_configuration;
910 config
911 .payer
912 .as_str()
913 .clone_into(&mut bucket.request_payment.write());
914
915 debug!(bucket = %bucket_name, "put_bucket_request_payment completed");
916 Ok(())
917 }
918
919 pub async fn handle_get_bucket_website(
925 &self,
926 input: GetBucketWebsiteInput,
927 ) -> Result<GetBucketWebsiteOutput, S3Error> {
928 let bucket_name = input.bucket;
929
930 let bucket = self
931 .state
932 .get_bucket(&bucket_name)
933 .map_err(S3ServiceError::into_s3_error)?;
934
935 let guard = bucket.website.read();
936 let config = guard
937 .as_ref()
938 .ok_or_else(|| S3ServiceError::NoSuchWebsiteConfiguration.into_s3_error())?;
939
940 Ok(GetBucketWebsiteOutput {
941 index_document: config
942 .index_document_suffix
943 .as_ref()
944 .map(|s| IndexDocument { suffix: s.clone() }),
945 error_document: config
946 .error_document_key
947 .as_ref()
948 .map(|k| ErrorDocument { key: k.clone() }),
949 redirect_all_requests_to: config.redirect_all_requests_to_host.as_ref().map(|host| {
950 RedirectAllRequestsTo {
951 host_name: host.clone(),
952 protocol: config.redirect_all_requests_to_protocol.as_ref().map(|p| {
953 match p.as_str() {
954 "https" => Protocol::Https,
955 _ => Protocol::Http,
956 }
957 }),
958 }
959 }),
960 routing_rules: Vec::new(),
961 })
962 }
963
964 pub async fn handle_put_bucket_website(
966 &self,
967 input: PutBucketWebsiteInput,
968 ) -> Result<(), S3Error> {
969 let bucket_name = input.bucket;
970
971 let bucket = self
972 .state
973 .get_bucket(&bucket_name)
974 .map_err(S3ServiceError::into_s3_error)?;
975
976 let wc = &input.website_configuration;
977 *bucket.website.write() = Some(WebsiteConfig {
978 index_document_suffix: wc.index_document.as_ref().map(|d| d.suffix.clone()),
979 error_document_key: wc.error_document.as_ref().map(|d| d.key.clone()),
980 redirect_all_requests_to_host: wc
981 .redirect_all_requests_to
982 .as_ref()
983 .map(|r| r.host_name.clone()),
984 redirect_all_requests_to_protocol: wc
985 .redirect_all_requests_to
986 .as_ref()
987 .and_then(|r| r.protocol.as_ref().map(|p| p.as_str().to_owned())),
988 });
989
990 debug!(bucket = %bucket_name, "put_bucket_website completed");
991 Ok(())
992 }
993
994 pub async fn handle_delete_bucket_website(
996 &self,
997 input: DeleteBucketWebsiteInput,
998 ) -> Result<(), S3Error> {
999 let bucket_name = input.bucket;
1000
1001 let bucket = self
1002 .state
1003 .get_bucket(&bucket_name)
1004 .map_err(S3ServiceError::into_s3_error)?;
1005
1006 *bucket.website.write() = None;
1007
1008 debug!(bucket = %bucket_name, "delete_bucket_website completed");
1009 Ok(())
1010 }
1011
1012 pub async fn handle_get_bucket_acl(
1018 &self,
1019 input: GetBucketAclInput,
1020 ) -> Result<GetBucketAclOutput, S3Error> {
1021 let bucket_name = input.bucket;
1022
1023 let bucket = self
1024 .state
1025 .get_bucket(&bucket_name)
1026 .map_err(S3ServiceError::into_s3_error)?;
1027
1028 let owner = to_model_owner(&bucket.owner);
1029 let acl = *bucket.acl.read();
1030 let grants = canned_acl_to_grants(&bucket.owner, acl);
1031
1032 Ok(GetBucketAclOutput {
1033 grants,
1034 owner: Some(owner),
1035 })
1036 }
1037
1038 pub async fn handle_put_bucket_acl(&self, input: PutBucketAclInput) -> Result<(), S3Error> {
1040 let bucket_name = input.bucket;
1041
1042 let bucket = self
1043 .state
1044 .get_bucket(&bucket_name)
1045 .map_err(S3ServiceError::into_s3_error)?;
1046
1047 if let Some(acl_val) = input.acl {
1048 let acl: CannedAcl = acl_val
1049 .as_str()
1050 .parse()
1051 .map_err(|_| S3Error::invalid_argument("Invalid canned ACL"))?;
1052 *bucket.acl.write() = acl;
1053 }
1054
1055 debug!(bucket = %bucket_name, "put_bucket_acl completed");
1056 Ok(())
1057 }
1058
1059 pub async fn handle_get_bucket_policy_status(
1065 &self,
1066 input: GetBucketPolicyStatusInput,
1067 ) -> Result<GetBucketPolicyStatusOutput, S3Error> {
1068 let bucket_name = input.bucket;
1069
1070 let _bucket = self
1071 .state
1072 .get_bucket(&bucket_name)
1073 .map_err(S3ServiceError::into_s3_error)?;
1074
1075 Ok(GetBucketPolicyStatusOutput {
1076 policy_status: Some(PolicyStatus {
1077 is_public: Some(false),
1078 }),
1079 })
1080 }
1081}
1082
1083fn cors_config_to_dto(config: &CorsRuleConfig) -> CORSRule {
1089 CORSRule {
1090 allowed_headers: config.allowed_headers.clone(),
1091 allowed_methods: config.allowed_methods.clone(),
1092 allowed_origins: config.allowed_origins.clone(),
1093 expose_headers: config.expose_headers.clone(),
1094 id: config.id.clone(),
1095 max_age_seconds: config.max_age_seconds,
1096 }
1097}
1098
1099fn dto_to_cors_config(rule: &CORSRule) -> CorsRuleConfig {
1101 CorsRuleConfig {
1102 id: rule.id.clone(),
1103 allowed_origins: rule.allowed_origins.clone(),
1104 allowed_methods: rule.allowed_methods.clone(),
1105 allowed_headers: rule.allowed_headers.clone(),
1106 expose_headers: rule.expose_headers.clone(),
1107 max_age_seconds: rule.max_age_seconds,
1108 }
1109}
1110
1111fn canned_acl_to_grants(owner: &InternalOwner, acl: CannedAcl) -> Vec<Grant> {
1113 let owner_grant = Grant {
1114 grantee: Some(Grantee {
1115 display_name: Some(owner.display_name.clone()),
1116 email_address: None,
1117 id: Some(owner.id.clone()),
1118 r#type: rustack_s3_model::types::Type::from("CanonicalUser"),
1119 uri: None,
1120 }),
1121 permission: Some(Permission::from("FULL_CONTROL")),
1122 };
1123
1124 match acl {
1125 CannedAcl::PublicRead => {
1126 let public_read = Grant {
1127 grantee: Some(Grantee {
1128 display_name: None,
1129 email_address: None,
1130 id: None,
1131 r#type: rustack_s3_model::types::Type::from("Group"),
1132 uri: Some("http://acs.amazonaws.com/groups/global/AllUsers".to_owned()),
1133 }),
1134 permission: Some(Permission::from("READ")),
1135 };
1136 vec![owner_grant, public_read]
1137 }
1138 _ => vec![owner_grant],
1139 }
1140}