Compare commits

..

1 Commits

Author SHA1 Message Date
Claude Bot
c6a730ae7c fix(http): add Date header to error responses using endWithoutBody
Calls to `endWithoutBody()` in the HTTP server skipped `writeMark()`,
which is responsible for writing the `Date` header. This affected 413,
403, and 500 error responses generated before reaching user handlers.

Fixes #27512

Co-Authored-By: Claude <noreply@anthropic.com>
2026-02-27 10:09:42 +00:00
4 changed files with 25 additions and 72 deletions

View File

@@ -1981,6 +1981,7 @@ pub fn NewServer(protocol_enum: enum { http, https }, development_kind: enum { d
if (!node_response.flags.request_has_completed and raw_response.state().isResponsePending()) {
if (raw_response.state().isHttpStatusCalled()) {
raw_response.writeStatus("500 Internal Server Error");
raw_response.writeMark();
raw_response.endWithoutBody(true);
} else {
raw_response.endStream(true);
@@ -2217,6 +2218,7 @@ pub fn NewServer(protocol_enum: enum { http, https }, development_kind: enum { d
// Abort the request very early.
if (len > this.config.max_request_body_size) {
resp.writeStatus("413 Request Entity Too Large");
resp.writeMark();
resp.endWithoutBody(true);
return null;
}
@@ -2344,6 +2346,7 @@ pub fn NewServer(protocol_enum: enum { http, https }, development_kind: enum { d
// require fetch method to be set otherwise we dont know what route to call
// this should be the fallback in case no route is provided to upgrade
resp.writeStatus("403 Forbidden");
resp.writeMark();
resp.endWithoutBody(true);
return;
}

View File

@@ -4209,18 +4209,13 @@ pub const BundleV2 = struct {
});
result.ast.import_records = import_records;
// Set is_export_star_target for barrel optimization.
// In dev server mode, source_index is not saved on JS import
// records, so fall back to resolving via the path map.
const path_to_source_index_map = this.pathToSourceIndexMap(result.ast.target);
// Set is_export_star_target for barrel optimization
for (result.ast.export_star_import_records) |star_record_idx| {
if (star_record_idx < import_records.len) {
const star_ir = import_records.slice()[star_record_idx];
const resolved_index = if (star_ir.source_index.isValid())
star_ir.source_index.get()
else
path_to_source_index_map.getPath(&star_ir.path) orelse continue;
graph.input_files.items(.flags)[resolved_index].is_export_star_target = true;
if (star_ir.source_index.isValid()) {
graph.input_files.items(.flags)[star_ir.source_index.get()].is_export_star_target = true;
}
}
}

View File

@@ -550,69 +550,6 @@ devTest("barrel optimization: multi-file imports preserved across rebuilds", {
},
});
devTest("barrel optimization: export star target not deferred (#27521)", {
files: {
"index.html": emptyHtmlFile({ scripts: ["index.ts"] }),
// The user imports from consumer-lib, which is a non-barrel package
// that imports QueryClient from outer-lib.
"index.ts": `
import { useQuery } from 'consumer-lib';
console.log('result: ' + useQuery());
`,
// consumer-lib is NOT a barrel — it has real code that uses
// QueryClient from outer-lib. This mirrors @refinedev/core
// importing QueryClient from @tanstack/react-query.
"node_modules/consumer-lib/package.json": JSON.stringify({
name: "consumer-lib",
version: "1.0.0",
main: "./index.js",
}),
"node_modules/consumer-lib/index.js": `
import { QueryClient } from 'outer-lib';
export function useQuery() {
const client = new QueryClient();
return client instanceof QueryClient ? 'PASS' : 'FAIL';
}
`,
// outer-lib is a barrel with sideEffects:false that re-exports
// everything from inner-lib via export *. Mirrors @tanstack/react-query.
"node_modules/outer-lib/package.json": JSON.stringify({
name: "outer-lib",
version: "1.0.0",
main: "./index.js",
sideEffects: false,
}),
"node_modules/outer-lib/index.js": `
export * from 'inner-lib';
export { Unrelated } from './unrelated.js';
`,
"node_modules/outer-lib/unrelated.js": `export const Unrelated = "X";`,
// inner-lib is a barrel with sideEffects:false that re-exports
// from submodules. Mirrors @tanstack/query-core. Without the fix,
// the barrel optimizer defers queryClient.js because it doesn't
// know inner-lib is an export-star target (source_index is not
// set in dev-server mode), so QueryClient becomes undefined.
"node_modules/inner-lib/package.json": JSON.stringify({
name: "inner-lib",
version: "1.0.0",
main: "./index.js",
sideEffects: false,
}),
"node_modules/inner-lib/index.js": `
export { QueryClient } from './queryClient.js';
export { Other } from './other.js';
`,
"node_modules/inner-lib/queryClient.js": `
export class QueryClient { constructor() { this.ready = true; } }
`,
"node_modules/inner-lib/other.js": `export const Other = "OTHER";`,
},
async test(dev) {
await using c = await dev.client("/");
await c.expectMessage("result: PASS");
},
});
devTest("barrel optimization: two export-from blocks pointing to the same source", {
files: {
"index.html": emptyHtmlFile({ scripts: ["index.ts"] }),

View File

@@ -0,0 +1,18 @@
import { expect, test } from "bun:test";
test("413 responses should include a Date header", async () => {
using server = Bun.serve({
port: 0,
maxRequestBodySize: 1,
fetch() {
return new Response("Hello Bun");
},
});
const res = await fetch(`http://localhost:${server.port}/`, {
method: "POST",
body: "12",
});
expect(res.status).toBe(413);
expect(res.headers.get("date")).not.toBeNull();
});