From 27ff35e574bc28873616c4178692aed78d56b075 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=AE=89=E6=AD=A3=E8=B6=85?= Date: Sat, 28 Feb 2026 22:35:56 +0800 Subject: [PATCH] fix: avoid region fallback panic paths (#2006) --- rustfs/src/app/bucket_usecase.rs | 24 +++++++++--------------- rustfs/src/app/multipart_usecase.rs | 18 +++++++++--------- 2 files changed, 18 insertions(+), 24 deletions(-) diff --git a/rustfs/src/app/bucket_usecase.rs b/rustfs/src/app/bucket_usecase.rs index 15f450a05..9d614fa59 100644 --- a/rustfs/src/app/bucket_usecase.rs +++ b/rustfs/src/app/bucket_usecase.rs @@ -72,13 +72,11 @@ fn to_internal_error(err: impl Display) -> S3Error { S3Error::with_message(S3ErrorCode::InternalError, format!("{err}")) } -fn default_region() -> Region { - // RUSTFS_REGION is a compile-time constant ("us-east-1") guaranteed to be valid. - Region::new(RUSTFS_REGION.into()).expect("RUSTFS_REGION constant must be a valid region") -} - -fn resolve_notification_region(global_region: Option, request_region: Option) -> Region { - global_region.or(request_region).unwrap_or_else(default_region) +fn resolve_notification_region(global_region: Option, request_region: Option) -> String { + global_region + .or(request_region) + .map(|region| region.to_string()) + .unwrap_or_else(|| RUSTFS_REGION.to_string()) } const ERR_LIFECYCLE_RULE_STATUS: &str = "Rule status must be either Enabled or Disabled"; @@ -1218,9 +1216,8 @@ impl DefaultBucketUsecase { let event_rules = event_rules_result.map_err(|e| s3_error!(InvalidArgument, "Invalid ARN in notification configuration: {e}"))?; warn!("notify event rules: {:?}", &event_rules); - let region_clone = region.clone(); notify - .add_event_specific_rules(&bucket, region_clone.as_str(), &event_rules) + .add_event_specific_rules(&bucket, region.as_str(), &event_rules) .await .map_err(|e| s3_error!(InternalError, "Failed to add rules: {e}"))?; @@ -1758,22 +1755,19 @@ mod tests { #[test] fn resolve_notification_region_prefers_global_region() { let binding = resolve_notification_region(Some("us-east-1".parse().unwrap()), Some("ap-southeast-1".parse().unwrap())); - let region = binding.as_str(); - assert_eq!(region, "us-east-1"); + assert_eq!(binding, "us-east-1"); } #[test] fn resolve_notification_region_falls_back_to_request_region() { let binding = resolve_notification_region(None, Some("ap-southeast-1".parse().unwrap())); - let region = binding.as_str(); - assert_eq!(region, "ap-southeast-1"); + assert_eq!(binding, "ap-southeast-1"); } #[test] fn resolve_notification_region_defaults_value() { let binding = resolve_notification_region(None, None); - let region = binding.as_str(); - assert_eq!(region, RUSTFS_REGION); + assert_eq!(binding, RUSTFS_REGION); } #[tokio::test] diff --git a/rustfs/src/app/multipart_usecase.rs b/rustfs/src/app/multipart_usecase.rs index 72e3fee81..e77cb53ee 100644 --- a/rustfs/src/app/multipart_usecase.rs +++ b/rustfs/src/app/multipart_usecase.rs @@ -79,7 +79,7 @@ impl DefaultMultipartUsecase { self.context.as_ref().and_then(|context| context.bucket_metadata().handle()) } - fn global_region(&self) -> Option { + fn global_region(&self) -> Option { self.context.as_ref().and_then(|context| context.region().get()) } @@ -339,12 +339,13 @@ impl DefaultMultipartUsecase { let region = self .global_region() - .unwrap_or_else(|| Region::new(RUSTFS_REGION.into()).expect("RUSTFS_REGION constant must be a valid region")); + .map(|region| region.to_string()) + .unwrap_or_else(|| RUSTFS_REGION.to_string()); let output = CompleteMultipartUploadOutput { bucket: Some(bucket.clone()), key: Some(key.clone()), e_tag: obj_info.etag.clone().map(|etag| to_s3s_etag(&etag)), - location: Some(region.to_string()), + location: Some(region.clone()), server_side_encryption: server_side_encryption.clone(), ssekms_key_id: ssekms_key_id.clone(), checksum_crc32: checksum_crc32.clone(), @@ -356,16 +357,11 @@ impl DefaultMultipartUsecase { version_id: mpu_version, ..Default::default() }; - info!( - "TDD: Created output: SSE={:?}, KMS={:?}", - output.server_side_encryption, output.ssekms_key_id - ); - let helper_output = entity::CompleteMultipartUploadOutput { bucket: Some(bucket.clone()), key: Some(key.clone()), e_tag: obj_info.etag.clone().map(|etag| to_s3s_etag(&etag)), - location: Some(region.to_string()), + location: Some(region), server_side_encryption, ssekms_key_id, checksum_crc32, @@ -376,6 +372,10 @@ impl DefaultMultipartUsecase { checksum_type, ..Default::default() }; + info!( + "TDD: Created output: SSE={:?}, KMS={:?}", + output.server_side_encryption, output.ssekms_key_id + ); let mt2 = HashMap::new(); let replicate_options =