Skip to content

Commit 987f5c9

Browse files
authored
ServeDir: convert io::ErrorKind::NotADirectory to not_found (#331)
* ServeDir: convert io::ErrorKind::NotADirectory to not_found * only check raw OS error on unix OS, add comment. * mention "is a directory" handling in ServeDir in documentation
1 parent a6d0f7b commit 987f5c9

File tree

3 files changed

+36
-2
lines changed

3 files changed

+36
-2
lines changed

tower-http/src/services/fs/serve_dir/future.rs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -124,8 +124,19 @@ where
124124
}
125125

126126
Err(err) => {
127-
if let io::ErrorKind::NotFound | io::ErrorKind::PermissionDenied =
128-
err.kind()
127+
#[cfg(unix)]
128+
// 20 = libc::ENOTDIR => "not a directory
129+
// when `io_error_more` landed, this can be changed
130+
// to checking for `io::ErrorKind::NotADirectory`.
131+
// https://github.com/rust-lang/rust/issues/86442
132+
let error_is_not_a_directory = err.raw_os_error() == Some(20);
133+
#[cfg(not(unix))]
134+
let error_is_not_a_directory = false;
135+
136+
if matches!(
137+
err.kind(),
138+
io::ErrorKind::NotFound | io::ErrorKind::PermissionDenied
139+
) || error_is_not_a_directory
129140
{
130141
if let Some((mut fallback, request)) = fallback_and_request.take() {
131142
call_fallback(&mut fallback, request)

tower-http/src/services/fs/serve_dir/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,8 @@ const DEFAULT_CAPACITY: usize = 65536;
3535
/// - The file doesn't exist
3636
/// - Any segment of the path contains `..`
3737
/// - Any segment of the path contains a backslash
38+
/// - On unix, any segment of the path referenced as directory is actually an
39+
/// existing file (`/file.html/something`)
3840
/// - We don't have necessary permissions to read the file
3941
///
4042
/// # Example

tower-http/src/services/fs/serve_dir/tests.rs

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,6 +289,27 @@ async fn not_found() {
289289
assert!(body.is_empty());
290290
}
291291

292+
#[cfg(unix)]
293+
#[tokio::test]
294+
async fn not_found_when_not_a_directory() {
295+
let svc = ServeDir::new("../test-files");
296+
297+
// `index.html` is a file, and we are trying to request
298+
// it as a directory.
299+
let req = Request::builder()
300+
.uri("/index.html/some_file")
301+
.body(Body::empty())
302+
.unwrap();
303+
let res = svc.oneshot(req).await.unwrap();
304+
305+
// This should lead to a 404
306+
assert_eq!(res.status(), StatusCode::NOT_FOUND);
307+
assert!(res.headers().get(header::CONTENT_TYPE).is_none());
308+
309+
let body = body_into_text(res.into_body()).await;
310+
assert!(body.is_empty());
311+
}
312+
292313
#[tokio::test]
293314
async fn not_found_precompressed() {
294315
let svc = ServeDir::new("../test-files").precompressed_gzip();

0 commit comments

Comments
 (0)