diff --git a/rustfs/src/app/bucket_usecase.rs b/rustfs/src/app/bucket_usecase.rs index ab90badca..7d92ade6f 100644 --- a/rustfs/src/app/bucket_usecase.rs +++ b/rustfs/src/app/bucket_usecase.rs @@ -23,7 +23,6 @@ use crate::error::ApiError; use crate::server::RemoteAddr; use crate::storage::access::{ReqInfo, authorize_request, req_info_ref}; use crate::storage::helper::{OperationHelper, spawn_background_with_context}; -use crate::storage::s3_api::acl; use crate::storage::s3_api::bucket::{ ListObjectVersionsParams, ListObjectsV2Params, build_list_buckets_output, build_list_object_versions_output, build_list_objects_output, build_list_objects_v2_output, parse_list_object_versions_params, parse_list_objects_v2_params, @@ -574,32 +573,6 @@ impl DefaultBucketUsecase { result } - pub async fn execute_put_bucket_acl(&self, req: S3Request) -> S3Result> { - let PutBucketAclInput { - bucket, - access_control_policy, - .. - } = req.input; - - let Some(store) = new_object_layer_fn() else { - return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string())); - }; - - store - .get_bucket_info(&bucket, &BucketOptions::default()) - .await - .map_err(ApiError::from)?; - - if access_control_policy.is_some() { - return Err(s3_error!( - NotImplemented, - "ACL XML grants are not supported; use canned ACL headers or omit ACL" - )); - } - - Ok(S3Response::new(PutBucketAclOutput::default())) - } - #[instrument(level = "debug", skip(self, req))] pub async fn execute_delete_bucket(&self, mut req: S3Request) -> S3Result> { let helper = OperationHelper::new(&req, EventName::BucketRemoved, S3Operation::DeleteBucket); @@ -655,21 +628,6 @@ impl DefaultBucketUsecase { Ok(S3Response::new(HeadBucketOutput::default())) } - pub async fn execute_get_bucket_acl(&self, req: S3Request) -> S3Result> { - let GetBucketAclInput { bucket, .. } = req.input; - - let Some(store) = new_object_layer_fn() else { - return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string())); - }; - - store - .get_bucket_info(&bucket, &BucketOptions::default()) - .await - .map_err(ApiError::from)?; - - Ok(S3Response::new(acl::build_get_bucket_acl_output())) - } - #[instrument(level = "debug", skip(self, req))] pub async fn execute_get_bucket_location( &self, @@ -2050,20 +2008,6 @@ mod tests { assert_eq!(err.code(), &S3ErrorCode::InternalError); } - #[tokio::test] - async fn execute_get_bucket_acl_returns_internal_error_when_store_uninitialized() { - let input = GetBucketAclInput::builder() - .bucket("test-bucket".to_string()) - .build() - .unwrap(); - - let req = build_request(input, Method::GET); - let usecase = DefaultBucketUsecase::without_context(); - - let err = usecase.execute_get_bucket_acl(req).await.unwrap_err(); - assert_eq!(err.code(), &S3ErrorCode::InternalError); - } - #[tokio::test] async fn execute_get_bucket_location_returns_internal_error_when_store_uninitialized() { let input = GetBucketLocationInput::builder() @@ -2733,20 +2677,6 @@ mod tests { assert_eq!(err.code(), &S3ErrorCode::InternalError); } - #[tokio::test] - async fn execute_put_bucket_acl_returns_internal_error_when_store_uninitialized() { - let input = PutBucketAclInput::builder() - .bucket("test-bucket".to_string()) - .build() - .unwrap(); - - let req = build_request(input, Method::PUT); - let usecase = DefaultBucketUsecase::without_context(); - - let err = usecase.execute_put_bucket_acl(req).await.unwrap_err(); - assert_eq!(err.code(), &S3ErrorCode::InternalError); - } - #[tokio::test] async fn execute_put_bucket_encryption_returns_internal_error_when_store_uninitialized() { let input = PutBucketEncryptionInput::builder() diff --git a/rustfs/src/app/object_usecase.rs b/rustfs/src/app/object_usecase.rs index 0dcc2079b..208f43b28 100644 --- a/rustfs/src/app/object_usecase.rs +++ b/rustfs/src/app/object_usecase.rs @@ -674,42 +674,6 @@ impl DefaultObjectUsecase { result } - pub async fn execute_put_object_acl(&self, req: S3Request) -> S3Result> { - let mut helper = OperationHelper::new(&req, EventName::ObjectAclPut, S3Operation::PutObjectAcl); - let PutObjectAclInput { - bucket, - key, - access_control_policy, - version_id, - .. - } = req.input.clone(); - - let Some(store) = new_object_layer_fn() else { - return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string())); - }; - - let opts: ObjectOptions = get_opts(&bucket, &key, version_id.clone(), None, &req.headers) - .await - .map_err(ApiError::from)?; - let object_info = store.get_object_info(&bucket, &key, &opts).await.map_err(ApiError::from)?; - - if access_control_policy.is_some() { - return Err(s3_error!( - NotImplemented, - "ACL XML grants are not supported; use canned ACL headers or omit ACL" - )); - } - - let event_version_id = version_id - .or_else(|| object_info.version_id.map(|version_id| version_id.to_string())) - .unwrap_or_default(); - helper = helper.object(object_info).version_id(event_version_id); - - let result = Ok(S3Response::new(PutObjectAclOutput::default())); - let _ = helper.complete(&result); - result - } - #[instrument( level = "debug", skip(self, req), @@ -2666,21 +2630,6 @@ mod tests { assert!(build_put_object_expiration_header(&event).is_none()); } - #[tokio::test] - async fn execute_put_object_acl_returns_internal_error_when_store_uninitialized() { - let input = PutObjectAclInput::builder() - .bucket("test-bucket".to_string()) - .key("test-key".to_string()) - .build() - .unwrap(); - - let req = build_request(input, Method::PUT); - let usecase = DefaultObjectUsecase::without_context(); - - let err = usecase.execute_put_object_acl(req).await.unwrap_err(); - assert_eq!(err.code(), &S3ErrorCode::InternalError); - } - #[tokio::test] async fn execute_head_object_rejects_range_with_part_number() { let input = HeadObjectInput::builder() diff --git a/rustfs/src/storage/ecfs.rs b/rustfs/src/storage/ecfs.rs index 9b7a7875e..f6dc2b60d 100644 --- a/rustfs/src/storage/ecfs.rs +++ b/rustfs/src/storage/ecfs.rs @@ -426,8 +426,18 @@ impl S3 for FS { async fn get_bucket_acl(&self, req: S3Request) -> S3Result> { record_s3_op(S3Operation::GetBucketAcl, &req.input.bucket); - let usecase = DefaultBucketUsecase::from_global(); - usecase.execute_get_bucket_acl(req).await + let GetBucketAclInput { bucket, .. } = req.input; + + let Some(store) = new_object_layer_fn() else { + return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string())); + }; + + store + .get_bucket_info(&bucket, &BucketOptions::default()) + .await + .map_err(ApiError::from)?; + + Ok(S3Response::new(acl::build_get_bucket_acl_output())) } async fn get_bucket_accelerate_configuration( @@ -897,8 +907,30 @@ impl S3 for FS { } async fn put_bucket_acl(&self, req: S3Request) -> S3Result> { - let usecase = DefaultBucketUsecase::from_global(); - usecase.execute_put_bucket_acl(req).await + let PutBucketAclInput { + bucket, + access_control_policy, + .. + } = req.input; + record_s3_op(S3Operation::PutBucketAcl, &bucket); + + let Some(store) = new_object_layer_fn() else { + return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string())); + }; + + store + .get_bucket_info(&bucket, &BucketOptions::default()) + .await + .map_err(ApiError::from)?; + + if access_control_policy.is_some() { + return Err(s3_error!( + NotImplemented, + "ACL XML grants are not supported; use canned ACL headers or omit ACL" + )); + } + + Ok(S3Response::new(PutBucketAclOutput::default())) } async fn put_bucket_accelerate_configuration( @@ -1075,8 +1107,35 @@ impl S3 for FS { async fn put_object_acl(&self, req: S3Request) -> S3Result> { record_s3_op(S3Operation::PutObjectAcl, &req.input.bucket); - let usecase = DefaultObjectUsecase::from_global(); - usecase.execute_put_object_acl(req).await + let mut helper = OperationHelper::new(&req, EventName::ObjectAclPut, S3Operation::PutObjectAcl); + let bucket = &req.input.bucket; + let key = &req.input.key; + let version_id = req.input.version_id.clone(); + + let Some(store) = new_object_layer_fn() else { + return Err(S3Error::with_message(S3ErrorCode::InternalError, "Not init".to_string())); + }; + + let opts: ObjectOptions = get_opts(bucket, key, version_id.clone(), None, &req.headers) + .await + .map_err(ApiError::from)?; + let object_info = store.get_object_info(bucket, key, &opts).await.map_err(ApiError::from)?; + + if req.input.access_control_policy.is_some() { + return Err(s3_error!( + NotImplemented, + "ACL XML grants are not supported; use canned ACL headers or omit ACL" + )); + } + + let event_version_id = version_id + .or_else(|| object_info.version_id.map(|version_id| version_id.to_string())) + .unwrap_or_default(); + helper = helper.object(object_info).version_id(event_version_id); + + let result = Ok(S3Response::new(PutObjectAclOutput::default())); + let _ = helper.complete(&result); + result } async fn put_object_legal_hold( diff --git a/rustfs/src/storage/ecfs_test.rs b/rustfs/src/storage/ecfs_test.rs index 64245b56a..84b230162 100644 --- a/rustfs/src/storage/ecfs_test.rs +++ b/rustfs/src/storage/ecfs_test.rs @@ -35,11 +35,12 @@ mod tests { }; use rustfs_zip::CompressionFormat; use s3s::dto::{ - CORSConfiguration, CORSRule, DefaultRetention, DeleteObjectTaggingInput, Delimiter, GetObjectAclInput, + CORSConfiguration, CORSRule, DefaultRetention, DeleteObjectTaggingInput, Delimiter, GetBucketAclInput, GetObjectAclInput, GetObjectLegalHoldInput, GetObjectRetentionInput, GetObjectTaggingInput, LambdaFunctionConfiguration, ObjectLockConfiguration, ObjectLockEnabled, ObjectLockLegalHold, ObjectLockLegalHoldStatus, ObjectLockRetention, - ObjectLockRetentionMode, ObjectLockRule, PutObjectLegalHoldInput, PutObjectLockConfigurationInput, - PutObjectRetentionInput, PutObjectTaggingInput, QueueConfiguration, Tag, Tagging, TopicConfiguration, + ObjectLockRetentionMode, ObjectLockRule, PutBucketAclInput, PutObjectAclInput, PutObjectLegalHoldInput, + PutObjectLockConfigurationInput, PutObjectRetentionInput, PutObjectTaggingInput, QueueConfiguration, Tag, Tagging, + TopicConfiguration, }; use s3s::{S3, S3Error, S3ErrorCode, S3Request, s3_error}; use time::OffsetDateTime; @@ -200,6 +201,18 @@ mod tests { assert_eq!(err.code(), &S3ErrorCode::InternalError); } + #[tokio::test] + async fn test_get_bucket_acl_returns_internal_error_when_store_uninitialized() { + let input = GetBucketAclInput::builder() + .bucket("test-bucket".to_string()) + .build() + .unwrap(); + + let fs = FS::new(); + let err = fs.get_bucket_acl(build_request(input, Method::GET)).await.unwrap_err(); + assert_eq!(err.code(), &S3ErrorCode::InternalError); + } + #[tokio::test] async fn test_get_object_legal_hold_returns_internal_error_when_store_uninitialized() { let input = GetObjectLegalHoldInput::builder() @@ -239,6 +252,31 @@ mod tests { assert_eq!(err.code(), &S3ErrorCode::InternalError); } + #[tokio::test] + async fn test_put_bucket_acl_returns_internal_error_when_store_uninitialized() { + let input = PutBucketAclInput::builder() + .bucket("test-bucket".to_string()) + .build() + .unwrap(); + + let fs = FS::new(); + let err = fs.put_bucket_acl(build_request(input, Method::PUT)).await.unwrap_err(); + assert_eq!(err.code(), &S3ErrorCode::InternalError); + } + + #[tokio::test] + async fn test_put_object_acl_returns_internal_error_when_store_uninitialized() { + let input = PutObjectAclInput::builder() + .bucket("test-bucket".to_string()) + .key("test-key".to_string()) + .build() + .unwrap(); + + let fs = FS::new(); + let err = fs.put_object_acl(build_request(input, Method::PUT)).await.unwrap_err(); + assert_eq!(err.code(), &S3ErrorCode::InternalError); + } + #[tokio::test] async fn test_put_object_retention_returns_internal_error_when_store_uninitialized() { let input = PutObjectRetentionInput::builder()