Skip to content

fix(serve): negotiate Content-Encoding from Accept-Encoding - #60

Open
alshdavid wants to merge 6 commits into
mainfrom
agent/auto-flash/223da754fb6d
Open

alshdavid wants to merge 6 commits into
mainfrom
agent/auto-flash/223da754fb6d

Conversation

@alshdavid

Copy link
Copy Markdown
Owner

Summary

  • Negotiate response coding from the request's Accept-Encoding instead of always claiming br.
  • JIT compression (--compress, including transpiled SCSS/TS output) now only applies brotli when the client accepts it; otherwise the response is sent uncompressed.
  • Pre-compressed sibling files are served only when their coding is accepted, preferring .br over .gz consistent with the header's quality values.
  • Compressed variants now send Vary: Accept-Encoding so shared caches keep separate entries.

Testing

  • cargo test --workspace
  • cargo clippy --all-targets --workspace -- -D warnings
  • cargo xfmt --check

Fixes #22

alshdavid

This comment was marked as outdated.

alshdavid

This comment was marked as outdated.

Repository owner deleted a comment from alshdavid-machine Oct 20, 2026
@alshdavid

Copy link
Copy Markdown
Owner Author

@alshdavid-machine rebase this

Only apply brotli compression, or serve a pre-compressed sibling, when the
client accepts that coding, and send Vary: Accept-Encoding so caches do not
reuse the wrong variant. Fixes #22.
@alshdavid-machine
alshdavid-machine force-pushed the agent/auto-flash/223da754fb6d branch from cb61d83 to eb5d490 Compare October 20, 2026 12:22
@alshdavid-machine

Copy link
Copy Markdown
Collaborator

In reply to #60 (comment)

Rebased agent/auto-flash/223da754fb6d onto main (cf70df1) and force-pushed.

  • Resolved the src/cmd/serve/handler.rs conflict: kept the PR's Accept-Encoding negotiation and folded it into main's file_path.to_str() guard (dropped the .unwrap()).
  • cargo check, clippy -D warnings, cargo test (38 passed), and cargo xfmt all clean.

PR #60 now sits on current main with no conflicts.

}

/// Pick the most preferred supported coding from an `Accept-Encoding` header.
pub fn negotiate(accept_encoding: Option<&str>) -> Option<Encoding> {

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alshdavid-machine why are these in the same file as the brotli function?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

They were together because commit eb5d490 moved the old mod.rs body into a single compress.rs verbatim — it carried the HTTP content-negotiation concern (Encoding, negotiate, quality) along with the actual compression function.

Split them so each file owns one concern:

  • src/platform/compress/compress.rs — just brotli.
  • src/platform/compress/encoding.rs — Encoding, negotiate, quality.
  • mod.rs re-exports both; the public API (compress::brotli, compress::negotiate, compress::Encoding) is unchanged, so handler.rs callers are untouched.

cargo check, clippy -D warnings, cargo test (38 passed) and cargo xfmt all clean. Pushed to agent/auto-flash/223da754fb6d as ad93ff2.

Comment thread src/platform/compress/encoding_test.rs
Comment thread src/platform/compress/mod.rs
Comment thread src/platform/compress/brotli.rs

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alshdavid-machine read-only. What is the purpose of this file?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/platform/compress/encoding.rs defines the content-encoding negotiation for the server — the logic that decides whether to compress a response with brotli or gzip based on the client's Accept-Encoding header.

  • Encoding enum (Brotli, Gzip) with name() mapping to the wire tokens br / gzip.
  • negotiate(Option<&str>) picks the best supported coding: it takes the header, evaluates each supported encoding's quality via quality(), drops anything with q=0, and returns the highest-preference match (brotli wins ties, since it's listed first in the [Brotli, Gzip] array).
  • quality() parses Accept-Encoding into tokens and params, reads q= (defaulting to 1.0), and handles the * wildcard as a fallback.

Consumed by src/cmd/serve/handler.rs, which calls compress::negotiate(...) and sets Content-Encoding / Vary on responses. Tests live in encoding_test.rs.

Read-only request — no code changed, nothing committed or pushed.

Copy link
Copy Markdown
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@alshdavid-machine

Despite offering the ability to negotiate the use of gzip, it appears only brotli is supported for actual compression.

Is there a mechanism to compress with gzip?

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No — nothing produces gzip at request time. The only gzip path is pre-compressed sidecar files.

  • JIT (--compress): src/platform/compress/brotli.rs is the entire compressor, brotli only. Every compression site in src/cmd/serve/handler.rs gates on encoding == Some(compress::Encoding::Brotli) (lines 359, 403, 518). When negotiate returns Gzip, none of those branches match, so the client gets the uncompressed body and no Content-Encoding.
  • Sidecars (--compress off): handler.rs:441-455 looks for a <file>.br / <file>.gz sibling and, if it exists, serves it with Content-Encoding: gzip and Vary: Accept-Encoding. This is the only place Encoding::Gzip is actually honoured — and it is guarded by !config.compress, so it never runs when JIT compression is on.

So negotiation advertises gzip as supported while JIT can't fulfil it. Closing the gap would need a gzip encoder plus a Gzip arm at those three sites; no code changed for this question.

Comment thread src/platform/compress/encoding.rs Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Compression ignores Accept-Encoding (always sends br)

2 participants