Skip to content

feat(http/unstable): accept HeadersInit for serveDir and serveFile headers#7190

Open
minato32 wants to merge 3 commits into
denoland:mainfrom
minato32:feat/6723-headersinit
Open

feat(http/unstable): accept HeadersInit for serveDir and serveFile headers#7190
minato32 wants to merge 3 commits into
denoland:mainfrom
minato32:feat/6723-headersinit

Conversation

@minato32

Copy link
Copy Markdown
Contributor

Closes #6723.

ServeDirOptions.headers and ServeFileOptions.headers in @std/http/unstable-file-server now accept HeadersInit instead of string[], so callers can pass a Headers instance, a record, or a list of tuples without hand-rolling name:value strings.

The stable serveDir/serveFile keep their existing string[] signature, so the file-server CLI behaviour is unchanged. The unstable wrapper strips headers before delegating to the stable implementation and applies them to the response itself (skipping redirect responses, matching the stable behaviour).

@CLAassistant

CLAassistant commented Jun 24, 2026

Copy link
Copy Markdown

CLA assistant check
All committers have signed the CLA.

@codecov

codecov Bot commented Jun 24, 2026

Copy link
Copy Markdown

Codecov Report

❌ Patch coverage is 94.44444% with 1 line in your changes missing coverage. Please review.
✅ Project coverage is 94.63%. Comparing base (f0431c2) to head (6f87cb1).
⚠️ Report is 4 commits behind head on main.

Files with missing lines Patch % Lines
http/unstable_file_server.ts 94.44% 0 Missing and 1 partial ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #7190      +/-   ##
==========================================
- Coverage   94.64%   94.63%   -0.02%     
==========================================
  Files         629      630       +1     
  Lines       51895    51902       +7     
  Branches     9373     9376       +3     
==========================================
- Hits        49116    49115       -1     
- Misses       2211     2217       +6     
- Partials      568      570       +2     

☔ View full report in Codecov by Harness.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@bartlomieju bartlomieju left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Nice ergonomic improvement — accepting HeadersInit is much friendlier than hand-built "name:value" strings, and the implementation reads cleanly. Verified the redirect-skip matches stable serveDir and that headers is correctly stripped before delegating so there's no double-application. Coverage is good (record + Headers instance + redirect skip, for both serveDir/serveFile).

A couple of non-blocking notes inline. Also worth calling out in the changelog: this is a hard break for the unstable API (old headers: ["X-Extra: extra header"] callers now fail to type-check and throw at runtime via new Headers(...)). That's fine for unstable — just be explicit about it. LGTM overall.

function appendHeaders(target: Headers, headers: HeadersInit): void {
const normalized = new Headers(headers);
for (const [name, value] of normalized) {
target.append(name, value);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Using .append() means custom headers are added alongside any the file server already set, rather than replacing them — e.g. passing cache-control would yield a comma-joined value rather than overriding. This matches the previous string[] behavior so it's not a regression, but now that the API takes a rich HeadersInit, callers may reasonably expect to override (e.g. set their own Cache-Control). Worth a one-line doc note on the headers option clarifying that values are appended, not replaced. (The cache-control test only passes because the dir-listing response doesn't pre-set that header.)

Comment thread http/file_server_test.ts Outdated
const req = new Request("http://localhost/hello");
const res = await unstableServeDir(req, {
...serveDirOptions,
...serveDirOptions as UnstableServeDirOptions,

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The as UnstableServeDirOptions cast (repeated at 5 call sites) is forced by Omit<StableServeDirOptions, "headers"> + redefine: the spread carries stable's headers?: string[], which isn't assignable to HeadersInit. You could avoid all the casts by typing the shared serveDirOptions fixture as UnstableServeDirOptions (or using satisfies). Minor, test-only.

Document that serveDir/serveFile headers are appended rather than
replacing pre-set headers, and type the test fixture with satisfies so
the per-call UnstableServeDirOptions casts are no longer needed.

Addresses @bartlomieju's review feedback.
@minato32

Copy link
Copy Markdown
Contributor Author

@bartlomieju updated in 6f87cb1 — added a doc note on both headers options clarifying values are appended (not replaced), and switched the test fixture to satisfies ServeDirOptions so the per-call casts are gone. Thanks for the review!

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.

suggestion(http): change ServeDirOptions.headers to accept HeadersInit instead of string[]

3 participants