diff --git a/http/file_server_test.ts b/http/file_server_test.ts index f3384705ff77..c53730aaeafe 100644 --- a/http/file_server_test.ts +++ b/http/file_server_test.ts @@ -24,6 +24,7 @@ import { getAvailablePort } from "@std/net/get-available-port"; import { concat } from "@std/bytes/concat"; import { lessThan, parse as parseSemver } from "@std/semver"; import { serveDir as unstableServeDir } from "./unstable_file_server.ts"; +import { serveFile as unstableServeFile } from "./unstable_file_server.ts"; const moduleDir = dirname(fromFileUrl(import.meta.url)); const testdataDir = resolve(moduleDir, "testdata"); @@ -1176,3 +1177,14 @@ Deno.test("(unstable) serveDir() does not shadow existing files and directory if assertEquals(res.status, 301); assertEquals(res.headers.has("location"), true); }); + +Deno.test("(unstable) serveFile() sends custom headers", async () => { + const req = new Request("http://localhost/testdata/test_file.txt"); + const res = await unstableServeFile(req, TEST_FILE_PATH, { + headers: ["X-Extra: extra header"], + }); + + assertEquals(res.status, 200); + assertEquals(res.headers.get("X-Extra"), "extra header"); + assertEquals(await res.text(), TEST_FILE_TEXT); +}); diff --git a/http/unstable_file_server.ts b/http/unstable_file_server.ts index 3dbfcf3e33c0..f5ef9729e6a9 100644 --- a/http/unstable_file_server.ts +++ b/http/unstable_file_server.ts @@ -3,8 +3,9 @@ import { serveDir as stableServeDir, type ServeDirOptions as StableServeDirOptions, + serveFile as stableServeFile, + type ServeFileOptions as StableServeFileOptions, } from "./file_server.ts"; -export { serveFile, type ServeFileOptions } from "./file_server.ts"; /** * Serves the files under the given directory root (opts.fsRoot). @@ -61,3 +62,50 @@ export interface ServeDirOptions extends StableServeDirOptions { */ cleanUrls?: boolean; } + +/** Interface for serveFile options. */ +export interface ServeFileOptions extends StableServeFileOptions { + /** Headers to add to each response + * + * @default {[]} + */ + headers?: string[]; +} + +/** + * Resolves a {@linkcode Response} with the requested file as the body. + * + * @experimental **UNSTABLE**: New API, yet to be vetted. + * + * @example Usage + * ```ts ignore + * import { serveFile } from "@std/http/file-server"; + * + * Deno.serve((req) => { + * return serveFile(req, "README.md"); + * }); + * ``` + * + * @param req The server request context used to cleanup the file handle. + * @param filePath Path of the file to serve. + * @param options Additional options. + * @returns A response for the request. + */ +export async function serveFile( + req: Request, + filePath: string, + options?: ServeFileOptions, +): Promise { + const response = await stableServeFile(req, filePath, options); + + if (options?.headers) { + for (const header of options.headers) { + const headerSplit = header.split(":"); + const name = headerSplit[0]!; + const value = headerSplit.slice(1).join(":"); + response.headers.append(name, value); + } + } + + return response; +}