mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-27 15:37:02 +00:00
fix: preserve exact JSON format in bucket policy GET response (#1598)
Co-authored-by: loverustfs <hello@rustfs.com>
This commit is contained in:
@@ -96,6 +96,15 @@ pub async fn get_bucket_policy(bucket: &str) -> Result<(BucketPolicy, OffsetDate
|
|||||||
bucket_meta_sys.get_bucket_policy(bucket).await
|
bucket_meta_sys.get_bucket_policy(bucket).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the raw JSON string of the bucket policy as originally stored.
|
||||||
|
/// This preserves the exact format of the policy document as it was PUT.
|
||||||
|
pub async fn get_bucket_policy_raw(bucket: &str) -> Result<(String, OffsetDateTime)> {
|
||||||
|
let bucket_meta_sys_lock = get_bucket_metadata_sys()?;
|
||||||
|
let bucket_meta_sys = bucket_meta_sys_lock.read().await;
|
||||||
|
|
||||||
|
bucket_meta_sys.get_bucket_policy_raw(bucket).await
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_quota_config(bucket: &str) -> Result<(BucketQuota, OffsetDateTime)> {
|
pub async fn get_quota_config(bucket: &str) -> Result<(BucketQuota, OffsetDateTime)> {
|
||||||
let bucket_meta_sys_lock = get_bucket_metadata_sys()?;
|
let bucket_meta_sys_lock = get_bucket_metadata_sys()?;
|
||||||
let bucket_meta_sys = bucket_meta_sys_lock.read().await;
|
let bucket_meta_sys = bucket_meta_sys_lock.read().await;
|
||||||
@@ -455,6 +464,20 @@ impl BucketMetadataSys {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the raw JSON string of the bucket policy as originally stored.
|
||||||
|
/// This preserves the exact format of the policy document as it was PUT.
|
||||||
|
pub async fn get_bucket_policy_raw(&self, bucket: &str) -> Result<(String, OffsetDateTime)> {
|
||||||
|
let (bm, _) = self.get_config(bucket).await?;
|
||||||
|
|
||||||
|
if bm.policy_config_json.is_empty() {
|
||||||
|
Err(Error::ConfigNotFound)
|
||||||
|
} else {
|
||||||
|
let policy_str = String::from_utf8(bm.policy_config_json.clone())
|
||||||
|
.map_err(|e| Error::other(format!("invalid UTF-8 in policy JSON: {}", e)))?;
|
||||||
|
Ok((policy_str, bm.policy_config_updated_at))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn get_tagging_config(&self, bucket: &str) -> Result<(Tagging, OffsetDateTime)> {
|
pub async fn get_tagging_config(&self, bucket: &str) -> Result<(Tagging, OffsetDateTime)> {
|
||||||
let (bm, _) = self.get_config(bucket).await?;
|
let (bm, _) = self.get_config(bucket).await?;
|
||||||
|
|
||||||
|
|||||||
@@ -5736,7 +5736,9 @@ impl S3 for FS {
|
|||||||
.await
|
.await
|
||||||
.map_err(ApiError::from)?;
|
.map_err(ApiError::from)?;
|
||||||
|
|
||||||
let cfg = match PolicySys::get(&bucket).await {
|
// Return the raw policy JSON as originally stored to preserve exact format.
|
||||||
|
// This ensures GET returns the same document that was PUT, matching S3 behavior.
|
||||||
|
let (policy_str, _) = match metadata_sys::get_bucket_policy_raw(&bucket).await {
|
||||||
Ok(res) => res,
|
Ok(res) => res,
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
if StorageError::ConfigNotFound == err {
|
if StorageError::ConfigNotFound == err {
|
||||||
@@ -5746,9 +5748,9 @@ impl S3 for FS {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let policies = try_!(serde_json::to_string(&cfg));
|
Ok(S3Response::new(GetBucketPolicyOutput {
|
||||||
|
policy: Some(policy_str),
|
||||||
Ok(S3Response::new(GetBucketPolicyOutput { policy: Some(policies) }))
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn put_bucket_policy(&self, req: S3Request<PutBucketPolicyInput>) -> S3Result<S3Response<PutBucketPolicyOutput>> {
|
async fn put_bucket_policy(&self, req: S3Request<PutBucketPolicyInput>) -> S3Result<S3Response<PutBucketPolicyOutput>> {
|
||||||
@@ -5773,7 +5775,9 @@ impl S3 for FS {
|
|||||||
return Err(s3_error!(InvalidPolicyDocument));
|
return Err(s3_error!(InvalidPolicyDocument));
|
||||||
}
|
}
|
||||||
|
|
||||||
let data = serde_json::to_vec(&cfg).map_err(|e| s3_error!(InternalError, "parse policy failed {:?}", e))?;
|
// Store the original policy string as-is to preserve the exact JSON format.
|
||||||
|
// This ensures GET returns the same document that was PUT.
|
||||||
|
let data = policy.into_bytes();
|
||||||
|
|
||||||
metadata_sys::update(&bucket, BUCKET_POLICY_CONFIG, data)
|
metadata_sys::update(&bucket, BUCKET_POLICY_CONFIG, data)
|
||||||
.await
|
.await
|
||||||
|
|||||||
@@ -17,7 +17,7 @@
|
|||||||
# - Metadata: User-defined metadata
|
# - Metadata: User-defined metadata
|
||||||
# - Conditional GET: If-Match, If-None-Match, If-Modified-Since
|
# - Conditional GET: If-Match, If-None-Match, If-Modified-Since
|
||||||
#
|
#
|
||||||
# Total: 119 tests
|
# Total: 123 tests
|
||||||
|
|
||||||
test_basic_key_count
|
test_basic_key_count
|
||||||
test_bucket_create_naming_bad_short_one
|
test_bucket_create_naming_bad_short_one
|
||||||
@@ -101,6 +101,7 @@ test_bucketv2_notexist
|
|||||||
test_bucketv2_policy_another_bucket
|
test_bucketv2_policy_another_bucket
|
||||||
test_get_bucket_policy_status
|
test_get_bucket_policy_status
|
||||||
test_get_nonpublicpolicy_principal_bucket_policy_status
|
test_get_nonpublicpolicy_principal_bucket_policy_status
|
||||||
|
test_set_get_del_bucket_policy
|
||||||
test_get_object_ifmatch_good
|
test_get_object_ifmatch_good
|
||||||
test_get_object_ifmodifiedsince_good
|
test_get_object_ifmodifiedsince_good
|
||||||
test_get_object_ifunmodifiedsince_failed
|
test_get_object_ifunmodifiedsince_failed
|
||||||
|
|||||||
@@ -173,7 +173,6 @@ test_put_excess_tags
|
|||||||
test_put_excess_val_tags
|
test_put_excess_val_tags
|
||||||
test_put_get_delete_public_block
|
test_put_get_delete_public_block
|
||||||
test_put_public_block
|
test_put_public_block
|
||||||
test_set_get_del_bucket_policy
|
|
||||||
|
|
||||||
# Object attributes and torrent tests
|
# Object attributes and torrent tests
|
||||||
test_create_bucket_no_ownership_controls
|
test_create_bucket_no_ownership_controls
|
||||||
|
|||||||
Reference in New Issue
Block a user