diff --git a/ci/vscode.patch b/ci/vscode.patch index 2bd4971f..5014b67c 100644 --- a/ci/vscode.patch +++ b/ci/vscode.patch @@ -819,7 +819,7 @@ index 0000000000..0d2e93edae +} diff --git a/src/vs/server/browser/worker.ts b/src/vs/server/browser/worker.ts new file mode 100644 -index 0000000000..0ba93cc070 +index 0000000000..a93381631a --- /dev/null +++ b/src/vs/server/browser/worker.ts @@ -0,0 +1,57 @@ @@ -841,8 +841,8 @@ index 0000000000..0ba93cc070 + const fetchUri = URI.from({ + scheme: self.location.protocol.replace(':', ''), + authority: self.location.host, -+ path: `${self.location.pathname.replace(/\/static.*\/out\/vs\/workbench\/services\/extensions\/worker\/extensionHostWorkerMain.js$/, '')}/tar`, -+ query: `path=${encodeURIComponent(module.extensionLocation.path)}`, ++ path: self.location.pathname.replace(/\/static\/([^\/]+)\/.*$/, '/static/$1\/'), ++ query: `tar=${encodeURIComponent(module.extensionLocation.path)}`, + }); + const response = await fetch(fetchUri.toString(true)); + if (response.status !== 200) { diff --git a/src/node/app/static.ts b/src/node/app/static.ts index 93be8f40..676a99a8 100644 --- a/src/node/app/static.ts +++ b/src/node/app/static.ts @@ -1,13 +1,26 @@ +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" /** - * Static file HTTP provider. Static requests do not require authentication and - * they only allow access to resources within the application. + * Static file HTTP provider. Regular static requests (the path is the request + * itself) do not require authentication and they only allow access to resources + * within the application. Requests for tars (the path is in a query parameter) + * do require permissions and can access any directory. */ export class StaticHttpProvider extends HttpProvider { public async handleRequest(route: Route, request: http.IncomingMessage): Promise { this.ensureMethod(request) + + if (typeof route.query.tar === "string") { + this.ensureAuthenticated(request) + return this.getTarredResource(request, route.query.tar) + } + const response = await this.getReplacedResource(route) if (!this.isDev) { response.cache = true @@ -30,4 +43,23 @@ export class StaticHttpProvider extends HttpProvider { } return this.getResource(this.rootPath, ...split) } + + /** + * Tar up and stream a directory. + */ + private async getTarredResource(request: http.IncomingMessage, ...parts: string[]): Promise { + 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 } + } } diff --git a/src/node/app/vscode.ts b/src/node/app/vscode.ts index 4b3fda72..5759213c 100644 --- a/src/node/app/vscode.ts +++ b/src/node/app/vscode.ts @@ -155,11 +155,6 @@ export class VscodeHttpProvider extends HttpProvider { return this.getResource(route.query.path) } break - case "/tar": - if (typeof route.query.path === "string") { - return this.getTarredResource(request, route.query.path) - } - break case "/webview": if (/^\/vscode-resource/.test(route.requestPath)) { return this.getResource(route.requestPath.replace(/^\/vscode-resource(\/file)?/, "")) diff --git a/src/node/http.ts b/src/node/http.ts index c4cf25f6..077f0149 100644 --- a/src/node/http.ts +++ b/src/node/http.ts @@ -8,10 +8,8 @@ import * as path from "path" import * as querystring from "querystring" import safeCompare from "safe-compare" import { Readable } from "stream" -import * as tarFs from "tar-fs" import * as tls from "tls" import * as url from "url" -import * as zlib from "zlib" import { HttpCode, HttpError } from "../common/http" import { normalize, Options, plural, split } from "../common/util" import { SocketProxyProvider } from "./socket" @@ -233,25 +231,6 @@ export abstract class HttpProvider { return { content: await fs.readFile(filePath, "utf8"), filePath } } - /** - * Tar up and stream a directory. - */ - protected async getTarredResource(request: http.IncomingMessage, ...parts: string[]): Promise { - 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 } - } - /** * Helper to error on invalid methods (default GET). */