-
Notifications
You must be signed in to change notification settings - Fork 0
/
file-server.ts
81 lines (71 loc) · 1.81 KB
/
file-server.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import {
ServerRequest,
Response,
Status,
posix,
serve,
assert,
} from "./deps.ts";
import serveFile from "./serve-file.ts";
import serveFallback from "./serve-fallback.ts";
import setCORS from "./set-cors.ts";
export class FileServer {
readonly #param: Param;
#stop: boolean = false;
constructor(param: Param) {
this.#param = param;
}
public async start() {
this.#stop = false;
const server = serve({
port: this.#param.port,
hostname: this.#param.hostname,
});
for await (const req of server) {
if (this.#stop) break;
let normalizedUrl = posix.normalize(req.url);
try {
normalizedUrl = decodeURIComponent(normalizedUrl);
} catch (e) {
if (!(e instanceof URIError)) {
throw e;
}
}
const fsPath = posix.join(this.#param.target, normalizedUrl);
let response: Response | undefined;
try {
const info = await Deno.stat(fsPath);
if (info.isDirectory) {
response = {
status: Status.Forbidden,
body: "Cannot serve directory",
};
} else {
response = await serveFile(fsPath);
}
} catch (error) {
this.#param.onError?.(error);
response = await serveFallback(error);
} finally {
if (this.#param.cors) {
assert(response);
setCORS(response);
}
this.#param.onServe?.(req, response!);
req.respond(response!);
}
}
}
public stop() {
this.#stop = true;
}
}
export interface Param {
readonly onError?: (error: any) => void;
readonly onServe?: (request: ServerRequest, response: Response) => void;
readonly port: number;
readonly hostname?: string;
readonly target: string;
readonly cors: boolean;
}
export default FileServer;