Skip to content

Commit 92041ee

Browse files
committed
fix(cp): avoid guessed content type for multipart uploads
1 parent 6a6d6b6 commit 92041ee

1 file changed

Lines changed: 49 additions & 6 deletions

File tree

  • crates/cli/src/commands

crates/cli/src/commands/cp.rs

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -277,12 +277,6 @@ async fn upload_file(
277277
return ExitCode::Success;
278278
}
279279

280-
// Determine content type
281-
let guessed_type: Option<String> = mime_guess::from_path(src)
282-
.first()
283-
.map(|m| m.essence_str().to_string());
284-
let content_type = args.content_type.as_deref().or(guessed_type.as_deref());
285-
286280
// Get file size for progress bar decision
287281
let file_size = match std::fs::metadata(src) {
288282
Ok(m) => m.len(),
@@ -294,6 +288,16 @@ async fn upload_file(
294288
}
295289
};
296290

291+
// Determine content type
292+
let guessed_type: Option<String> = mime_guess::from_path(src)
293+
.first()
294+
.map(|m| m.essence_str().to_string());
295+
let content_type = select_upload_content_type(
296+
args.content_type.as_deref(),
297+
guessed_type.as_deref(),
298+
file_size,
299+
);
300+
297301
// Show progress bar for large files
298302
let progress = if file_size >= MULTIPART_THRESHOLD {
299303
tracing::debug!(
@@ -335,6 +339,18 @@ async fn upload_file(
335339
}
336340
}
337341

342+
fn select_upload_content_type<'a>(
343+
explicit_type: Option<&'a str>,
344+
guessed_type: Option<&'a str>,
345+
file_size: u64,
346+
) -> Option<&'a str> {
347+
if file_size > MULTIPART_THRESHOLD {
348+
explicit_type
349+
} else {
350+
explicit_type.or(guessed_type)
351+
}
352+
}
353+
338354
async fn upload_directory(
339355
client: &S3Client,
340356
src: &Path,
@@ -862,6 +878,33 @@ mod tests {
862878
assert!(!progress.is_visible());
863879
}
864880

881+
#[test]
882+
fn test_select_upload_content_type_uses_guess_for_small_files() {
883+
let selected =
884+
select_upload_content_type(None, Some("text/plain"), MULTIPART_THRESHOLD - 1);
885+
886+
assert_eq!(selected, Some("text/plain"));
887+
}
888+
889+
#[test]
890+
fn test_select_upload_content_type_skips_guess_for_multipart_files() {
891+
let selected =
892+
select_upload_content_type(None, Some("text/plain"), MULTIPART_THRESHOLD + 1);
893+
894+
assert_eq!(selected, None);
895+
}
896+
897+
#[test]
898+
fn test_select_upload_content_type_keeps_explicit_type_for_multipart_files() {
899+
let selected = select_upload_content_type(
900+
Some("application/octet-stream"),
901+
Some("text/plain"),
902+
MULTIPART_THRESHOLD + 1,
903+
);
904+
905+
assert_eq!(selected, Some("application/octet-stream"));
906+
}
907+
865908
#[test]
866909
fn test_parse_cp_path_prefers_existing_local_path_when_alias_missing() {
867910
let (alias_manager, temp_dir) = temp_alias_manager();

0 commit comments

Comments
 (0)