Skip to content

Commit f8635a1

Browse files
committed
Add tar endpoint
This will be used to load extensions into the browser using requirefs.
1 parent c3c50e9 commit f8635a1

File tree

3 files changed

+61
-6
lines changed

3 files changed

+61
-6
lines changed

package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
"@coder/nbin": "^1.2.0",
1818
"@types/pem": "^1.9.5",
1919
"@types/safe-compare": "^1.1.0",
20+
"@types/tar-fs": "^1.16.1",
2021
"@types/tar-stream": "^1.6.1",
2122
"nodemon": "^1.19.1"
2223
},
@@ -29,6 +30,7 @@
2930
"httpolyglot": "^0.1.2",
3031
"pem": "^1.14.2",
3132
"safe-compare": "^1.1.4",
33+
"tar-fs": "^2.0.0",
3234
"tar-stream": "^2.1.0"
3335
}
3436
}

src/server.ts

Lines changed: 31 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import * as https from "https";
55
import * as net from "net";
66
import * as path from "path";
77
import * as querystring from "querystring";
8+
import { Readable } from "stream";
89
import * as tls from "tls";
910
import * as url from "url";
1011
import * as util from "util";
@@ -67,6 +68,8 @@ import { AuthType, getMediaMime, getUriTransformer, localRequire, tmpdir } from
6768
import { RemoteExtensionLogFileName } from "vs/workbench/services/remote/common/remoteAgentService";
6869
import { IWorkbenchConstructionOptions } from "vs/workbench/workbench.web.api";
6970

