Target a recent commit for VS Code

This is so we can try out the web worker extension host.
This commit is contained in:
Asher 2019-08-29 19:05:48 -05:00
parent 624a4c08b9
commit b901043bfc
No known key found for this signature in database
GPG key ID: D63C1EF81242354A
12 changed files with 443 additions and 580 deletions

View file

@ -8,14 +8,14 @@ matrix:
- os: linux - os: linux
dist: trusty dist: trusty
env: env:
- VSCODE_VERSION="1.37.0" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER" TARGET="linux" - VSCODE_VERSION="20dd80d91a76cbe80fb1d1979c3a9f02d94ba161" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER" TARGET="linux"
- os: linux - os: linux
dist: trusty dist: trusty
env: env:
- VSCODE_VERSION="1.37.0" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER" TARGET="alpine" - VSCODE_VERSION="20dd80d91a76cbe80fb1d1979c3a9f02d94ba161" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER" TARGET="alpine"
- os: osx - os: osx
env: env:
- VSCODE_VERSION="1.37.0" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER" - VSCODE_VERSION="20dd80d91a76cbe80fb1d1979c3a9f02d94ba161" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER"
before_install: before_install:
- if [[ "$TRAVIS_BRANCH" == "master" ]]; then export MINIFY="true"; fi - if [[ "$TRAVIS_BRANCH" == "master" ]]; then export MINIFY="true"; fi
- if [[ "$TRAVIS_BRANCH" == "master" ]]; then export PACKAGE="true"; fi - if [[ "$TRAVIS_BRANCH" == "master" ]]; then export PACKAGE="true"; fi

View file

@ -81,7 +81,7 @@ data collected to improve code-server.
```shell ```shell
git clone https://github.com/microsoft/vscode git clone https://github.com/microsoft/vscode
cd vscode cd vscode
git checkout 1.37.0 git checkout <see travis.yml for the VS Code version to use here>
git clone https://github.com/cdr/code-server src/vs/server git clone https://github.com/cdr/code-server src/vs/server
cd src/vs/server cd src/vs/server
yarn patch:apply yarn patch:apply
@ -98,30 +98,28 @@ If you run into issues about a different version of Node being used, try running
`vscode-ripgrep`. `vscode-ripgrep`.
### Upgrading VS Code ### Upgrading VS Code
We have to patch VS Code to provide and fix some functionality. As the web We patch VS Code to provide and fix some functionality. As the web portion of VS
portion of VS Code matures, we'll be able to shrink and maybe even entirely Code matures, we'll be able to shrink and maybe even entirely eliminate our
eliminate our patch. In the meantime, however, upgrading the VS Code version patch. In the meantime, however, upgrading the VS Code version requires ensuring
requires ensuring that the patch still applies and has the intended effects. that the patch still applies and has the intended effects.
To generate a new patch, **stage all the changes** you want to be included in To generate a new patch, **stage all the changes** you want to be included in
the patch in the VS Code source, then run `yarn patch:generate` in this the patch in the VS Code source, then run `yarn patch:generate` in this
directory. directory.
Our changes include: Our changes include:
- Add a `code-server` schema. - Change the remote schema to `code-server`.
- Allow multiple extension directories (both user and built-in). - Allow multiple extension directories (both user and built-in).
- Modify the loader, websocket, webview, service worker, and asset requests to - Modify the loader, websocket, webview, service worker, and asset requests to
use the URL of the page as a base (and TLS if necessary for the websocket). use the URL of the page as a base (and TLS if necessary for the websocket).
- Send client-side telemetry through the server. - Send client-side telemetry through the server and get the initial log level
- Add a file prefix to ignore for temporary files created during upload. from the server.
- Insert our upload service for use in editor windows and explorer. - Add an upload service for use in editor windows and the explorer along with a
- Modify the log level to get its initial setting from the server. file prefix to ignore for temporary files created during upload.
- Change a regular expression used for mnemonics so it works on Firefox. - Make changing the display language work.
- Make hiding or toggling the menu bar possible.
- Make it possible for us to load code on the client. - Make it possible for us to load code on the client.
- Modify the build process to include our code. - Modify the build process to include our code.
- Fix a CSP issue within webviews.
- Fix an issue displaying extension contributions.
- Make changing the display language work.
## License ## License
[MIT](LICENSE) [MIT](LICENSE)

