From 4987cfe5e55e5fc6165fd8392b3c2396f6d34437 Mon Sep 17 00:00:00 2001 From: "Helmut K. C. Tessarek" Date: Fri, 8 Mar 2024 08:47:13 -0500 Subject: [PATCH] fix(upload): error on upload with the same filename (#258) --- .../config.toml | 9 +++ .../test-file-upload-same-filename/test.sh | 21 +++++++ src/paste.rs | 8 +++ src/server.rs | 57 +++++++++++++++++++ 4 files changed, 95 insertions(+) create mode 100644 fixtures/test-file-upload-same-filename/config.toml create mode 100755 fixtures/test-file-upload-same-filename/test.sh diff --git a/fixtures/test-file-upload-same-filename/config.toml b/fixtures/test-file-upload-same-filename/config.toml new file mode 100644 index 0000000..279c7c9 --- /dev/null +++ b/fixtures/test-file-upload-same-filename/config.toml @@ -0,0 +1,9 @@ +[server] +address = "127.0.0.1:8000" +max_content_length = "10MB" +upload_path = "./upload" + +[paste] +random_url = { type = "alphanumeric", length = "4", suffix_mode = true } +default_extension = "txt" +duplicate_files = true diff --git a/fixtures/test-file-upload-same-filename/test.sh b/fixtures/test-file-upload-same-filename/test.sh new file mode 100755 index 0000000..1bef175 --- /dev/null +++ b/fixtures/test-file-upload-same-filename/test.sh @@ -0,0 +1,21 @@ +#!/usr/bin/env bash + +content="test data" + +setup() { + echo "$content" > file +} + +run_test() { + file_url=$(curl -s -F "file=@file" -H "filename:fn_from_header.txt" localhost:8000) + test "$file_url" = "http://localhost:8000/fn_from_header.txt" + test "$content" = "$(cat upload/fn_from_header.txt)" + test "$content" = "$(curl -s $file_url)" + file_url=$(curl -s -F "file=@file" -H "filename:fn_from_header.txt" localhost:8000) + test "$file_url" = "file already exists" +} + +teardown() { + rm file + rm -r upload +} diff --git a/src/paste.rs b/src/paste.rs index 7a1c27c..e39c827 100644 --- a/src/paste.rs +++ b/src/paste.rs @@ -176,6 +176,14 @@ impl Paste { .map(|v| v.to_string_lossy()) .unwrap_or_default() .to_string(); + let file_path = util::glob_match_file(path.clone()) + .map_err(|_| IoError::new(IoErrorKind::Other, String::from("path is not valid")))?; + if file_path.is_file() && file_path.exists() { + return Err(IoError::new( + IoErrorKind::AlreadyExists, + String::from("file already exists\n"), + )); + } if let Some(timestamp) = expiry_date { path.set_file_name(format!("{file_name}.{timestamp}")); } diff --git a/src/server.rs b/src/server.rs index 2abbf85..dbd9cbf 100644 --- a/src/server.rs +++ b/src/server.rs @@ -907,6 +907,63 @@ mod tests { Ok(()) } + #[actix_web::test] + async fn test_upload_same_filename() -> Result<(), Error> { + let mut config = Config::default(); + config.server.upload_path = env::current_dir()?; + + let app = test::init_service( + App::new() + .app_data(Data::new(RwLock::new(config))) + .app_data(Data::new(Client::default())) + .configure(configure_routes), + ) + .await; + + let file_name = "test_file.txt"; + let header_filename = "fn_from_header.txt"; + let timestamp = util::get_system_time()?.as_secs().to_string(); + let response = test::call_service( + &app, + get_multipart_request(×tamp, "file", file_name) + .insert_header(( + header::HeaderName::from_static("filename"), + header::HeaderValue::from_static("fn_from_header.txt"), + )) + .to_request(), + ) + .await; + assert_eq!(StatusCode::OK, response.status()); + assert_body( + response.into_body(), + &format!("http://localhost:8080/{header_filename}\n"), + ) + .await?; + + let timestamp = util::get_system_time()?.as_secs().to_string(); + let response = test::call_service( + &app, + get_multipart_request(×tamp, "file", file_name) + .insert_header(( + header::HeaderName::from_static("filename"), + header::HeaderValue::from_static("fn_from_header.txt"), + )) + .to_request(), + ) + .await; + assert_eq!(StatusCode::INTERNAL_SERVER_ERROR, response.status()); + assert_body(response.into_body(), "file already exists\n").await?; + + fs::remove_file(header_filename)?; + let serve_request = TestRequest::get() + .uri(&format!("/{header_filename}")) + .to_request(); + let response = test::call_service(&app, serve_request).await; + assert_eq!(StatusCode::NOT_FOUND, response.status()); + + Ok(()) + } + #[actix_web::test] #[allow(deprecated)] async fn test_upload_duplicate_file() -> Result<(), Error> {