mirror of
https://github.com/rustfs/rustfs.git
synced 2026-07-26 08:18:18 +00:00
fix(quota): only require decoded length for actually framed aws-chunked bodies (#4968)
PUT admission since #4928 rejected any request whose Content-Encoding declares aws-chunked but lacks x-amz-decoded-content-length with 400 UnexpectedContent. Whether the body is actually chunk-framed is signalled by a STREAMING-* x-amz-content-sha256, not by the declared encoding: the s3s auth layer only de-frames streaming payloads and already requires the decoded length for them, so a declared-only aws-chunked request (issue #1857 clients) carries an unframed body whose wire Content-Length is the authoritative object size. Admit it against that length; keep failing closed for genuinely framed bodies without a decoded length, and use the decoded length for streaming payloads even when Content-Encoding is absent. Refs: https://github.com/rustfs/backlog/issues/1336
This commit is contained in:
@@ -277,6 +277,64 @@ mod integration_tests {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// backlog#1336 regression: a PUT that merely declares `Content-Encoding: aws-chunked`
|
||||
/// (no SigV4 streaming payload, so no `x-amz-decoded-content-length`) carries an unframed
|
||||
/// body whose wire Content-Length is the real object size. Quota admission must use that
|
||||
/// length — with and without a hard quota configured — instead of rejecting the request
|
||||
/// with 400 UnexpectedContent, and an over-quota aws-chunked PUT must still get the quota
|
||||
/// rejection.
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn test_quota_admission_aws_chunked_declared_encoding() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
init_logging();
|
||||
if skip_without_awscurl() {
|
||||
return Ok(());
|
||||
}
|
||||
let env = QuotaTestEnv::new().await?;
|
||||
env.create_bucket().await?;
|
||||
|
||||
let put_aws_chunked = |key: &'static str, size_bytes: usize| {
|
||||
env.client
|
||||
.put_object()
|
||||
.bucket(&env.bucket_name)
|
||||
.key(key)
|
||||
.content_encoding("aws-chunked")
|
||||
.body(aws_sdk_s3::primitives::ByteStream::from(vec![0u8; size_bytes]))
|
||||
.send()
|
||||
};
|
||||
|
||||
// No quota configured: the declared aws-chunked PUT must be admitted.
|
||||
put_aws_chunked("no-quota.bin", 512)
|
||||
.await
|
||||
.expect("declared aws-chunked PUT without quota must succeed");
|
||||
assert!(env.object_exists("no-quota.bin").await?);
|
||||
|
||||
// Hard quota configured: a within-quota declared aws-chunked PUT is admitted
|
||||
// against its wire Content-Length.
|
||||
env.set_bucket_quota(4 * 1024).await?;
|
||||
put_aws_chunked("within-quota.bin", 1024)
|
||||
.await
|
||||
.expect("declared aws-chunked PUT within quota must succeed");
|
||||
assert!(env.object_exists("within-quota.bin").await?);
|
||||
|
||||
// An over-quota declared aws-chunked PUT is rejected by quota admission —
|
||||
// not with UnexpectedContent.
|
||||
let err = put_aws_chunked("over-quota.bin", 16 * 1024)
|
||||
.await
|
||||
.expect_err("declared aws-chunked PUT over quota must be rejected");
|
||||
let err_debug = format!("{err:?}");
|
||||
assert!(
|
||||
!err_debug.contains("UnexpectedContent"),
|
||||
"over-quota rejection must be the quota error, not UnexpectedContent: {err_debug}"
|
||||
);
|
||||
assert!(!env.object_exists("over-quota.bin").await?);
|
||||
|
||||
env.clear_bucket_quota().await?;
|
||||
env.cleanup_bucket().await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tokio::test]
|
||||
#[serial]
|
||||
async fn test_quota_update_and_clear() -> Result<(), Box<dyn std::error::Error + Send + Sync>> {
|
||||
|
||||
Reference in New Issue
Block a user