diff --git a/src/bun.js/api/server.zig b/src/bun.js/api/server.zig index 59c16b6fb5771c..5540dc7d5ae2ea 100644 --- a/src/bun.js/api/server.zig +++ b/src/bun.js/api/server.zig @@ -2546,6 +2546,39 @@ fn NewRequestContext(comptime ssl_enabled: bool, comptime debug_mode: bool, comp } } + fn writeHeaders( + this: *RequestContext, + headers: *JSC.FetchHeaders, + ) void { + ctxLog("writeHeaders", .{}); + headers.fastRemove(.ContentLength); + headers.fastRemove(.TransferEncoding); + if (!ssl_enabled) headers.fastRemove(.StrictTransportSecurity); + if (this.resp) |resp| { + headers.toUWSResponse(ssl_enabled, resp); + } + } + + pub fn writeStatus(this: *RequestContext, status: u16) void { + var status_text_buf: [48]u8 = undefined; + assert(!this.flags.has_written_status); + this.flags.has_written_status = true; + + if (this.resp) |resp| { + var response: *JSC.WebCore.Response = this.response_ptr.?; + const status_text = response.statusText(); + + if (status_text.length() != 0) { + resp.writeStatus(std.fmt.bufPrint(&status_text_buf, "{d} {s}", .{ status, status_text.byteSlice() }) catch unreachable); + } else if (HTTPStatusText.get(status)) |text| { + resp.writeStatus(text); + } else { + resp.writeStatus(std.fmt.bufPrint(&status_text_buf, "{d} HM", .{status}) catch unreachable); + } + } + } + + pub fn endSendFile(this: *RequestContext, writeOffSet: usize, closeConnection: bool) void { if (this.resp) |resp| { defer this.deref(); diff --git a/src/bun.js/webcore/response.zig b/src/bun.js/webcore/response.zig index 184c1f9cbbc06d..d6c0976887ae9f 100644 --- a/src/bun.js/webcore/response.zig +++ b/src/bun.js/webcore/response.zig @@ -122,6 +122,10 @@ pub const Response = struct { return this.init.status_code; } + pub inline fn statusText(this: *const Response) bun.String { + return this.init.status_text; + } + pub fn redirectLocation(this: *const Response) ?[]const u8 { return this.header(.Location); } diff --git a/test/js/bun/http/bun-server.test.ts b/test/js/bun/http/bun-server.test.ts index f6ebd8a57ac3b5..af6ef9ceb17f88 100644 --- a/test/js/bun/http/bun-server.test.ts +++ b/test/js/bun/http/bun-server.test.ts @@ -4,7 +4,44 @@ import { bunEnv, bunExe, rejectUnauthorizedScope } from "harness"; import path from "path"; describe("Server", () => { - test("normlizes incoming request URLs", async () => { + test("should set a custom statusText", async () => { + const server = Bun.serve({ + fetch(request) { + return new Response(request.url, { + headers: { + "Connection": "close", + }, + statusText: "customStatusText", + }); + }, + port: 0, + }); + + const response = await fetch(server.url); + expect(response.statusText).toBe("customStatusText"); + + server.stop(true); + }); + + test("should set the default statusText if not statusText is defined", async () => { + const server = Bun.serve({ + fetch(request) { + return new Response(request.url, { + headers: { + "Connection": "close", + }, + }); + }, + port: 0, + }); + + const response = await fetch(server.url); + expect(response.statusText).toBe("OK"); + + server.stop(true); + }); + + test("normalizes incoming request URLs", async () => { using server = Bun.serve({ fetch(request) { return new Response(request.url, { diff --git a/test/js/node/http/node-http.test.ts b/test/js/node/http/node-http.test.ts index a3f4e2f76775d1..1f37ec62e928ac 100644 --- a/test/js/node/http/node-http.test.ts +++ b/test/js/node/http/node-http.test.ts @@ -44,6 +44,42 @@ function listen(server: Server, protocol: string = "http"): Promise { describe("node:http", () => { describe("createServer", async () => { + it("should set a custom statusText", async () => { + try { + var server = createServer((req, res) => { + res.writeHead(200, "customStatusText"); + + res.end("Hello World"); + }); + const url = await listen(server); + const res = await fetch(new URL(url)); + + expect(res.statusText).toBe("customStatusText"); + } catch (e) { + throw e; + } finally { + server.close(); + } + }); + + it("should set the default statusText if not custom statusText is defined", async () => { + try { + var server = createServer((req, res) => { + res.writeHead(200); + + res.end("Hello World"); + }); + const url = await listen(server); + const res = await fetch(new URL(url)); + + expect(res.statusText).toBe("OK"); + } catch (e) { + throw e; + } finally { + server.close(); + } + }); + it("hello world", async () => { try { var server = createServer((req, res) => {