From ec8abb19abebc406a6ea1a9c7f91254ff559393b Mon Sep 17 00:00:00 2001 From: Zhengchao An Date: Fri, 28 Aug 2026 06:53:15 +0800 Subject: [PATCH] refactor(s3-client): reuse rustfs-utils header classification instead of duplicating it (#6758) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit crates/s3-client/src/utils.rs carried a verbatim copy of the header classification tables and predicates owned by crates/utils/src/http/headers.rs: SUPPORTED_HEADERS (same 11 keys), SUPPORTED_QUERY_VALUES (same 9 keys), and is_standard_header / is_storageclass_header / is_amz_header / is_rustfs_header / is_minio_header with byte-identical bodies. The duplication was already half-resolved and inconsistent — the local is_amz_header called rustfs_utils::http::is_sse_header while consulting its own tables — and s3-client already depends on rustfs-utils with the "full" feature, so reusing the canonical owner adds no crate edge. The sole caller, PutObjectOptions::header(), now imports the five predicates from rustfs_utils::http. Semantics are unchanged: both sides normalize with to_lowercase(), return false for unknown keys, and the storage-class constants are the same string ("x-amz-storage-class" from s3s::header::X_AMZ_STORAGE_CLASS vs rustfs_utils AMZ_STORAGE_CLASS), so the set of user-metadata headers passed through verbatim rather than prefixed with x-amz-meta- is identical. SUPPORTED_QUERY_VALUES is deleted outright: s3-client had no reader for it (utils consumes its own copy via is_standard_query_value). The base64_encode/base64_decode helpers and their rustfs/rustfs#4811 regression test stay untouched, and lazy_static remains a dependency because crates/s3-client/src/constants.rs still uses it. Refs rustfs/backlog#2050 --- crates/s3-client/src/api_put_object.rs | 2 +- crates/s3-client/src/utils.rs | 61 -------------------------- 2 files changed, 1 insertion(+), 62 deletions(-) diff --git a/crates/s3-client/src/api_put_object.rs b/crates/s3-client/src/api_put_object.rs index 82797a22f..158523946 100644 --- a/crates/s3-client/src/api_put_object.rs +++ b/crates/s3-client/src/api_put_object.rs @@ -24,6 +24,7 @@ use std::{collections::HashMap, sync::Arc}; use time::{Duration, OffsetDateTime, macros::format_description}; use tracing::{error, info, warn}; +use rustfs_utils::http::{is_amz_header, is_minio_header, is_rustfs_header, is_standard_header, is_storageclass_header}; use s3s::dto::{ObjectLockLegalHoldStatus, ObjectLockRetentionMode, ReplicationStatus}; use s3s::header::{ X_AMZ_OBJECT_LOCK_LEGAL_HOLD, X_AMZ_OBJECT_LOCK_MODE, X_AMZ_OBJECT_LOCK_RETAIN_UNTIL_DATE, X_AMZ_REPLICATION_STATUS, @@ -40,7 +41,6 @@ use crate::{ constants::{ISO8601_DATEFORMAT, MAX_MULTIPART_PUT_OBJECT_SIZE, MIN_PART_SIZE}, credentials::SignatureType, transition_api::{ReaderImpl, TransitionClient, UploadInfo}, - utils::{is_amz_header, is_minio_header, is_rustfs_header, is_standard_header, is_storageclass_header}, }; #[derive(Debug, Clone)] diff --git a/crates/s3-client/src/utils.rs b/crates/s3-client/src/utils.rs index 3a03449fb..bc3645346 100644 --- a/crates/s3-client/src/utils.rs +++ b/crates/s3-client/src/utils.rs @@ -12,67 +12,6 @@ // See the License for the specific language governing permissions and // limitations under the License. -use lazy_static::lazy_static; -use std::collections::HashMap; - -use s3s::header::X_AMZ_STORAGE_CLASS; - -lazy_static! { - static ref SUPPORTED_QUERY_VALUES: HashMap = { - let mut m = HashMap::new(); - m.insert("attributes".to_string(), true); - m.insert("partNumber".to_string(), true); - m.insert("versionId".to_string(), true); - m.insert("response-cache-control".to_string(), true); - m.insert("response-content-disposition".to_string(), true); - m.insert("response-content-encoding".to_string(), true); - m.insert("response-content-language".to_string(), true); - m.insert("response-content-type".to_string(), true); - m.insert("response-expires".to_string(), true); - m - }; - static ref SUPPORTED_HEADERS: HashMap = { - let mut m = HashMap::new(); - m.insert("content-type".to_string(), true); - m.insert("cache-control".to_string(), true); - m.insert("content-encoding".to_string(), true); - m.insert("content-disposition".to_string(), true); - m.insert("content-language".to_string(), true); - m.insert("x-amz-website-redirect-location".to_string(), true); - m.insert("x-amz-object-lock-mode".to_string(), true); - m.insert("x-amz-metadata-directive".to_string(), true); - m.insert("x-amz-object-lock-retain-until-date".to_string(), true); - m.insert("expires".to_string(), true); - m.insert("x-amz-replication-status".to_string(), true); - m - }; -} - -pub fn is_storageclass_header(header_key: &str) -> bool { - header_key.to_lowercase() == X_AMZ_STORAGE_CLASS.as_str().to_lowercase() -} - -pub fn is_standard_header(header_key: &str) -> bool { - *SUPPORTED_HEADERS.get(&header_key.to_lowercase()).unwrap_or(&false) -} - -pub fn is_amz_header(header_key: &str) -> bool { - let key = header_key.to_lowercase(); - key.starts_with("x-amz-meta-") - || key.starts_with("x-amz-grant-") - || key == "x-amz-acl" - || rustfs_utils::http::is_sse_header(header_key) - || key.starts_with("x-amz-checksum-") -} - -pub fn is_rustfs_header(header_key: &str) -> bool { - header_key.to_lowercase().starts_with("x-rustfs-") -} - -pub fn is_minio_header(header_key: &str) -> bool { - header_key.to_lowercase().starts_with("x-minio-") -} - /// Standard base64 (with `+`/`/` and `=` padding). Every base64 value this /// transition client emits or parses — `Content-MD5`, `x-amz-checksum-*`, and /// checksum digests in request/response bodies — is S3 wire format, which is