未验证 提交 91ff9109 编写于 作者: A Alberto Ricart 提交者: GitHub

feat(std): added TLS serve abilities to file_server (#6962)

上级 b344a7f8
......@@ -7,7 +7,13 @@
// https://github.com/indexzero/http-server/blob/master/test/http-server-test.js
import { posix, extname } from "../path/mod.ts";
import { listenAndServe, ServerRequest, Response } from "./server.ts";
import {
listenAndServe,
listenAndServeTLS,
ServerRequest,
Response,
HTTPSOptions,
} from "./server.ts";
import { parse } from "../flags/mod.ts";
import { assert } from "../_util/assert.ts";
......@@ -28,6 +34,14 @@ interface FileServerArgs {
// -h --help
h: boolean;
help: boolean;
// --host
host: string;
// -c --cert
c: string;
cert: string;
// -k --key
k: string;
key: string;
}
const encoder = new TextEncoder();
......@@ -49,6 +63,7 @@ const MEDIA_TYPES: Record<string, string> = {
".gz": "application/gzip",
".css": "text/css",
".wasm": "application/wasm",
".mjs": "application/javascript",
};
/** Returns the content-type based on the extension of a path. */
......@@ -306,7 +321,19 @@ function html(strings: TemplateStringsArray, ...values: unknown[]): string {
function main(): void {
const CORSEnabled = serverArgs.cors ? true : false;
const addr = `0.0.0.0:${serverArgs.port ?? serverArgs.p ?? 4507}`;
const port = serverArgs.port ?? serverArgs.p ?? 4507;
const host = serverArgs.host ?? "0.0.0.0";
const addr = `${host}:${port}`;
const tlsOpts = {} as HTTPSOptions;
tlsOpts.certFile = serverArgs.cert ?? serverArgs.c ?? "";
tlsOpts.keyFile = serverArgs.key ?? serverArgs.k ?? "";
if (tlsOpts.keyFile || tlsOpts.certFile) {
if (tlsOpts.keyFile === "" || tlsOpts.certFile === "") {
console.log("--key and --cert are required for TLS");
serverArgs.h = true;
}
}
if (serverArgs.h ?? serverArgs.help) {
console.log(`Deno File Server
......@@ -321,50 +348,62 @@ function main(): void {
OPTIONS:
-h, --help Prints help information
-p, --port <PORT> Set port
--cors Enable CORS via the "Access-Control-Allow-Origin" header`);
--cors Enable CORS via the "Access-Control-Allow-Origin" header
--host <HOST> Hostname (default is 0.0.0.0)
-c, --cert <FILE> TLS certificate file (enables TLS)
-k, --key <FILE> TLS key file (enables TLS)
All TLS options are required when one is provided.`);
Deno.exit();
}
listenAndServe(
addr,
async (req): Promise<void> => {
let normalizedUrl = posix.normalize(req.url);
try {
normalizedUrl = decodeURIComponent(normalizedUrl);
} catch (e) {
if (!(e instanceof URIError)) {
throw e;
}
const handler = async (req: ServerRequest): Promise<void> => {
let normalizedUrl = posix.normalize(req.url);
try {
normalizedUrl = decodeURIComponent(normalizedUrl);
} catch (e) {
if (!(e instanceof URIError)) {
throw e;
}
const fsPath = posix.join(target, normalizedUrl);
}
const fsPath = posix.join(target, normalizedUrl);
let response: Response | undefined;
let response: Response | undefined;
try {
const fileInfo = await Deno.stat(fsPath);
if (fileInfo.isDirectory) {
response = await serveDir(req, fsPath);
} else {
response = await serveFile(req, fsPath);
}
} catch (e) {
console.error(e.message);
response = await serveFallback(req, e);
} finally {
if (CORSEnabled) {
assert(response);
setCORS(response);
}
serverLog(req, response!);
try {
const fileInfo = await Deno.stat(fsPath);
if (fileInfo.isDirectory) {
response = await serveDir(req, fsPath);
} else {
response = await serveFile(req, fsPath);
}
await req.respond(response!);
} catch (e) {
console.error(e.message);
response = await serveFallback(req, e);
} finally {
if (CORSEnabled) {
assert(response);
setCORS(response);
}
serverLog(req, response!);
try {
await req.respond(response!);
} catch (e) {
console.error(e.message);
}
}
},
);
}
};
console.log(`HTTP server listening on http://${addr}/`);
let proto = "http";
if (tlsOpts.keyFile || tlsOpts.certFile) {
proto += "s";
tlsOpts.hostname = host;
tlsOpts.port = port;
listenAndServeTLS(tlsOpts, handler);
} else {
listenAndServe(addr, handler);
}
console.log(`${proto.toUpperCase()} server listening on ${proto}://${addr}/`);
}
if (import.meta.main) {
......
......@@ -199,3 +199,92 @@ Deno.test("file_server running as library", async function (): Promise<void> {
await killFileServer();
}
});
async function startTlsFileServer({
target = ".",
port = 4577,
}: FileServerCfg = {}): Promise<void> {
fileServer = Deno.run({
cmd: [
Deno.execPath(),
"run",
"--allow-read",
"--allow-net",
"http/file_server.ts",
target,
"--host",
"localhost",
"--cert",
"./http/testdata/tls/localhost.crt",
"--key",
"./http/testdata/tls/localhost.key",
"--cors",
"-p",
`${port}`,
],
stdout: "piped",
stderr: "null",
});
// Once fileServer is ready it will write to its stdout.
assert(fileServer.stdout != null);
const r = new TextProtoReader(new BufReader(fileServer.stdout));
const s = await r.readLine();
assert(s !== null && s.includes("server listening"));
}
Deno.test("serveDirectory TLS", async function (): Promise<void> {
await startTlsFileServer();
try {
// Valid request after invalid
const conn = await Deno.connectTls({
hostname: "localhost",
port: 4577,
certFile: "./http/testdata/tls/RootCA.pem",
});
await Deno.writeAll(
conn,
new TextEncoder().encode("GET /http HTTP/1.0\r\n\r\n"),
);
const res = new Uint8Array(128 * 1024);
const nread = await conn.read(res);
assert(nread !== null);
conn.close();
const page = new TextDecoder().decode(res.subarray(0, nread));
assert(page.includes("<title>Deno File Server</title>"));
} finally {
await killFileServer();
}
});
Deno.test("partial TLS arguments fail", async function (): Promise<void> {
fileServer = Deno.run({
cmd: [
Deno.execPath(),
"run",
"--allow-read",
"--allow-net",
"http/file_server.ts",
".",
"--host",
"localhost",
"--cert",
"./http/testdata/tls/localhost.crt",
"-p",
`4578`,
],
stdout: "piped",
stderr: "null",
});
try {
// Once fileServer is ready it will write to its stdout.
assert(fileServer.stdout != null);
const r = new TextProtoReader(new BufReader(fileServer.stdout));
const s = await r.readLine();
assert(
s !== null && s.includes("--key and --cert are required for TLS"),
);
} finally {
await killFileServer();
}
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册