diff --git a/test-files/empty.txt b/test-files/empty.txt new file mode 100644 index 0000000..e69de29 diff --git a/tower-http/src/services/fs/serve_dir/future.rs b/tower-http/src/services/fs/serve_dir/future.rs index b1cc999..305029b 100644 --- a/tower-http/src/services/fs/serve_dir/future.rs +++ b/tower-http/src/services/fs/serve_dir/future.rs @@ -269,12 +269,18 @@ fn build_response(output: FileOpened) -> Response { empty_body() }; + let content_length = if size == 0 { + 0 + } else { + range.end() - range.start() + 1 + }; + builder .header( header::CONTENT_RANGE, format!("bytes {}-{}/{}", range.start(), range.end(), size), ) - .header(header::CONTENT_LENGTH, range.end() - range.start() + 1) + .header(header::CONTENT_LENGTH, content_length) .status(StatusCode::PARTIAL_CONTENT) .body(body) .unwrap() diff --git a/tower-http/src/services/fs/serve_dir/tests.rs b/tower-http/src/services/fs/serve_dir/tests.rs index 1fd768c..ea1c543 100644 --- a/tower-http/src/services/fs/serve_dir/tests.rs +++ b/tower-http/src/services/fs/serve_dir/tests.rs @@ -506,6 +506,25 @@ async fn access_space_percent_encoded_uri_path() { assert_eq!(res.headers()["content-type"], "text/plain"); } +#[tokio::test] +async fn read_partial_empty() { + let svc = ServeDir::new("../test-files"); + + let req = Request::builder() + .uri("/empty.txt") + .header("Range", "bytes=0-") + .body(Body::empty()) + .unwrap(); + let res = svc.oneshot(req).await.unwrap(); + + assert_eq!(res.status(), StatusCode::PARTIAL_CONTENT); + assert_eq!(res.headers()["content-length"], "0"); + assert_eq!(res.headers()["content-range"], "bytes 0-0/0"); + + let body = to_bytes(res.into_body()).await.ok().unwrap(); + assert!(body.is_empty()); +} + #[tokio::test] async fn read_partial_in_bounds() { let svc = ServeDir::new("..");