forked from coder/code-server
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathstatic.ts
More file actions
73 lines (65 loc) · 2.6 KB
/
static.ts
File metadata and controls
73 lines (65 loc) · 2.6 KB
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
import { field, logger } from "@coder/logger"
import * as http from "http"
import * as path from "path"
import { Readable } from "stream"
import * as tarFs from "tar-fs"
import * as zlib from "zlib"
import { HttpProvider, HttpResponse, Route } from "../http"
import { pathToFsPath } from "../util"
/**
* Static file HTTP provider. Static requests do not require authentication if
* the resource is in the application's directory except requests to serve a
* directory as a tar which always requires authentication.
*/
export class StaticHttpProvider extends HttpProvider {
public async handleRequest(route: Route, request: http.IncomingMessage): Promise<HttpResponse> {
this.ensureMethod(request)
if (typeof route.query.tar === "string") {
this.ensureAuthenticated(request)
return this.getTarredResource(request, pathToFsPath(route.query.tar))
}
const response = await this.getReplacedResource(request, route)
if (!this.isDev) {
response.cache = true
}
return response
}
/**
* Return a resource with variables replaced where necessary.
*/
protected async getReplacedResource(request: http.IncomingMessage, route: Route): Promise<HttpResponse> {
// The first part is always the commit (for caching purposes).
const split = route.requestPath.split("/").slice(1)
const resourcePath = path.resolve("/", ...split)
// Make sure it's in code-server or a plugin.
const validPaths = [this.rootPath, process.env.PLUGIN_DIR]
if (!validPaths.find((p) => p && resourcePath.startsWith(p))) {
this.ensureAuthenticated(request)
}
switch (split[split.length - 1]) {
case "manifest.json": {
const response = await this.getUtf8Resource(resourcePath)
return this.replaceTemplates(route, response)
}
}
return this.getResource(resourcePath)
}
/**
* Tar up and stream a directory.
*/
private async getTarredResource(request: http.IncomingMessage, ...parts: string[]): Promise<HttpResponse> {
const filePath = path.join(...parts)
let stream: Readable = tarFs.pack(filePath)
const headers: http.OutgoingHttpHeaders = {}
if (request.headers["accept-encoding"] && request.headers["accept-encoding"].includes("gzip")) {
logger.debug("gzipping tar", field("filePath", filePath))
const compress = zlib.createGzip()
stream.pipe(compress)
stream.on("error", (error) => compress.destroy(error))
stream.on("close", () => compress.end())
stream = compress
headers["content-encoding"] = "gzip"
}
return { stream, filePath, mime: "application/x-tar", cache: true, headers }
}
}