tomaka / rouille

Web framework in Rust
Apache License 2.0
1.12k stars 106 forks source link

Audio metadata preload fails: no Content-Length header sent for matched asset #249

Closed kthy closed 2 years ago

kthy commented 2 years ago

Using rust 2021 stable on Windows 10 (rustc-1.57.0).

Minimal repro application (created using cargo new rouille-content-length-missing --bin):

Cargo.toml

[package]
name = "rouille-content-length-missing"
version = "0.1.0"
edition = "2021"

[dependencies]
rouille = "3.5.0"

src/main.rs

use rouille::{match_assets, router, start_server, Response};

fn main() {
    start_server("localhost:2635", move |req| {
        router!(req,
            (GET) (/) => {
                Response::redirect_303("/index.html")
            },
            _ => {
                if let Some(req) = req.remove_prefix("/static") {
                    match_assets(&req, "/Windows/Media/")
                } else {
                    match_assets(&req, ".").with_unique_header("Cache-Control", "no-store")
                }
            }
        )
    });
}

index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="utf-8">
</head>
<body>
    <audio controls preload="metadata" src="/static/Windows Error.wav"/>
</body>
</html>

(The .wav file can be anything, I've just used a standard Windows system sound for the example.)

Retrieving http://localhost:2635/index.html in my browser, I would expect to see a Content-Length: 171564 header, but this is what I get:

HTTP/1.1 200 OK
Server: tiny-http (Rust)
Date: Wed,  5 Jan 2022 13:15:57 GMT
Content-Type: audio/wav
ETag: 15272835558814221030
Cache-Control: public, max-age=3600
Transfer-Encoding: chunked

The missing Content-Length then leads me to experience Firefox bug 1416976 where the audio control shows the length of the WAV file as 6h45m48s.

bradfier commented 2 years ago

I think this is unfortunately a Firefox issue rather than a Rouille one. If you take a look at RFC2616 Section 4.4 you'll find the paragraph:

Messages MUST NOT include both a Content-Length header field and a non-identity transfer-coding. If the message does include a non-identity transfer-coding, the Content-Length MUST be ignored.

Firefox is relying on the presence of a header that the spec specifically prohibits, I don't think we can fix that in Rouille without violating the spec for every other use case.

kthy commented 2 years ago

It is a Firefox issue, but the inability to set Content-Length means I didn't have a workaround. I wasn't aware of that limitation in the RFC, though. 😢

Closing, sorry about the noise.

bradfier commented 2 years ago

You can work around it by forcing an HTTP 1.0 request (as HTTP 1.0 doesn't support chunked).

Using a <script> tag to make a raw connection via net.connect should be straightforward if a bit of a hack.