mirror of
https://github.com/rustfs/rustfs.git
synced 2026-08-25 13:36:50 +00:00
fix(download): preserve archive download integrity (#2415)
Co-authored-by: heihutu <heihutu@gmail.com> Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: houseme <4829346+houseme@users.noreply.github.com>
This commit is contained in:
@@ -170,6 +170,7 @@ pub trait CachedGetObjectSource {
|
||||
fn content_type(&self) -> Option<&str>;
|
||||
fn e_tag(&self) -> Option<&str>;
|
||||
fn last_modified(&self) -> Option<&str>;
|
||||
fn expires(&self) -> Option<&str>;
|
||||
fn cache_control(&self) -> Option<&str>;
|
||||
fn content_disposition(&self) -> Option<&str>;
|
||||
fn content_encoding(&self) -> Option<&str>;
|
||||
@@ -405,6 +406,10 @@ where
|
||||
.last_modified()
|
||||
.and_then(|s| OffsetDateTime::parse(s, &Rfc3339).ok())
|
||||
.map(Timestamp::from);
|
||||
let expires = cached
|
||||
.expires()
|
||||
.and_then(|s| OffsetDateTime::parse(s, &Rfc3339).ok())
|
||||
.map(Timestamp::from);
|
||||
|
||||
let content_type = cached.content_type().and_then(|ct| ContentType::from_str(ct).ok());
|
||||
|
||||
@@ -416,6 +421,7 @@ where
|
||||
accept_ranges: Some("bytes".to_string()),
|
||||
e_tag: cached.e_tag().map(to_s3s_etag),
|
||||
last_modified,
|
||||
expires,
|
||||
content_type,
|
||||
cache_control: cached.cache_control().map(str::to_string),
|
||||
content_disposition: cached.content_disposition().map(str::to_string),
|
||||
@@ -890,8 +896,12 @@ pub fn build_get_object_output(
|
||||
body,
|
||||
content_length: Some(response_content_length),
|
||||
last_modified,
|
||||
expires: info.expires.map(Timestamp::from),
|
||||
content_type,
|
||||
cache_control: info.user_defined.get(CACHE_CONTROL.as_str()).cloned(),
|
||||
content_disposition: info.user_defined.get(CONTENT_DISPOSITION.as_str()).cloned(),
|
||||
content_encoding: info.content_encoding.clone(),
|
||||
content_language: info.user_defined.get(CONTENT_LANGUAGE.as_str()).cloned(),
|
||||
accept_ranges: Some("bytes".to_string()),
|
||||
content_range,
|
||||
e_tag: info.etag.as_ref().map(|etag| to_s3s_etag(etag)),
|
||||
@@ -1052,6 +1062,7 @@ mod tests {
|
||||
content_type: Option<String>,
|
||||
e_tag: Option<String>,
|
||||
last_modified: Option<String>,
|
||||
expires: Option<String>,
|
||||
cache_control: Option<String>,
|
||||
content_disposition: Option<String>,
|
||||
content_encoding: Option<String>,
|
||||
@@ -1090,6 +1101,10 @@ mod tests {
|
||||
self.last_modified.as_deref()
|
||||
}
|
||||
|
||||
fn expires(&self) -> Option<&str> {
|
||||
self.expires.as_deref()
|
||||
}
|
||||
|
||||
fn cache_control(&self) -> Option<&str> {
|
||||
self.cache_control.as_deref()
|
||||
}
|
||||
@@ -1624,6 +1639,7 @@ mod tests {
|
||||
content_type: None,
|
||||
e_tag: None,
|
||||
last_modified: None,
|
||||
expires: None,
|
||||
cache_control: None,
|
||||
content_disposition: None,
|
||||
content_encoding: None,
|
||||
@@ -1651,6 +1667,46 @@ mod tests {
|
||||
assert_eq!(result.output.checksum_type, Some(ChecksumType::from_static(ChecksumType::FULL_OBJECT)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_get_object_output_preserves_http_metadata_like_cached_path() {
|
||||
let mut info = ObjectInfo {
|
||||
content_type: Some("application/octet-stream".to_string()),
|
||||
content_encoding: Some("zstd".to_string()),
|
||||
etag: Some("etag".to_string()),
|
||||
expires: Some(OffsetDateTime::UNIX_EPOCH),
|
||||
..Default::default()
|
||||
};
|
||||
info.user_defined
|
||||
.insert("cache-control".to_string(), "max-age=3600".to_string());
|
||||
info.user_defined
|
||||
.insert("content-disposition".to_string(), "attachment; filename=\"bundle.zip\"".to_string());
|
||||
info.user_defined.insert("content-language".to_string(), "en-US".to_string());
|
||||
|
||||
let output = build_get_object_output(
|
||||
None,
|
||||
&info,
|
||||
info.content_type
|
||||
.as_ref()
|
||||
.and_then(|content_type| ContentType::from_str(content_type).ok()),
|
||||
info.mod_time.map(Timestamp::from),
|
||||
8,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
None,
|
||||
&GetObjectChecksums::default(),
|
||||
None,
|
||||
None,
|
||||
);
|
||||
|
||||
assert_eq!(output.cache_control.as_deref(), Some("max-age=3600"));
|
||||
assert_eq!(output.content_disposition.as_deref(), Some("attachment; filename=\"bundle.zip\""));
|
||||
assert_eq!(output.content_language.as_deref(), Some("en-US"));
|
||||
assert_eq!(output.content_encoding.as_deref(), Some("zstd"));
|
||||
assert_eq!(output.expires, Some(Timestamp::from(OffsetDateTime::UNIX_EPOCH)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn build_cors_wrapped_get_object_flow_result_uses_wrapped_mode() {
|
||||
let result = build_cors_wrapped_get_object_flow_result(
|
||||
|
||||
Reference in New Issue
Block a user