diff --git a/src/Request.ts b/src/Request.ts index ee38d70..e3afb45 100644 --- a/src/Request.ts +++ b/src/Request.ts @@ -169,6 +169,12 @@ export class Request { public async text(): Promise { return (await this.blob()).text(); } + + /** + * Response headers that the Response to this request should include. + * @internal + */ + public _responseHeaders = new Headers(); } export namespace Request { diff --git a/src/Server.ts b/src/Server.ts index b9b476a..81e3b49 100644 --- a/src/Server.ts +++ b/src/Server.ts @@ -36,8 +36,12 @@ class Server { this.server.listen(options.port); } + /** @internal **/ + public get _keepAliveTimeout() { + return this.server.keepAliveTimeout; + } + private async listener(req: http.IncomingMessage, res: http.ServerResponse) { - res.setHeaders(this.globalHeaders); let apiRequest: Request; try { apiRequest = Request.incomingMessage(req); @@ -52,11 +56,13 @@ class Server { throw e; } + for (const [key, value] of this.globalHeaders) + apiRequest._responseHeaders.set(key, value); + if (this.copyOrigin) { - res.appendHeader("Access-Control-Allow-Origin", apiRequest.headers.get("Origin") ?? "*"); - res.appendHeader("Vary", "Origin"); + apiRequest._responseHeaders.set("access-control-allow-origin", apiRequest.headers.get("Origin") ?? "*"); + apiRequest._responseHeaders.set("vary", "origin"); } - res.setHeaders(this.globalHeaders); let response: Response; try { diff --git a/src/response/BufferResponse.ts b/src/response/BufferResponse.ts index ad4e833..fca0a72 100644 --- a/src/response/BufferResponse.ts +++ b/src/response/BufferResponse.ts @@ -1,4 +1,6 @@ import http from "node:http"; +import {Request} from "../Request.js"; +import {Server} from "../Server.js"; import {Response} from "./Response.js"; /** @@ -10,9 +12,15 @@ export abstract class BufferResponse extends Response { */ protected abstract readBuffer(): Uint8Array | Promise; - protected override async send(res: http.ServerResponse): Promise { - this.writeHead(res); + protected override async send(res: http.ServerResponse, server: Server, req?: Request): Promise { const buffer = await this.readBuffer(); + if (req !== undefined) { + if (res.chunkedEncoding) + req._responseHeaders.set("transfer-encoding", "chunked"); + else + req._responseHeaders.set("content-length", buffer.byteLength.toString()); + } + this.writeHead(res, server, req); res.end(buffer); } } diff --git a/src/response/EmptyResponse.ts b/src/response/EmptyResponse.ts index 9028707..536a2f6 100644 --- a/src/response/EmptyResponse.ts +++ b/src/response/EmptyResponse.ts @@ -1,4 +1,6 @@ import http from "node:http"; +import {Request} from "../Request.js"; +import {Server} from "../Server.js"; import {Response} from "./Response.js"; /** @@ -14,8 +16,15 @@ export class EmptyResponse extends Response { super(status, headers); } - protected override send(res: http.ServerResponse): void { + /*protected override send(res: http.ServerResponse): void { this.writeHead(res); res.end(); + }*/ + + protected override send(res: http.ServerResponse, server: Server, req?: Request): void { + if (req !== undefined) + req._responseHeaders.set("content-length", "0"); + this.writeHead(res, server, req); + res.end(); } } diff --git a/src/response/Response.ts b/src/response/Response.ts index 1feb840..b9aef60 100644 --- a/src/response/Response.ts +++ b/src/response/Response.ts @@ -36,9 +36,27 @@ export abstract class Response { /** * Set the HTTP response status code and headers. */ - protected writeHead(res: http.ServerResponse) { - res.statusCode = this.statusCode; - res.setHeaders(this.headers); + protected writeHead(res: http.ServerResponse, server: Server, req?: Request) { + const headers = new Headers(this.headers); + if (req !== undefined) + for (const [key, value] of req._responseHeaders) + headers.set(key, value); + if (!headers.has("date")) + headers.set("date", new Date().toUTCString()); + if ( + req === undefined + || req.headers.get("connection") === "close" + || !res.shouldKeepAlive + ) + headers.set("connection", "close"); + else { + headers.set("connection", "keep-alive"); + headers.set("keep-alive", "timeout=" + server._keepAliveTimeout); + } + for (const [key, value] of Array.from(headers.entries()) + .sort((a, b) => a[0].localeCompare(b[0]))) + res.setHeader(key, value); + res.writeHead(this.statusCode); } /**