fix: handle copy_source_if_match in copy_object for S3 compatibility (#1408)

Co-authored-by: loverustfs <hello@rustfs.com>
Co-authored-by: houseme <housemecn@gmail.com>
This commit is contained in:
安正超
2026-01-14 21:09:13 +08:00
committed by GitHub
parent 6928221b56
commit cb53ee13cd
3 changed files with 30 additions and 3 deletions

5
Cargo.lock generated
View File

@@ -8544,8 +8544,9 @@ checksum = "a50f4cf475b65d88e057964e0e9bb1f0aa9bbb2036dc65c64596b42932536984"
[[package]]
name = "s3s"
version = "0.13.0-alpha"
source = "git+https://github.com/s3s-project/s3s.git?branch=main#18c168ae21bf1176555f8f529686ecdc2ebd6db7"
version = "0.13.0-alpha.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6ea18014c794952beba5e5faf4663be467b591d45b4834916aad4bbcd2b5c27"
dependencies = [
"arrayvec",
"async-trait",

View File

@@ -225,7 +225,7 @@ regex = { version = "1.12.2" }
rumqttc = { version = "0.25.1" }
rust-embed = { version = "8.9.0" }
rustc-hash = { version = "2.1.1" }
s3s = { version = "0.13.0-alpha", features = ["minio"], git = "https://github.com/s3s-project/s3s.git", branch = "main" }
s3s = { version = "0.13.0-alpha.1", features = ["minio"] }
serial_test = "3.3.1"
shadow-rs = { version = "1.5.0", default-features = false }
siphasher = "1.0.1"

View File

@@ -873,6 +873,8 @@ impl S3 for FS {
sse_customer_key_md5,
metadata_directive,
metadata,
copy_source_if_match,
copy_source_if_none_match,
..
} = req.input.clone();
let (src_bucket, src_key, version_id) = match copy_source {
@@ -948,6 +950,30 @@ impl S3 for FS {
let mut src_info = gr.object_info.clone();
// Validate copy source conditions
if let Some(if_match) = copy_source_if_match {
if let Some(ref etag) = src_info.etag {
if let Some(strong_etag) = if_match.into_etag() {
if ETag::Strong(etag.clone()) != strong_etag {
return Err(s3_error!(PreconditionFailed));
}
} else {
// Weak ETag or Any (*) in If-Match should fail per RFC 9110
return Err(s3_error!(PreconditionFailed));
}
} else {
return Err(s3_error!(PreconditionFailed));
}
}
if let Some(if_none_match) = copy_source_if_none_match
&& let Some(ref etag) = src_info.etag
&& let Some(strong_etag) = if_none_match.into_etag()
&& ETag::Strong(etag.clone()) == strong_etag
{
return Err(s3_error!(PreconditionFailed));
}
if cp_src_dst_same {
src_info.metadata_only = true;
}