]> OzVa Git service - ozva-cloud/commitdiff
fix: serve files with names containing newline char (#328)
authorsigoden <sigoden@gmail.com>
Sat, 23 Dec 2023 07:40:41 +0000 (15:40 +0800)
committerGitHub <noreply@github.com>
Sat, 23 Dec 2023 07:40:41 +0000 (15:40 +0800)
src/server.rs
tests/fixtures.rs
tests/http.rs

index 8c426c657f86f3abb95fc923ad744e1f9dd9b1cf..632431755e7da403495c51e6fcf4ae42b5e739e3 100644 (file)
@@ -1547,13 +1547,23 @@ fn status_no_content(res: &mut Response) {
 
 fn set_content_diposition(res: &mut Response, inline: bool, filename: &str) -> Result<()> {
     let kind = if inline { "inline" } else { "attachment" };
+    let filename: String = filename
+        .chars()
+        .map(|ch| {
+            if ch.is_ascii_control() && ch != '\t' {
+                ' '
+            } else {
+                ch
+            }
+        })
+        .collect();
     let value = if filename.is_ascii() {
         HeaderValue::from_str(&format!("{kind}; filename=\"{}\"", filename,))?
     } else {
         HeaderValue::from_str(&format!(
             "{kind}; filename=\"{}\"; filename*=UTF-8''{}",
             filename,
-            encode_uri(filename),
+            encode_uri(&filename),
         ))?
     };
     res.headers_mut().insert(CONTENT_DISPOSITION, value);
index a83722dac6c3f1708e22c8884217f8d02e523b89..906563a91bc845a266f47168f288461e008d7825 100644 (file)
@@ -16,7 +16,14 @@ pub const BIN_FILE: &str = "😀.bin";
 
 /// File names for testing purpose
 #[allow(dead_code)]
-pub static FILES: &[&str] = &["test.txt", "test.html", "index.html", BIN_FILE];
+pub static FILES: &[&str] = &[
+    "test.txt",
+    "test.html",
+    "index.html",
+    #[cfg(not(target_os = "windows"))]
+    "file\n1.txt",
+    BIN_FILE,
+];
 
 /// Directory names for testing directory don't exist
 #[allow(dead_code)]
index 67fb328762021333d95b825cd26bdfec0fb24fc1..88fb51352561c2df8c763d1b79da2582ba88d009 100644 (file)
@@ -207,6 +207,18 @@ fn get_file_emoji_path(server: TestServer) -> Result<(), Error> {
     Ok(())
 }
 
+#[cfg(not(target_os = "windows"))]
+#[rstest]
+fn get_file_newline_path(server: TestServer) -> Result<(), Error> {
+    let resp = reqwest::blocking::get(format!("{}file%0A1.txt", server.url()))?;
+    assert_eq!(resp.status(), 200);
+    assert_eq!(
+        resp.headers().get("content-disposition").unwrap(),
+        "inline; filename=\"file 1.txt\""
+    );
+    Ok(())
+}
+
 #[rstest]
 fn get_file_edit(server: TestServer) -> Result<(), Error> {
     let resp = fetch!(b"GET", format!("{}index.html?edit", server.url())).send()?;