Gate 206 response checksum headers on full-range coverage

This commit is contained in:
2026-04-24 20:18:41 +08:00
parent 5aba9ac9e9
commit 37541ffba1
4 changed files with 103 additions and 8 deletions

12
Cargo.lock generated
View File

@@ -2639,7 +2639,7 @@ dependencies = [
[[package]]
name = "myfsio-auth"
version = "0.4.5"
version = "0.5.0"
dependencies = [
"aes",
"base64",
@@ -2664,7 +2664,7 @@ dependencies = [
[[package]]
name = "myfsio-common"
version = "0.4.5"
version = "0.5.0"
dependencies = [
"chrono",
"serde",
@@ -2675,7 +2675,7 @@ dependencies = [
[[package]]
name = "myfsio-crypto"
version = "0.4.5"
version = "0.5.0"
dependencies = [
"aes-gcm",
"base64",
@@ -2696,7 +2696,7 @@ dependencies = [
[[package]]
name = "myfsio-server"
version = "0.4.5"
version = "0.5.0"
dependencies = [
"aes-gcm",
"async-trait",
@@ -2753,7 +2753,7 @@ dependencies = [
[[package]]
name = "myfsio-storage"
version = "0.4.5"
version = "0.5.0"
dependencies = [
"chrono",
"dashmap",
@@ -2777,7 +2777,7 @@ dependencies = [
[[package]]
name = "myfsio-xml"
version = "0.4.5"
version = "0.5.0"
dependencies = [
"chrono",
"myfsio-common",

View File

@@ -10,7 +10,7 @@ members = [
]
[workspace.package]
version = "0.4.5"
version = "0.5.0"
edition = "2021"
[workspace.dependencies]

View File

@@ -2783,7 +2783,9 @@ async fn stream_partial_content(
headers.insert("x-amz-server-side-encryption", alg.parse().unwrap());
}
apply_stored_response_headers(&mut headers, &meta.internal_metadata);
apply_stored_checksum_headers(&mut headers, &meta.internal_metadata);
if start == 0 && end + 1 == plaintext_size {
apply_stored_checksum_headers(&mut headers, &meta.internal_metadata);
}
if let Some(ref requested_version) = query.version_id {
if let Ok(value) = requested_version.parse() {
headers.insert("x-amz-version-id", value);

View File

@@ -1905,6 +1905,99 @@ async fn test_range_request() {
assert_eq!(&body[..], b"data.");
}
#[tokio::test]
async fn test_range_get_omits_whole_object_checksum() {
use base64::engine::general_purpose::STANDARD as B64;
use sha2::{Digest, Sha256};
let (app, _tmp) = test_app();
app.clone()
.oneshot(signed_request(Method::PUT, "/csum-bucket", Body::empty()))
.await
.unwrap();
let data = b"Hello, World! This is range checksum data.";
let sha = B64.encode(Sha256::digest(data));
app.clone()
.oneshot(
Request::builder()
.method(Method::PUT)
.uri("/csum-bucket/obj.bin")
.header("x-access-key", TEST_ACCESS_KEY)
.header("x-secret-key", TEST_SECRET_KEY)
.header("x-amz-checksum-sha256", &sha)
.body(Body::from(&data[..]))
.unwrap(),
)
.await
.unwrap();
let full = app
.clone()
.oneshot(
Request::builder()
.uri("/csum-bucket/obj.bin")
.header("x-access-key", TEST_ACCESS_KEY)
.header("x-secret-key", TEST_SECRET_KEY)
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(full.status(), StatusCode::OK);
assert_eq!(
full.headers().get("x-amz-checksum-sha256").unwrap(),
sha.as_str()
);
let partial = app
.clone()
.oneshot(
Request::builder()
.uri("/csum-bucket/obj.bin")
.header("x-access-key", TEST_ACCESS_KEY)
.header("x-secret-key", TEST_SECRET_KEY)
.header("range", "bytes=0-4")
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(partial.status(), StatusCode::PARTIAL_CONTENT);
for algo in ["sha256", "sha1", "crc32", "crc32c", "crc64nvme"] {
let header = format!("x-amz-checksum-{}", algo);
assert!(
partial.headers().get(&header).is_none(),
"ranged GET must not include {}",
header
);
}
let body_bytes = partial.into_body().collect().await.unwrap().to_bytes();
assert_eq!(&body_bytes[..], &data[..5]);
let full_range = format!("bytes=0-{}", data.len() - 1);
let covering = app
.oneshot(
Request::builder()
.uri("/csum-bucket/obj.bin")
.header("x-access-key", TEST_ACCESS_KEY)
.header("x-secret-key", TEST_SECRET_KEY)
.header("range", &full_range)
.body(Body::empty())
.unwrap(),
)
.await
.unwrap();
assert_eq!(covering.status(), StatusCode::PARTIAL_CONTENT);
assert_eq!(
covering.headers().get("x-amz-checksum-sha256").unwrap(),
sha.as_str()
);
}
#[tokio::test]
async fn test_copy_object() {
let (app, _tmp) = test_app();