Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 97bd72d

Browse files
committed
Refactor missing tar endpoint.
1 parent a845cfc commit 97bd72d

File tree

7 files changed

+94
-23
lines changed

7 files changed

+94
-23
lines changed

ci/dev/vscode.patch

+15-7
Original file line numberDiff line numberDiff line change
@@ -986,17 +986,17 @@ index 0000000000000000000000000000000000000000..5dd5406befcb593ad6366d9e98f46485
986986
+export const IExtHostNodeProxy = createDecorator<IExtHostNodeProxy>('IExtHostNodeProxy');
987987
diff --git a/src/vs/server/browser/mainThreadNodeProxy.ts b/src/vs/server/browser/mainThreadNodeProxy.ts
988988
new file mode 100644
989-
index 0000000000000000000000000000000000000000..21a139288e5b8f56016491879d69d01da929decb
989+
index 0000000000000000000000000000000000000000..e11988d1b3263c4a2ede064c653653b038c8238c
990990
--- /dev/null
991991
+++ b/src/vs/server/browser/mainThreadNodeProxy.ts
992-
@@ -0,0 +1,55 @@
992+
@@ -0,0 +1,63 @@
993993
+import { VSBuffer } from 'vs/base/common/buffer';
994994
+import { IDisposable } from 'vs/base/common/lifecycle';
995995
+import { FileAccess } from 'vs/base/common/network';
996996
+import { URI, UriComponents } from 'vs/base/common/uri';
997997
+import { INodeProxyService } from 'vs/server/common/nodeProxy';
998998
+import { ExtHostContext, IExtHostContext, MainContext, MainThreadNodeProxyShape } from 'vs/workbench/api/common/extHost.protocol';
999-
+import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
999+
+import {extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
10001000
+
10011001
+@extHostNamedCustomer(MainContext.MainThreadNodeProxy)
10021002
+export class MainThreadNodeProxy implements MainThreadNodeProxyShape {
@@ -1025,14 +1025,22 @@ index 0000000000000000000000000000000000000000..21a139288e5b8f56016491879d69d01d
10251025
+ }
10261026
+
10271027
+ async $fetchExtension(extensionUri: UriComponents): Promise<VSBuffer> {
1028+
+ // Use FileAccess to get the static base path.
1029+
+ const basePath = FileAccess.asBrowserUri("", require).path;
1030+
+
10281031
+ const fetchUri = URI.from({
10291032
+ scheme: window.location.protocol.replace(':', ''),
10301033
+ authority: window.location.host,
1031-
+ // Use FileAccess to get the static base path.
1032-
+ path: FileAccess.asBrowserUri("", require).path,
1033-
+ query: `tar=${encodeURIComponent(extensionUri.path)}`,
1034+
+ path: `${basePath}../../../extension/tar`,
1035+
+ query: `filePath=${encodeURIComponent(extensionUri.path)}`,
10341036
+ });
1035-
+ const response = await fetch(fetchUri.toString(true));
1037+
+
1038+
+ const response = await fetch(fetchUri.toString(true), {
1039+
+ headers: {
1040+
+ Accept: "application/x-tar, application/json;q=0.9"
1041+
+ }
1042+
+ });
1043+
+
10361044
+ if (response.status !== 200) {
10371045
+ throw new Error(`Failed to download extension "${module}"`);
10381046
+ }

src/browser/views/vscode/index.handlebars

+6-6
Original file line numberDiff line numberDiff line change
@@ -29,15 +29,15 @@
2929
<link rel="manifest" href="./code-server.webmanifest" crossorigin="use-credentials" />
3030

3131
{{#if (prod)}}
32-
<link data-name="vs/workbench/workbench.web.api" rel="stylesheet" href="{{assetPath base '/static/lib/vscode/out/vs/workbench/workbench.web.api.css'}}">
32+
<link data-name="vs/workbench/workbench.web.api" rel="stylesheet" href="{{assetPath base '/vscode/lib/vscode/out/vs/workbench/workbench.web.api.css'}}">
3333
{{/if}}
3434

3535
<link rel="apple-touch-icon" href="{{assetPath base '/static/media/pwa-icon-384.png'}}" />
3636
<meta name="apple-mobile-web-app-capable" content="yes" />
3737

3838
<!-- Prefetch to avoid waterfall -->
3939
{{#if (prod)}}
40-
<link rel="prefetch" href="{{assetPath base '/static/lib/vscode/node_modules/semver-umd/lib/semver-umd.js'}}">
40+
<link rel="prefetch" href="{{assetPath base '/vscode/lib/vscode/node_modules/semver-umd/lib/semver-umd.js'}}">
4141
{{/if}}
4242

4343
<meta id="coder-options" data-settings="{{{json coderOptions}}}" />
@@ -48,19 +48,19 @@
4848
<!-- Startup (do not modify order of script tags!) -->
4949
<script data-cfasync="false" src="{{assetPath base '/static/views/vscode/index.js'}}"></script>
5050
<script data-cfasync="false" src="{{assetPath base '/static/main.js'}}"></script>
51-
<script data-cfasync="false" src="{{assetPath base '/static/lib/vscode/out/vs/loader.js'}}"></script>
51+
<script data-cfasync="false" src="{{assetPath base '/vscode/lib/vscode/out/vs/loader.js'}}"></script>
5252

5353
<script>
5454
globalThis.MonacoPerformanceMarks.push("willLoadWorkbenchMain", Date.now());
5555
</script>
5656

5757
{{#if (prod)}}
58-
<script data-cfasync="false" src="{{assetPath base '/static/lib/vscode/out/vs/workbench/workbench.web.api.nls.js'}}"></script>
59-
<script data-cfasync="false" src="{{assetPath base '/static/lib/vscode/out/vs/workbench/workbench.web.api.js'}}"></script>
58+
<script data-cfasync="false" src="{{assetPath base '/vscode/lib/vscode/out/vs/workbench/workbench.web.api.nls.js'}}"></script>
59+
<script data-cfasync="false" src="{{assetPath base '/vscode/lib/vscode/out/vs/workbench/workbench.web.api.js'}}"></script>
6060
{{/if}}
6161

6262
<script>
63-
require.config({baseUrl: `${window.location.origin}/{{base}}/static/lib/vscode/out`});
63+
require.config({baseUrl: `${window.location.origin}/{{base}}/vscode/lib/vscode/out`});
6464
require(["vs/code/browser/workbench/workbench"], function () {});
6565
</script>
6666
</html>

src/browser/views/vscode/index.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ const initializeCodeServerEditor = () => {
7777

7878
const amdLoaderConfig: CodeServerAmdLoaderConfigurationOptions = {
7979
// Without the full URL VS Code will try to load file://.
80-
baseUrl: `${window.location.origin}${options.base}/static/lib/vscode/out`,
80+
baseUrl: `${window.location.origin}${options.base}/vscode/lib/vscode/out`,
8181
recordStats: true,
8282
paths: {
8383
"vscode-textmate": `../node_modules/vscode-textmate/release/main`,

src/node/app.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import * as httpolyglot from "httpolyglot"
88
import { resolve } from "path"
99
import { normalize } from "../common/util"
1010
import { DefaultedArgs } from "./cli"
11-
import { rootPath } from "./constants"
11+
import { commit, rootPath } from "./constants"
1212
import { handleUpgrade } from "./wsRouter"
1313

1414
/**
@@ -24,7 +24,7 @@ export const createApp = async (args: DefaultedArgs): Promise<[Express, Express,
2424
exphbs({
2525
defaultLayout: "",
2626
helpers: {
27-
prod: () => prod,
27+
prod: () => commit !== "development",
2828
assetPath: (base: string, path: string) => normalize(base + path),
2929
/**
3030
* Converts to JSON string and encodes entities for use in HTML.

src/node/routes/index.ts

+2-1
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,15 @@ export const register = async (
132132
}
133133

134134
const status = err.status ?? err.statusCode ?? 500
135+
const message = err.message || "An unknown server error occured"
135136

136137
try {
137138
res.status(status).render("error/index", {
138139
...commonTemplateVars(req),
139140
HOME_PATH: (typeof req.query.to === "string" && req.query.to) || "/",
140141
ERROR_TITLE: status,
141142
ERROR_HEADER: status,
142-
ERROR_BODY: err.message,
143+
ERROR_BODY: message,
143144
})
144145
} catch (error) {
145146
next(error)

src/node/routes/static.ts

+9-4
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,20 @@
1-
import { Router, static as _static } from "express"
1+
import { Router, static as createStaticRouteHandler } from "express"
22
import { resolve } from "path"
3-
import { rootPath } from "../constants"
3+
import { commit, rootPath } from "../constants"
44

55
export const router = Router()
66

77
const staticPaths: Record<string, string> = {
88
"/static": "dist",
9-
"/static/lib": "lib",
109
"/static/media": "src/browser/public/media",
1110
}
1211

1312
for (const [publicRoute, sourcePath] of Object.entries(staticPaths)) {
14-
router.use(publicRoute, _static(resolve(rootPath, sourcePath), { index: false }))
13+
router.use(
14+
publicRoute,
15+
createStaticRouteHandler(resolve(rootPath, sourcePath), {
16+
index: false,
17+
cacheControl: commit !== "development",
18+
}),
19+
)
1520
}

src/node/routes/vscode.ts

+59-2
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,16 @@
1+
import { field, logger } from "@coder/logger"
12
import * as crypto from "crypto"
2-
import { Router } from "express"
3+
import { RequestHandler, Router, static as createStaticRouteHandler } from "express"
34
import { promises as fs } from "fs"
45
import * as path from "path"
6+
import { resolve } from "path"
7+
import { ParsedQs } from "qs"
8+
import { Readable } from "stream"
9+
import * as tarFs from "tar-fs"
10+
import * as zlib from "zlib"
511
import { WorkbenchOptions } from "../../../lib/vscode/src/vs/server/ipc"
6-
import { commit, version } from "../constants"
12+
import { HttpCode, HttpError } from "../../common/http"
13+
import { commit, rootPath, version } from "../constants"
714
import { authenticated, commonTemplateVars, ensureAuthenticated, redirect } from "../http"
815
import { getMediaMime, pathToFsPath } from "../util"
916
import { VscodeProvider } from "../vscode"
@@ -96,3 +103,53 @@ wsRouter.ws("/", ensureAuthenticated, async (req) => {
96103
)
97104
await vscode.sendWebsocket(req.ws, req.query)
98105
})
106+
router.use(
107+
"/lib",
108+
createStaticRouteHandler(resolve(rootPath, "lib"), {
109+
index: false,
110+
cacheControl: commit !== "development",
111+
}),
112+
)
113+
114+
interface TarHandlerQueryParams extends ParsedQs {
115+
filePath?: string | string[]
116+
}
117+
118+
/**
119+
* Packs and serves requested file with tar.
120+
* This is commonly used to fetch an extension on the client.
121+
*
122+
* @remark See lib/vscode/src/vs/server/browser/mainThreadNodeProxy.ts#L35
123+
*/
124+
const tarHandler: RequestHandler<any, Buffer, null, TarHandlerQueryParams> = (req, res) => {
125+
const filePath = Array.isArray(req.query.filePath) ? req.query.filePath[0] : req.query.filePath
126+
127+
if (!filePath) {
128+
throw new HttpError("Missing 'filePath' query param", HttpCode.BadRequest)
129+
}
130+
131+
const resourcePath = resolve(filePath)
132+
133+
let stream: Readable = tarFs.pack(pathToFsPath(filePath))
134+
135+
if (req.headers["accept-encoding"] && req.headers["accept-encoding"].includes("gzip")) {
136+
logger.debug("gzipping tar", field("path", resourcePath))
137+
138+
const compress = zlib.createGzip()
139+
140+
stream.pipe(compress)
141+
stream.on("error", (error) => compress.destroy(error))
142+
stream.on("close", () => compress.end())
143+
144+
stream = compress
145+
146+
res.header("content-encoding", "gzip")
147+
}
148+
149+
res.set("Content-Type", "application/x-tar")
150+
stream.on("close", () => res.end())
151+
152+
return stream.pipe(res)
153+
}
154+
155+
router.get("/extension/tar", tarHandler)

0 commit comments

Comments
 (0)