View file

@ -133,7 +133,7 @@ function build-task() {
mkdir -p "${stagingPath}" mkdir -p "${stagingPath}"
if [[ ! -d "${sourcePath}" ]] ; then if [[ ! -d "${sourcePath}" ]] ; then
if ! download-pre-built "vscode-${vscodeVersion}.tar.gz" ; then if ! download-pre-built "vscode-${vscodeVersion}.tar.gz" ; then
git clone https://github.com/microsoft/vscode --quiet \ git clone https://github.com/microsoft/vscode --quiet \
--branch "${vscodeVersion}" --single-branch --depth=1 \ --branch "${vscodeVersion}" --single-branch --depth=1 \
"${sourcePath}" "${sourcePath}"
fi fi

File diff suppressed because it is too large Load diff

View file

@ -6,7 +6,7 @@ import { OS } from "vs/base/common/platform";
import { URI, UriComponents } from "vs/base/common/uri"; import { URI, UriComponents } from "vs/base/common/uri";
import { transformOutgoingURIs } from "vs/base/common/uriIpc"; import { transformOutgoingURIs } from "vs/base/common/uriIpc";
import { IServerChannel } from "vs/base/parts/ipc/common/ipc"; import { IServerChannel } from "vs/base/parts/ipc/common/ipc";
import { IDiagnosticInfo } from "vs/platform/diagnostics/common/diagnosticsService"; import { IDiagnosticInfo } from "vs/platform/diagnostics/common/diagnostics";
import { IEnvironmentService } from "vs/platform/environment/common/environment"; import { IEnvironmentService } from "vs/platform/environment/common/environment";
import { ExtensionIdentifier, IExtensionDescription } from "vs/platform/extensions/common/extensions"; import { ExtensionIdentifier, IExtensionDescription } from "vs/platform/extensions/common/extensions";
import { FileDeleteOptions, FileOpenOptions, FileOverwriteOptions, FileType, IStat, IWatchOptions } from "vs/platform/files/common/files"; import { FileDeleteOptions, FileOpenOptions, FileOverwriteOptions, FileType, IStat, IWatchOptions } from "vs/platform/files/common/files";
@ -163,11 +163,10 @@ export class FileProviderChannel implements IServerChannel, IDisposable {
} }
private transform(resource: UriComponents): URI { private transform(resource: UriComponents): URI {
// HACK: for now assume /out is relative to the build (used for the // Used for walkthrough content.
// walkthrough content). if (resource.path.indexOf("/static") === 0) {
if (resource.path.indexOf("/out") === 0) { return URI.file(this.environmentService.appRoot + resource.path.replace(/^\/static/, ""));
return URI.file(this.environmentService.appRoot + resource.path); // Used by the webview service worker to load resources.
// This is used by the webview service worker to load resources.
} else if (resource.path === "/vscode-resource" && resource.query) { } else if (resource.path === "/vscode-resource" && resource.query) {
try { try {
const query = JSON.parse(resource.query); const query = JSON.parse(resource.query);
@ -185,6 +184,7 @@ export class ExtensionEnvironmentChannel implements IServerChannel {
private readonly environment: IEnvironmentService, private readonly environment: IEnvironmentService,
private readonly log: ILogService, private readonly log: ILogService,
private readonly telemetry: ITelemetryService, private readonly telemetry: ITelemetryService,
private readonly connectionToken: string,
) {} ) {}
public listen(_: unknown, event: string): Event<any> { public listen(_: unknown, event: string): Event<any> {
@ -207,6 +207,7 @@ export class ExtensionEnvironmentChannel implements IServerChannel {
private async getEnvironmentData(locale: string): Promise<IRemoteAgentEnvironment> { private async getEnvironmentData(locale: string): Promise<IRemoteAgentEnvironment> {
return { return {
pid: process.pid, pid: process.pid,
connectionToken: this.connectionToken,
appRoot: URI.file(this.environment.appRoot), appRoot: URI.file(this.environment.appRoot),
appSettingsHome: this.environment.appSettingsHome, appSettingsHome: this.environment.appSettingsHome,
settingsPath: this.environment.machineSettingsHome, settingsPath: this.environment.machineSettingsHome,

View file

@ -7,6 +7,7 @@ import { LocalizationsService } from "vs/platform/localizations/electron-browser
import { IUpdateService } from "vs/platform/update/common/update"; import { IUpdateService } from "vs/platform/update/common/update";
import { UpdateService } from "vs/platform/update/electron-browser/updateService"; import { UpdateService } from "vs/platform/update/electron-browser/updateService";
import { TelemetryChannelClient } from "vs/server/src/telemetry"; import { TelemetryChannelClient } from "vs/server/src/telemetry";
import { IUploadService, UploadService } from 'vs/server/src/upload';
import { IRemoteAgentService } from "vs/workbench/services/remote/common/remoteAgentService"; import { IRemoteAgentService } from "vs/workbench/services/remote/common/remoteAgentService";
class TelemetryService extends TelemetryChannelClient { class TelemetryService extends TelemetryChannelClient {
@ -18,12 +19,13 @@ class TelemetryService extends TelemetryChannelClient {
} }
registerSingleton(ILocalizationsService, LocalizationsService); registerSingleton(ILocalizationsService, LocalizationsService);
registerSingleton(IUpdateService, UpdateService);
registerSingleton(ITelemetryService, TelemetryService); registerSingleton(ITelemetryService, TelemetryService);
registerSingleton(IUpdateService, UpdateService);
registerSingleton(IUploadService, UploadService, true);
import "vs/workbench/contrib/update/electron-browser/update.contribution"; import "vs/workbench/contrib/update/electron-browser/update.contribution";
import 'vs/workbench/contrib/localizations/browser/localizations.contribution';
import "vs/css!./media/firefox";
import { coderApi, vscodeApi } from "vs/server/src/api"; import { coderApi, vscodeApi } from "vs/server/src/api";
/** /**

View file

@ -1,104 +1,12 @@
<!DOCTYPE html> <!DOCTYPE html>
<html lang="en"> <html lang="en">
<head> <head>
<meta name="viewport" content="width=device-width, initial-scale=1, minimum-scale=1, maximum-scale=1"> <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0, user-scalable=no">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; style-src 'self' 'unsafe-inline'; script-src 'unsafe-inline'; manifest-src 'self'; img-src 'self';">
<title>Authenticate: code-server</title> <title>Authenticate: code-server</title>
<style> <link rel="icon" href="./favicon.ico" type="image/x-icon" />
html { <link rel="manifest" href="./manifest.json">
box-sizing: border-box; <link href="./static/out/vs/server/src/media/login.css" rel="stylesheet">
}
*, *:before, *:after {
box-sizing: inherit;
}
html, body {
background-color: #FFFFFF;
height: 100%;
min-height: 100%;
}
body {
align-items: center;
display: flex;
font-family: "monospace";
justify-content: center;
margin: 0;
padding: 10px;
}
.login-form {
border-radius: 5px;
box-shadow: 0 18px 80px 10px rgba(69, 65, 78, 0.08);
color: #575962;
margin-top: -10%;
max-width: 328px;
padding: 40px;
position: relative;
width: 100%;
}
.login-form > .title {
text-align: center;
text-transform: uppercase;
font-size: 12px;
font-weight: 500;
letter-spacing: 1.5px;
line-height: 15px;
margin-bottom: 0px;
margin-bottom: 5px;
margin-top: 0px;
}
.login-form > .subtitle {
font-size: 19px;
font-weight: bold;
line-height: 25px;
margin-bottom: 45px;
margin: 0;
text-align: center;
}
.login-form > .field {
text-align: left;
font-size: 12px;
color: #797E84;
margin: 16px 0;
}
.login-form > .field > .input {
background: none !important;
border: 1px solid #ccc;
border-radius: 2px;
padding: 5px;
width: 100%;
}
.login-form > .button {
border: none;
border-radius: 24px;
box-shadow: 0 12px 17px 2px rgba(171,173,163,0.14), 0 5px 22px 4px rgba(171,173,163,0.12), 0 7px 8px -4px rgba(171,173,163,0.2);
cursor: pointer;
display: block;
padding: 15px 5px;
width: 100%;
}
.login-form > .button:hover {
background-color: rgb(0, 122, 204);
color: #fff;
}
.error-display {
box-sizing: border-box;
color: #bb2d0f;
font-size: 14px;
font-weight: 400;
line-height: 12px;
padding: 20px 8px 0;
text-align: center;
}
</style>
</head> </head>
<body> <body>
<form class="login-form" method="post"> <form class="login-form" method="post">

View file

Before

Width:  |  Height:  |  Size: 2 KiB

After

Width:  |  Height:  |  Size: 2 KiB

View file

@ -1,14 +0,0 @@
@supports (-moz-appearance:none) {
/* Firefox doesn't support -webkit-margin-{before/after} so use margin. */
/* These are the collapsible section headings in a sidebar panel. */
.monaco-panel-view .panel > .panel-header h3.title {
margin-bottom: 0;
margin-top: 0;
}
/* Firefox doesn't seem to support fit-content. */
/* These are the file tabs. */
.monaco-workbench .part.editor > .content .editor-group-container > .title .tabs-container > .tab.sizing-fit {
min-width: -moz-fit-content;
}
}

94
src/media/login.css Normal file
View file

@ -0,0 +1,94 @@
html {
box-sizing: border-box;
}
*, *:before, *:after {
box-sizing: inherit;
}
html, body {
background-color: #FFFFFF;
height: 100%;
min-height: 100%;
}
body {
align-items: center;
display: flex;
font-family: "monospace";
justify-content: center;
margin: 0;
padding: 10px;
}
.login-form {
border-radius: 5px;
box-shadow: 0 18px 80px 10px rgba(69, 65, 78, 0.08);
color: #575962;
margin-top: -10%;
max-width: 328px;
padding: 40px;
position: relative;
width: 100%;
}
.login-form > .title {
text-align: center;
text-transform: uppercase;
font-size: 12px;
font-weight: 500;
letter-spacing: 1.5px;
line-height: 15px;
margin-bottom: 0px;
margin-bottom: 5px;
margin-top: 0px;
}
.login-form > .subtitle {
font-size: 19px;
font-weight: bold;
line-height: 25px;
margin-bottom: 45px;
margin: 0;
text-align: center;
}
.login-form > .field {
text-align: left;
font-size: 12px;
color: #797E84;
margin: 16px 0;
}
.login-form > .field > .input {
background: none !important;
border: 1px solid #ccc;
border-radius: 2px;
padding: 5px;
width: 100%;
}
.login-form > .button {
border: none;
border-radius: 24px;
box-shadow: 0 12px 17px 2px rgba(171,173,163,0.14), 0 5px 22px 4px rgba(171,173,163,0.12), 0 7px 8px -4px rgba(171,173,163,0.2);
cursor: pointer;
display: block;
padding: 15px 5px;
width: 100%;
}
.login-form > .button:hover {
background-color: rgb(0, 122, 204);
color: #fff;
}
.error-display {
box-sizing: border-box;
color: #bb2d0f;
font-size: 14px;
font-weight: 400;
line-height: 12px;
padding: 20px 8px 0;
text-align: center;
}

13
src/media/manifest.json Normal file
View file

@ -0,0 +1,13 @@
{
"name": "code-server",
"short_name": "code-server",
"start_url": ".",
"display": "standalone",
"background-color": "#fff",
"description": "Run VS Code on a remote server.",
"icons": [{
"src": "static/code-server.png",
"sizes": "128x128",
"type": "image/png"
}]
}

View file

@ -41,10 +41,9 @@ import { LocalizationsChannel } from "vs/platform/localizations/node/localizatio
import { getLogLevel, ILogService } from "vs/platform/log/common/log"; import { getLogLevel, ILogService } from "vs/platform/log/common/log";
import { LogLevelSetterChannel } from "vs/platform/log/common/logIpc"; import { LogLevelSetterChannel } from "vs/platform/log/common/logIpc";
import { SpdLogService } from "vs/platform/log/node/spdlogService"; import { SpdLogService } from "vs/platform/log/node/spdlogService";
import { IProductConfiguration, IProductService } from "vs/platform/product/common/product"; import { IProductService } from "vs/platform/product/common/product";
import pkg from "vs/platform/product/node/package"; import pkg from "vs/platform/product/node/package";
import product from "vs/platform/product/node/product"; import product from "vs/platform/product/node/product";
import { ProductService } from "vs/platform/product/node/productService";
import { ConnectionType, ConnectionTypeRequest } from "vs/platform/remote/common/remoteAgentConnection"; import { ConnectionType, ConnectionTypeRequest } from "vs/platform/remote/common/remoteAgentConnection";
import { REMOTE_FILE_SYSTEM_CHANNEL_NAME } from "vs/platform/remote/common/remoteAgentFileSystemChannel"; import { REMOTE_FILE_SYSTEM_CHANNEL_NAME } from "vs/platform/remote/common/remoteAgentFileSystemChannel";
import { IRequestService } from "vs/platform/request/common/request"; import { IRequestService } from "vs/platform/request/common/request";
@ -81,8 +80,6 @@ export enum HttpCode {
export interface Options { export interface Options {
WORKBENCH_WEB_CONGIGURATION: IWorkbenchConstructionOptions; WORKBENCH_WEB_CONGIGURATION: IWorkbenchConstructionOptions;
REMOTE_USER_DATA_URI: UriComponents | URI; REMOTE_USER_DATA_URI: UriComponents | URI;
PRODUCT_CONFIGURATION: IProductConfiguration | null;
CONNECTION_AUTH_TOKEN: string;
NLS_CONFIGURATION: NLSConfiguration; NLS_CONFIGURATION: NLSConfiguration;
} }
@ -110,6 +107,7 @@ export class HttpError extends Error {
export interface ServerOptions { export interface ServerOptions {
readonly auth?: AuthType; readonly auth?: AuthType;
readonly basePath?: string; readonly basePath?: string;
readonly connectionToken?: string;
readonly cert?: string; readonly cert?: string;
readonly certKey?: string; readonly certKey?: string;
readonly folderUri?: string; readonly folderUri?: string;
@ -122,6 +120,8 @@ export interface ServerOptions {
export abstract class Server { export abstract class Server {
protected readonly server: http.Server | https.Server; protected readonly server: http.Server | https.Server;
protected rootPath = path.resolve(__dirname, "../../../.."); protected rootPath = path.resolve(__dirname, "../../../..");
protected serverRoot = path.join(this.rootPath, "/out/vs/server/src");
protected readonly allowedRequestPaths: string[] = [this.rootPath];
private listenPromise: Promise<string> | undefined; private listenPromise: Promise<string> | undefined;
public readonly protocol: "http" | "https"; public readonly protocol: "http" | "https";
public readonly options: ServerOptions; public readonly options: ServerOptions;
@ -185,6 +185,9 @@ export abstract class Server {
protected async getResource(...parts: string[]): Promise<Response> { protected async getResource(...parts: string[]): Promise<Response> {
const filePath = path.join(...parts); const filePath = path.join(...parts);
if (!this.isAllowedRequestPath(filePath)) {
throw new HttpError("Unauthorized", HttpCode.Unauthorized);
}
return { content: await util.promisify(fs.readFile)(filePath), filePath }; return { content: await util.promisify(fs.readFile)(filePath), filePath };
} }
@ -193,10 +196,20 @@ export abstract class Server {
return `${this.protocol}://${request.headers.host}${this.options.basePath}${path}${split.length === 2 ? `?${split[1]}` : ""}`; return `${this.protocol}://${request.headers.host}${this.options.basePath}${path}${split.length === 2 ? `?${split[1]}` : ""}`;
} }
private isAllowedRequestPath(path: string): boolean {
for (let i = 0; i < this.allowedRequestPaths.length; ++i) {
if (path.indexOf(this.allowedRequestPaths[i]) === 0) {
return true;
}
}
return false;
}
private onRequest = async (request: http.IncomingMessage, response: http.ServerResponse): Promise<void> => { private onRequest = async (request: http.IncomingMessage, response: http.ServerResponse): Promise<void> => {
try { try {
const payload = await this.preHandleRequest(request); const payload = await this.preHandleRequest(request);
response.writeHead(payload.redirect ? HttpCode.Redirect : payload.code || HttpCode.Ok, { response.writeHead(payload.redirect ? HttpCode.Redirect : payload.code || HttpCode.Ok, {
// "Cache-Control": "public, max-age=31536000",
"Content-Type": getMediaMime(payload.filePath), "Content-Type": getMediaMime(payload.filePath),
...(payload.redirect ? { Location: this.withBase(request, payload.redirect) } : {}), ...(payload.redirect ? { Location: this.withBase(request, payload.redirect) } : {}),
...(request.headers["service-worker"] ? { "Service-Worker-Allowed": this.options.basePath || "/" } : {}), ...(request.headers["service-worker"] ? { "Service-Worker-Allowed": this.options.basePath || "/" } : {}),
@ -233,25 +246,29 @@ export abstract class Server {
base = path.normalize(base); base = path.normalize(base);
requestPath = path.normalize(requestPath || "/index.html"); requestPath = path.normalize(requestPath || "/index.html");
if (base !== "/login" || !this.options.auth || requestPath !== "/index.html") {
this.ensureGet(request);
}
switch (base) { switch (base) {
case "/": case "/":
this.ensureGet(request); switch (requestPath) {
if (requestPath === "/favicon.ico") { case "/favicon.ico":
return this.getResource(this.rootPath, "/out/vs/server/src/favicon", requestPath); case "/manifest.json":
} else if (!this.authenticate(request)) { return this.getResource(this.serverRoot, "media", requestPath);
}
if (!this.authenticate(request)) {
return { redirect: "/login" }; return { redirect: "/login" };
} }
break; break;
case "/static":
return this.getResource(this.rootPath, requestPath);
case "/login": case "/login":
if (!this.options.auth) { if (!this.options.auth || requestPath !== "/index.html") {
throw new HttpError("Not found", HttpCode.NotFound); throw new HttpError("Not found", HttpCode.NotFound);
} else if (requestPath === "/index.html") {
return this.tryLogin(request);
} }
this.ensureGet(request); return this.tryLogin(request);
return this.getResource(this.rootPath, "/out/vs/server/src/login", requestPath);
default: default:
this.ensureGet(request);
if (!this.authenticate(request)) { if (!this.authenticate(request)) {
throw new HttpError("Unauthorized", HttpCode.Unauthorized); throw new HttpError("Unauthorized", HttpCode.Unauthorized);
} }
@ -274,6 +291,7 @@ export abstract class Server {
socket.on("error", () => socket.destroy()); socket.on("error", () => socket.destroy());
socket.on("end", () => socket.destroy()); socket.on("end", () => socket.destroy());
this.ensureGet(request);
if (!this.authenticate(request)) { if (!this.authenticate(request)) {
throw new HttpError("Unauthorized", HttpCode.Unauthorized); throw new HttpError("Unauthorized", HttpCode.Unauthorized);
} else if (request.headers.upgrade !== "websocket") { } else if (request.headers.upgrade !== "websocket") {
@ -297,8 +315,7 @@ export abstract class Server {
} }
private async tryLogin(request: http.IncomingMessage): Promise<Response> { private async tryLogin(request: http.IncomingMessage): Promise<Response> {
if (this.authenticate(request)) { if (this.authenticate(request) && (request.method === "GET" || request.method === "POST")) {
this.ensureGet(request);
return { redirect: "/" }; return { redirect: "/" };
} }
if (request.method === "POST") { if (request.method === "POST") {
@ -322,7 +339,7 @@ export abstract class Server {
} }
private async getLogin(error: string = "", payload?: LoginPayload): Promise<Response> { private async getLogin(error: string = "", payload?: LoginPayload): Promise<Response> {
const filePath = path.join(this.rootPath, "out/vs/server/src/login/index.html"); const filePath = path.join(this.serverRoot, "login/index.html");
const content = (await util.promisify(fs.readFile)(filePath, "utf8")) const content = (await util.promisify(fs.readFile)(filePath, "utf8"))
.replace("{{ERROR}}", error) .replace("{{ERROR}}", error)
.replace("display:none", error ? "display:block" : "display:none") .replace("display:none", error ? "display:block" : "display:none")
@ -446,24 +463,12 @@ export class MainServer extends Server {
): Promise<Response> { ): Promise<Response> {
switch (base) { switch (base) {
case "/": return this.getRoot(request, parsedUrl); case "/": return this.getRoot(request, parsedUrl);
case "/resources": case "/resource":
case "/vscode-resources": case "/vscode-remote-resource":
if (requestPath === "/fetch") { if (typeof parsedUrl.query.path === "string") {
if (typeof parsedUrl.query.u === "string") { return this.getResource(parsedUrl.query.path);
return this.getResource(JSON.parse(parsedUrl.query.u).path);
}
// For some reason VS Code encodes the = so the query doesn't parse
// correctly. We'll look through what's available and try to find it.
for (let value in parsedUrl.query) {
if (value && typeof value === "string") {
const query = querystring.parse(value);
if (typeof query.u === "string") {
return this.getResource(JSON.parse(query.u).path);
}
}
}
} }
throw new HttpError("Not found", HttpCode.NotFound); break;
case "/webview": case "/webview":
if (requestPath.indexOf("/vscode-resource") === 0) { if (requestPath.indexOf("/vscode-resource") === 0) {
return this.getResource(requestPath.replace(/^\/vscode-resource/, "")); return this.getResource(requestPath.replace(/^\/vscode-resource/, ""));
@ -473,9 +478,8 @@ export class MainServer extends Server {
"out/vs/workbench/contrib/webview/browser/pre", "out/vs/workbench/contrib/webview/browser/pre",
requestPath requestPath
); );
default:
return this.getResource(this.rootPath, base, requestPath);
} }
throw new HttpError("Not found", HttpCode.NotFound);
} }
private async getRoot(request: http.IncomingMessage, parsedUrl: url.UrlWithParsedQuery): Promise<Response> { private async getRoot(request: http.IncomingMessage, parsedUrl: url.UrlWithParsedQuery): Promise<Response> {
@ -502,16 +506,11 @@ export class MainServer extends Server {
? transformer.transformOutgoing(URI.file(sanitizeFilePath(folderPath, cwd))) ? transformer.transformOutgoing(URI.file(sanitizeFilePath(folderPath, cwd)))
: undefined, : undefined,
remoteAuthority, remoteAuthority,
productConfiguration: product,
}, },
REMOTE_USER_DATA_URI: transformer.transformOutgoing( REMOTE_USER_DATA_URI: transformer.transformOutgoing(
(this.services.get(IEnvironmentService) as EnvironmentService).webUserDataHome, (this.services.get(IEnvironmentService) as EnvironmentService).webUserDataHome,
), ),
PRODUCT_CONFIGURATION: {
...product,
// @ts-ignore workaround for getting the VS Code version to the browser.
version: pkg.version,
},
CONNECTION_AUTH_TOKEN: "",
NLS_CONFIGURATION: await getNlsConfiguration(locale, environment.userDataPath), NLS_CONFIGURATION: await getNlsConfiguration(locale, environment.userDataPath),
}; };
@ -586,6 +585,14 @@ export class MainServer extends Server {
const fileService = new FileService(logService); const fileService = new FileService(logService);
fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(logService)); fileService.registerProvider(Schemas.file, new DiskFileSystemProvider(logService));
this.allowedRequestPaths.push(
path.join(environmentService.userDataPath, "clp"), // Language packs.
environmentService.extensionsPath,
environmentService.builtinExtensionsPath,
...environmentService.extraExtensionPaths,
...environmentService.extraBuiltinExtensionPaths,
);
this.ipc.registerChannel("loglevel", new LogLevelSetterChannel(logService)); this.ipc.registerChannel("loglevel", new LogLevelSetterChannel(logService));
this.ipc.registerChannel(ExtensionHostDebugBroadcastChannel.ChannelName, new ExtensionHostDebugBroadcastChannel()); this.ipc.registerChannel(ExtensionHostDebugBroadcastChannel.ChannelName, new ExtensionHostDebugBroadcastChannel());
@ -595,7 +602,7 @@ export class MainServer extends Server {
this.services.set(IConfigurationService, new SyncDescriptor(ConfigurationService, [environmentService.machineSettingsResource])); this.services.set(IConfigurationService, new SyncDescriptor(ConfigurationService, [environmentService.machineSettingsResource]));
this.services.set(IRequestService, new SyncDescriptor(RequestService)); this.services.set(IRequestService, new SyncDescriptor(RequestService));
this.services.set(IFileService, fileService); this.services.set(IFileService, fileService);
this.services.set(IProductService, new SyncDescriptor(ProductService)); this.services.set(IProductService, { _serviceBrand: undefined, ...product });
this.services.set(IDialogService, new DialogChannelClient(this.ipc.getChannel("dialog", router))); this.services.set(IDialogService, new DialogChannelClient(this.ipc.getChannel("dialog", router)));
this.services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService)); this.services.set(IExtensionGalleryService, new SyncDescriptor(ExtensionGalleryService));
this.services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService)); this.services.set(IExtensionManagementService, new SyncDescriptor(ExtensionManagementService));
@ -608,14 +615,9 @@ export class MainServer extends Server {
), ),
commonProperties: resolveCommonProperties( commonProperties: resolveCommonProperties(
product.commit, pkg.codeServerVersion, await getMachineId(), product.commit, pkg.codeServerVersion, await getMachineId(),
environmentService.installSourcePath, "code-server", [], environmentService.installSourcePath, "code-server",
), ),
piiPaths: [ piiPaths: this.allowedRequestPaths,
environmentService.appRoot,
environmentService.extensionsPath,
...environmentService.extraExtensionPaths,
...environmentService.extraBuiltinExtensionPaths,
],
} as ITelemetryServiceConfig])); } as ITelemetryServiceConfig]));
} else { } else {
this.services.set(ITelemetryService, NullTelemetryService); this.services.set(ITelemetryService, NullTelemetryService);
@ -633,7 +635,7 @@ export class MainServer extends Server {
const telemetryService = this.services.get(ITelemetryService) as ITelemetryService; const telemetryService = this.services.get(ITelemetryService) as ITelemetryService;
const extensionsChannel = new ExtensionManagementChannel(extensionsService, (context) => getUriTransformer(context.remoteAuthority)); const extensionsChannel = new ExtensionManagementChannel(extensionsService, (context) => getUriTransformer(context.remoteAuthority));
const extensionsEnvironmentChannel = new ExtensionEnvironmentChannel(environmentService, logService, telemetryService); const extensionsEnvironmentChannel = new ExtensionEnvironmentChannel(environmentService, logService, telemetryService, this.options.connectionToken || "");
const fileChannel = new FileProviderChannel(environmentService, logService); const fileChannel = new FileProviderChannel(environmentService, logService);
const requestChannel = new RequestChannel(this.services.get(IRequestService) as IRequestService); const requestChannel = new RequestChannel(this.services.get(IRequestService) as IRequestService);
const telemetryChannel = new TelemetryChannel(telemetryService); const telemetryChannel = new TelemetryChannel(telemetryService);