tower-rs / tower-http

HTTP specific Tower utilities.
682 stars 159 forks source link

ServeDir doesn't serve files without extentions if pre-compression is enabled #504

Open SvizelPritula opened 2 weeks ago

SvizelPritula commented 2 weeks ago

Bug Report

Version

tower-http v0.5.2

Platform

Linux turing-machine 6.8.0-41-generic #41-Ubuntu SMP PREEMPT_DYNAMIC Fri Aug  2 20:41:06 UTC 2024 x86_64 x86_64 x86_64 GNU/Linux

Description

When using ServeDir::precompressed_gzip or similar methods, ServeDir won't serve files without a file extention if the client supports the relevant encoding.

Consider the following axum server:

use axum::Router;
use std::net::SocketAddr;
use tower_http::services::ServeDir;

#[tokio::main]
async fn main() {
    let app = Router::new().fallback_service(ServeDir::new("assets/").precompressed_gzip());

    let addr = SocketAddr::from(([127, 0, 0, 1], 8000));
    let listener = tokio::net::TcpListener::bind(addr).await.unwrap();

    axum::serve(listener, app).await.unwrap();
}

I created the assets/hello file and tried to access it using curl:

$ curl -i http://localhost:8000/hello 
HTTP/1.1 200 OK
content-type: application/octet-stream
accept-ranges: bytes
last-modified: Thu, 29 Aug 2024 14:51:50 GMT
content-length: 14
date: Thu, 29 Aug 2024 15:04:58 GMT

Hello, world!
$ curl -i -H "Accept-Encoding: gzip" http://localhost:8000/hello 
HTTP/1.1 404 Not Found
content-length: 0
date: Thu, 29 Aug 2024 15:05:06 GMT

This happens whether assets/hello.gz exists or not.

Speculation

There seems to be a bug in the tower_http::services::fs::serve_dir::open_file::preferred_encoding method. I tried adding this test:

#[test]
fn preferred_encoding_without_extension() {
    let mut path = PathBuf::from("hello");
    preferred_encoding(&mut path, &[(Encoding::Gzip, QValue::one())]);
    assert_eq!(path, PathBuf::from("hello.gz"));
}

This test fails with the following panic:

thread 'services::fs::serve_dir::open_file::tests::preferred_encoding_without_extension' panicked at tower-http/src/services/fs/serve_dir/open_file.rs:342:9:
assertion `left == right` failed
  left: "hello..gz"
 right: "hello.gz"