diff --git a/src/webserver/http.rs b/src/webserver/http.rs index 1d0e31e7..ecc06c13 100644 --- a/src/webserver/http.rs +++ b/src/webserver/http.rs @@ -496,12 +496,11 @@ pub async fn main_handler( Serve(path) => { let if_modified_since = IfModifiedSince::parse(&service_request).ok(); let app_state: &web::Data = service_request.app_data().expect("app_state"); - serve_file( - path.as_os_str().to_str().unwrap(), - app_state, - if_modified_since, - ) - .await + let path = path + .as_os_str() + .to_str() + .ok_or_else(|| ErrorBadRequest("requested file path must be valid unicode"))?; + serve_file(path, app_state, if_modified_since).await } } .map(|response| service_request.into_response(response)) diff --git a/tests/core/mod.rs b/tests/core/mod.rs index 10f116ce..d765d87e 100644 --- a/tests/core/mod.rs +++ b/tests/core/mod.rs @@ -87,6 +87,55 @@ async fn test_routing_with_db_fs() { ); } +#[cfg(unix)] +#[actix_web::test] +async fn test_non_unicode_static_path_returns_bad_request_with_db_fs() { + let mut config = test_config(); + if !config.database_url.starts_with("sqlite") { + return; + } + config.database_url = + "sqlite://file:test_non_unicode_static_path?mode=memory&cache=shared".to_string(); + + let state = AppState::init(&config).await.unwrap(); + let expected_db_path = "\u{FFFD}.txt"; + let mut conn = state.db.connection.acquire().await.unwrap(); + + (&mut *conn) + .execute(sqlpage::filesystem::DbFsQueries::get_create_table_sql( + sqlpage::webserver::database::SupportedDatabase::Sqlite, + )) + .await + .unwrap(); + let insert_sql = format!( + "INSERT INTO sqlpage_files(path, contents) VALUES ({}, {})", + make_placeholder(state.db.info.kind, 1), + make_placeholder(state.db.info.kind, 2) + ); + sqlx::query(&insert_sql) + .bind(expected_db_path) + .bind("file from db fs".as_bytes()) + .execute(&mut *conn) + .await + .unwrap(); + drop(conn); + + let state = AppState::init(&config).await.unwrap(); + let app_data = actix_web::web::Data::new(state); + let req = test::TestRequest::get() + .uri("/%FF.txt") + .app_data(app_data) + .to_srv_request(); + + let err = sqlpage::webserver::http::main_handler(req) + .await + .expect_err("non-unicode path should not panic and must return bad request"); + assert_eq!( + err.as_response_error().status_code(), + StatusCode::BAD_REQUEST + ); +} + #[actix_web::test] async fn test_routing_with_prefix() { let mut config = test_config();