71+
const tarFs = localRequire<typeof import("tar-fs")>("tar-fs/index");
72+
7073
export enum HttpCode {
7174
Ok = 200,
7275
Redirect = 302,
@@ -89,7 +92,9 @@ export interface Response {
8992
content?: string | Buffer;
9093
filePath?: string;
9194
headers?: http.OutgoingHttpHeaders;
95+
mime?: string;
9296
redirect?: string;
97+
stream?: Readable;
9398
}
9499

95100
export interface LoginPayload {
@@ -185,11 +190,21 @@ export abstract class Server {
185190
): Promise<Response>;
186191

187192
protected async getResource(...parts: string[]): Promise<Response> {
193+
const filePath = this.ensureAuthorizedFilePath(...parts);
194+
return { content: await util.promisify(fs.readFile)(filePath), filePath };
195+
}
196+
197+
protected async getTarredResource(...parts: string[]): Promise<Response> {
198+
const filePath = this.ensureAuthorizedFilePath(...parts);
199+
return { stream: tarFs.pack(filePath), filePath, mime: "application/tar" };
200+
}
201+
202+
protected ensureAuthorizedFilePath(...parts: string[]): string {
188203
const filePath = path.join(...parts);
189204
if (!this.isAllowedRequestPath(filePath)) {
190205
throw new HttpError("Unauthorized", HttpCode.Unauthorized);
191206
}
192-
return { content: await util.promisify(fs.readFile)(filePath), filePath };
207+
return filePath;
193208
}
194209

195210
protected withBase(request: http.IncomingMessage, path: string): string {
@@ -211,13 +226,21 @@ export abstract class Server {
211226
const parsedUrl = request.url ? url.parse(request.url, true) : { query: {}};
212227
const payload = await this.preHandleRequest(request, parsedUrl);
213228
response.writeHead(payload.redirect ? HttpCode.Redirect : payload.code || HttpCode.Ok, {
214-
"Content-Type": getMediaMime(payload.filePath),
229+
"Content-Type": payload.mime || getMediaMime(payload.filePath),
215230
...(payload.redirect ? { Location: this.withBase(request, payload.redirect) } : {}),
216231
...(request.headers["service-worker"] ? { "Service-Worker-Allowed": this.options.basePath || "/" } : {}),
217232
...(payload.cache ? { "Cache-Control": "public, max-age=31536000" } : {}),
218233
...payload.headers,
219234
});
220-
response.end(payload.content);
235+
if (payload.stream) {
236+
payload.stream.on("error", (error: NodeJS.ErrnoException) => {
237+
response.writeHead(error.code === "ENOENT" ? HttpCode.NotFound : HttpCode.ServerError);
238+
response.end(error.message);
239+
});
240+
payload.stream.pipe(response);
241+
} else {
242+
response.end(payload.content);
243+
}
221244
} catch (error) {
222245
if (error.code === "ENOENT" || error.code === "EISDIR") {
223246
error = new HttpError("Not found", HttpCode.NotFound);
@@ -484,6 +507,11 @@ export class MainServer extends Server {
484507
return this.getResource(parsedUrl.query.path);
485508
}
486509
break;
510+
case "/tar":
511+
if (typeof parsedUrl.query.path === "string") {
512+
return this.getTarredResource(parsedUrl.query.path);
513+
}
514+
break;
487515
case "/webview":
488516
if (requestPath.indexOf("/vscode-resource") === 0) {
489517
return this.getResource(requestPath.replace(/^\/vscode-resource/, ""));

yarn.lock

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,13 @@
3535
resolved "https://registry.yarnpkg.com/@types/safe-compare/-/safe-compare-1.1.0.tgz#47ed9b9ca51a3a791b431cd59b28f47fa9bf1224"
3636
integrity sha512-1ri+LJhh0gRxIa37IpGytdaW7yDEHeJniBSMD1BmitS07R1j63brcYCzry+l0WJvGdEKQNQ7DYXO2epgborWPw==
3737

38+
"@types/tar-fs@^1.16.1":
39+
version "1.16.1"
40+
resolved "https://registry.yarnpkg.com/@types/tar-fs/-/tar-fs-1.16.1.tgz#6e3fba276c173e365ae91e55f7b797a0e64298e5"
41+
integrity sha512-uQQIaa8ukcKf/1yy2kzfP1PF+7jEZghFDKpDvgtsYo/mbqM1g4Qza1Y5oAw6kJMa7eLA/HkmxUsDqb2sWKVF9g==
42+
dependencies:
43+
"@types/node" "*"
44+
3845
"@types/tar-stream@^1.6.1":
3946
version "1.6.1"
4047
resolved "https://registry.yarnpkg.com/@types/tar-stream/-/tar-stream-1.6.1.tgz#67d759068ff781d976cad978893bb7a334ec8809"
@@ -480,7 +487,7 @@ duplexer3@^0.1.4:
480487
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
481488
integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
482489

483-
end-of-stream@^1.4.1:
490+
end-of-stream@^1.1.0, end-of-stream@^1.4.1:
484491
version "1.4.1"
485492
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
486493
integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==
@@ -1293,7 +1300,7 @@ object.pick@^1.3.0:
12931300
dependencies:
12941301
isobject "^3.0.1"
12951302

1296-
once@^1.3.0, once@^1.4.0:
1303+
once@^1.3.0, once@^1.3.1, once@^1.4.0:
12971304
version "1.4.0"
12981305
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
12991306
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
@@ -1417,6 +1424,14 @@ pstree.remy@^1.1.6:
14171424
resolved "https://registry.yarnpkg.com/pstree.remy/-/pstree.remy-1.1.7.tgz#c76963a28047ed61542dc361aa26ee55a7fa15f3"
14181425
integrity sha512-xsMgrUwRpuGskEzBFkH8NmTimbZ5PcPup0LA8JJkHIm2IMUbQcpo3yeLNWVrufEYjh8YwtSVh0xz6UeWc5Oh5A==
14191426

1427+
pump@^3.0.0:
1428+
version "3.0.0"
1429+
resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64"
1430+
integrity sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==
1431+
dependencies:
1432+
end-of-stream "^1.1.0"
1433+
once "^1.3.1"
1434+
14201435
rc@^1.0.1, rc@^1.1.6, rc@^1.2.7:
14211436
version "1.2.8"
14221437
resolved "https://registry.yarnpkg.com/rc/-/rc-1.2.8.tgz#cd924bf5200a075b83c188cd6b9e211b7fc0d3ed"
@@ -1744,7 +1759,17 @@ supports-color@^5.2.0, supports-color@^5.3.0:
17441759
dependencies:
17451760
has-flag "^3.0.0"
17461761

1747-
tar-stream@^2.1.0:
1762+
tar-fs@^2.0.0:
1763+
version "2.0.0"
1764+
resolved "https://registry.yarnpkg.com/tar-fs/-/tar-fs-2.0.0.tgz#677700fc0c8b337a78bee3623fdc235f21d7afad"
1765+
integrity sha512-vaY0obB6Om/fso8a8vakQBzwholQ7v5+uy+tF3Ozvxv1KNezmVQAiWtcNmMHFSFPqL3dJA8ha6gdtFbfX9mcxA==
1766+
dependencies:
1767+
chownr "^1.1.1"
1768+
mkdirp "^0.5.1"
1769+
pump "^3.0.0"
1770+
tar-stream "^2.0.0"
1771+
1772+
tar-stream@^2.0.0, tar-stream@^2.1.0:
17481773
version "2.1.0"
17491774
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.0.tgz#d1aaa3661f05b38b5acc9b7020efdca5179a2cc3"
17501775
integrity sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==

0 commit comments

Comments
 (0)