mirror of
https://github.com/rustfs/rustfs.git
synced 2026-10-04 04:21:35 +00:00
fix(s3): default CopyObject content-type to binary/octet-stream on REPLACE (#8073)
fix: default CopyObject content-type to binary/octet-stream on REPLACE
This commit is contained in:
@@ -298,7 +298,11 @@ mod tests {
|
||||
assert_eq!(empty_head_resp.content_disposition(), None);
|
||||
assert_eq!(empty_head_resp.content_encoding(), None);
|
||||
assert_eq!(empty_head_resp.content_language(), None);
|
||||
assert_eq!(empty_head_resp.content_type(), None);
|
||||
assert_eq!(
|
||||
empty_head_resp.content_type(),
|
||||
Some("binary/octet-stream"),
|
||||
"REPLACE without an explicit content type must default to binary/octet-stream, matching S3"
|
||||
);
|
||||
assert_eq!(empty_head_resp.expires_string(), None);
|
||||
assert_eq!(empty_head_resp.website_redirect_location(), None);
|
||||
|
||||
@@ -394,7 +398,15 @@ mod tests {
|
||||
assert_eq!(head.content_disposition(), (field == "content-disposition").then_some("attachment"));
|
||||
assert_eq!(head.content_encoding(), (field == "content-encoding").then_some("gzip"));
|
||||
assert_eq!(head.content_language(), (field == "content-language").then_some("de"));
|
||||
assert_eq!(head.content_type(), (field == "content-type").then_some("text/field"));
|
||||
assert_eq!(
|
||||
head.content_type(),
|
||||
Some(if field == "content-type" {
|
||||
"text/field"
|
||||
} else {
|
||||
"binary/octet-stream"
|
||||
}),
|
||||
"REPLACE without an explicit content type must default to binary/octet-stream, matching S3"
|
||||
);
|
||||
assert_eq!(
|
||||
head.expires_string(),
|
||||
(field == "expires").then_some(replacement_expires_http_date.as_str())
|
||||
@@ -420,7 +432,11 @@ mod tests {
|
||||
.send()
|
||||
.await
|
||||
.expect("HEAD failed for metadata collision case");
|
||||
assert_eq!(collision_head.content_type(), None);
|
||||
assert_eq!(
|
||||
collision_head.content_type(),
|
||||
Some("binary/octet-stream"),
|
||||
"user-metadata under the reserved 'content-type' key must not satisfy the system content-type default"
|
||||
);
|
||||
assert_eq!(collision_head.content_encoding(), None);
|
||||
assert_eq!(
|
||||
collision_head.metadata().and_then(|metadata| metadata.get("content-type")),
|
||||
|
||||
@@ -607,9 +607,16 @@ impl DefaultObjectUsecase {
|
||||
// Handle MetadataDirective REPLACE: replace user metadata while preserving system metadata.
|
||||
// System metadata (compression, encryption) is added after this block to ensure
|
||||
// it's not cleared by the REPLACE operation.
|
||||
if let Some(replacement_metadata) = replacement_metadata {
|
||||
if let Some(mut replacement_metadata) = replacement_metadata {
|
||||
// S3 defaults an object's content type to `binary/octet-stream` when none is
|
||||
// supplied. REPLACE must apply that same default instead of leaving
|
||||
// content-type unset.
|
||||
if !replacement_metadata.contains_key("content-type") {
|
||||
replacement_metadata.insert("content-type".to_string(), "binary/octet-stream".to_string());
|
||||
}
|
||||
let effective_content_type = replacement_metadata.get("content-type").cloned();
|
||||
user_defined = replacement_metadata;
|
||||
src_info.content_type = content_type.clone();
|
||||
src_info.content_type = effective_content_type;
|
||||
src_info.content_encoding = content_encoding.as_deref().and_then(normalize_content_encoding_for_storage);
|
||||
src_info.expires = expires_timestamp.map(OffsetDateTime::from);
|
||||
} else if metadata_directive.is_some() || website_redirect_location.is_some() {
|
||||
|
||||
Reference in New Issue
Block a user