Add https server

This commit is contained in:
Asher 2019-07-11 17:12:52 -05:00
parent 81862d4fa1
commit 2b2aa9a211
No known key found for this signature in database
GPG key ID: D63C1EF81242354A
20 changed files with 405 additions and 186 deletions

View file

@ -8,7 +8,7 @@ matrix:
- os: linux
dist: trusty
env:
- VSCODE_VERSION="1.36.1" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER" TARGET="centos"
- VSCODE_VERSION="1.36.1" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER" TARGET="linux"
- os: linux
dist: trusty
env:
@ -16,10 +16,6 @@ matrix:
- os: osx
env:
- VSCODE_VERSION="1.36.1" MAJOR_VERSION="2" VERSION="$MAJOR_VERSION.$TRAVIS_BUILD_NUMBER"
before_install:
- if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo apt-get install -y libxkbfile-dev libsecret-1-dev; fi
- npm install -g yarn@1.12.3
- npm install -g @coder/nbin
script:
- scripts/ci.bash
before_deploy:

View file

@ -1 +1 @@
require("../../bootstrap-amd").load("vs/server/cli");
require("../../bootstrap-amd").load("vs/server/src/cli");

View file

@ -1,25 +1,30 @@
{
"license": "MIT",
"scripts": {
"preinstall": "cd ../../../ && yarn",
"postinstall": "rm -rf node_modules/@types/node # I keep getting type conflicts",
"start": "nodemon ../../../out/vs/server/main.js --watch ../../../out --verbose",
"watch": "cd ../../../ && yarn watch",
"ensure-in-vscode": "bash ./scripts/tasks.bash ensure-in-vscode",
"preinstall": "yarn ensure-in-vscode && cd ../../../ && yarn || true",
"postinstall": "rm -rf node_modules/@types/node",
"start": "yarn ensure-in-vscode && nodemon ../../../out/vs/server/main.js --watch ../../../out --verbose",
"watch": "yarn ensure-in-vscode && cd ../../../ && yarn watch",
"build": "bash ./scripts/tasks.bash build",
"package": "bash ./scripts/tasks.bash package",
"vstar": "bash ./scripts/tasks.bash vstar",
"binary": "bash ./scripts/tasks.bash binary",
"patch:generate": "cd ../../../ && git diff --staged > ./src/vs/server/scripts/vscode.patch",
"patch:apply": "cd ../../../ && git apply ./src/vs/server/scripts/vscode.patch"
"patch:generate": "yarn ensure-in-vscode && cd ../../../ && git diff --staged > ./src/vs/server/scripts/vscode.patch",
"patch:apply": "yarn ensure-in-vscode && cd ../../../ && git apply ./src/vs/server/scripts/vscode.patch"
},
"devDependencies": {
"@types/pem": "^1.9.5",
"@types/safe-compare": "^1.1.0",
"@types/tar-stream": "^1.6.1",
"nodemon": "^1.19.1"
},
"dependencies": {
"tar-stream": "^2.1.0"
},
"resolutions": {
"@types/node": "^10.12.12"
},
"dependencies": {
"httpolyglot": "^0.1.2",
"pem": "^1.14.2",
"safe-compare": "^1.1.4"
}
}

View file

@ -3,11 +3,21 @@ set -euo pipefail
# Build using a Docker container.
function docker-build() {
local image="codercom/nbin-${target}"
if [[ "${target}" == "linux" ]] ; then
image="codercom/nbin-centos"
fi
local containerId
containerId=$(docker create --network=host --rm -it -v "$(pwd)"/.cache:/src/.cache "${image}")
docker start "${containerId}"
docker exec "${containerId}" mkdir -p /src
# TODO: temporary as long as we are rebuilding modules.
if [[ "${image}" == "codercom/nbin-alpine" ]] ; then
docker exec "${containerId}" apk add libxkbfile-dev libsecret-dev
fi
function docker-exec() {
local command="${1}" ; shift
local args="'${codeServerVersion}' '${vscodeVersion}' '${target}' '${arch}'"
@ -57,14 +67,6 @@ function main() {
target=darwin
local-build
else
local image
if [[ "${target}" == alpine ]]; then
image=codercom/nbin-alpine
target=musl
else
image=codercom/nbin-centos
target=linux
fi
docker-build
fi
}

View file

@ -20,39 +20,55 @@ function exit-if-ci() {
# Copy code-server into VS Code along with its dependencies.
function copy-server() {
log "Applying patch"
cd "${vscodeSourcePath}"
git reset --hard
git clean -fd
git apply "${rootPath}/scripts/vscode.patch"
local serverPath="${vscodeSourcePath}/src/vs/server"
rm -rf "${serverPath}"
mkdir -p "${serverPath}"
log "Copying server code"
log "Copying code-server code"
cp "${rootPath}"/*.{ts,js} "${serverPath}"
cp -r "${rootPath}/src" "${serverPath}"
cp -r "${rootPath}/typings" "${serverPath}"
cp "${rootPath}/main.js" "${serverPath}"
cp "${rootPath}/package.json" "${serverPath}"
cp "${rootPath}/yarn.lock" "${serverPath}"
if [[ -d "${rootPath}/node_modules" ]] ; then
log "Copying dependencies"
log "Copying code-server build dependencies"
cp -r "${rootPath}/node_modules" "${serverPath}"
else
log "Installing dependencies"
log "Installing code-server build dependencies"
cd "${serverPath}"
# Ignore scripts to avoid also installing VS Code dependencies which has
# already been done.
yarn --ignore-scripts
rm -r node_modules/@types/node # I keep getting type conflicts
fi
# TODO: Duplicate identifier issue. There must be a better way to fix this.
if [[ "${target}" == "darwin" ]] ; then
rm "${serverPath}/node_modules/fsevents/node_modules/safe-buffer/index.d.ts"
fi
}
# Prepend the nbin loading code which allows the code to find files within
# the binary.
# Prepend the nbin shim which enables finding files within the binary.
function prepend-loader() {
local filePath="${codeServerBuildPath}/${1}" ; shift
cat "${rootPath}/scripts/nbin-loader.js" "${filePath}" > "${filePath}.temp"
cat "${rootPath}/scripts/nbin-shim.js" "${filePath}" > "${filePath}.temp"
mv "${filePath}.temp" "${filePath}"
# Using : as the delimiter so the escaping here is easier to read.
# ${parameter/pattern/string}, so the pattern is /: (if the pattern starts
# with / it matches all instances) and the string is \\: (results in \:).
sed -i "s:{{ROOT_PATH}}:${codeServerBuildPath//:/\\:}:g" "${filePath}"
if [[ "${target}" == "darwin" ]] ; then
sed -i "" -e "s:{{ROOT_PATH}}:${codeServerBuildPath//:/\\:}:g" "${filePath}"
else
sed -i "s:{{ROOT_PATH}}:${codeServerBuildPath//:/\\:}:g" "${filePath}"
fi
}
# Copy code-server into VS Code then build it.
@ -63,10 +79,7 @@ function build-code-server() {
# (basically just want to skip extensions, target our server code, and get
# the same type of build you get with the vscode-linux-x64-min task).
# Something like: yarn gulp "vscode-server-${target}-${arch}-min"
cd "${vscodeSourcePath}"
git reset --hard
git clean -fd
git apply "${rootPath}/scripts/vscode.patch"
log "Building code-server"
yarn gulp compile-client
rm -rf "${codeServerBuildPath}"
@ -78,9 +91,22 @@ function build-code-server() {
node "${rootPath}/scripts/merge.js" "${vscodeBuildPath}/resources/app/package.json" "${rootPath}/scripts/package.json" "${codeServerBuildPath}/package.json" "${json}"
node "${rootPath}/scripts/merge.js" "${vscodeBuildPath}/resources/app/product.json" "${rootPath}/scripts/product.json" "${codeServerBuildPath}/product.json"
cp -r "${vscodeSourcePath}/out" "${codeServerBuildPath}"
rm -rf "${codeServerBuildPath}/out/vs/server/node_modules"
rm -rf "${codeServerBuildPath}/out/vs/server/typings"
# Rebuild to make sure the native modules work since at the moment all the
# pre-built packages are from one Linux system. This means you must build on
# the target system.
log "Installing remote dependencies"
cd "${vscodeSourcePath}/remote"
if [[ "${target}" != "linux" ]] ; then
yarn --production --force
fi
cp -r "${vscodeSourcePath}/remote/node_modules" "${codeServerBuildPath}"
# Only keep the production dependencies.
cd "${codeServerBuildPath}/out/vs/server"
yarn --production --ignore-scripts
prepend-loader "out/vs/server/main.js"
prepend-loader "out/bootstrap-fork.js"
@ -105,11 +131,9 @@ function build-vscode() {
if [[ ! -d "${vscodeSourcePath}/node_modules" ]] ; then
exit-if-ci
log "Installing VS Code dependencies"
yarn
# Not entirely sure why but there seem to be problems with native modules.
# Also vscode-ripgrep keeps complaining after the rebuild that the
# node_modules directory doesn't exist, so we're ignoring that for now.
npm rebuild || true
# Not entirely sure why but there seem to be problems with native modules
# so rebuild them.
yarn --force
# Keep just what we need to keep the pre-built archive smaller.
rm -rf "${vscodeSourcePath}/test"
@ -138,7 +162,7 @@ function download-vscode() {
cd "${buildPath}"
if command -v wget &> /dev/null ; then
log "Attempting to download ${tarName} with wget"
wget "${vsSourceUrl}" --quiet
wget "${vsSourceUrl}" --quiet --output-document "${tarName}"
else
log "Attempting to download ${tarName} with curl"
curl "${vsSourceUrl}" --silent --fail --output "${tarName}"
@ -152,13 +176,20 @@ function download-vscode() {
function prepare-vscode() {
if [[ ! -d "${vscodeBuildPath}" || ! -d "${vscodeSourcePath}" ]] ; then
mkdir -p "${buildPath}"
# TODO: for now everything uses the Linux build and we rebuild the modules.
# This means you must build on the target system.
local tarName="vstar-${vscodeVersion}-${target}-${arch}.tar.gz"
local vsSourceUrl="https://codesrv-ci.cdr.sh/${tarName}"
local linuxTarName="vstar-${vscodeVersion}-linux-${arch}.tar.gz"
local linuxVscodeBuildName="vscode-${vscodeVersion}-linux-${arch}-built"
local vsSourceUrl="https://codesrv-ci.cdr.sh/${linuxTarName}"
if download-vscode ; then
cd "${buildPath}"
rm -rf "${vscodeBuildPath}"
tar -xzf "${tarName}"
rm "${tarName}"
if [[ "${target}" != "linux" ]] ; then
mv "${linuxVscodeBuildName}" "${vscodeBuildName}"
fi
elif [[ -n "${ci}" ]] ; then
log "Pre-built VS Code ${vscodeVersion}-${target}-${arch} does not exist" "error"
exit 1
@ -199,12 +230,12 @@ function package-task() {
cp "${vscodeSourcePath}/ThirdPartyNotices.txt" "${archivePath}"
cd "${releasePath}"
if [[ "${target}" == "linux" ]] ; then
tar -czf "${binaryName}.tar.gz" "${binaryName}"
log "Archive: ${archivePath}.tar.gz"
else
if [[ "${target}" == "darwin" ]] ; then
zip -r "${binaryName}.zip" "${binaryName}"
log "Archive: ${archivePath}.zip"
else
tar -czf "${binaryName}.tar.gz" "${binaryName}"
log "Archive: ${archivePath}.tar.gz"
fi
}
@ -221,19 +252,54 @@ function binary-task() {
log "Binary: ${buildPath}/${binaryName}"
}
# Check if it looks like we are inside VS Code.
function in-vscode () {
log "Checking if we are inside VS Code"
local dir="${1}" ; shift
local maybeVscode
local dirName
maybeVscode="$(realpath "${dir}/../../..")"
dirName="$(basename "${maybeVscode}")"
if [[ "${dirName}" != "vscode" ]] ; then
return 1
fi
if [[ ! -f "${maybeVscode}/package.json" ]] ; then
return 1
fi
if ! grep '"name": "code-oss-dev"' "${maybeVscode}/package.json" --quiet ; then
return 1
fi
return 0
}
function ensure-in-vscode-task() {
if ! in-vscode "${rootPath}"; then
log "Not in vscode" "error"
exit 1
fi
exit 0
}
function main() {
local relativeRootPath
local rootPath
relativeRootPath="$(dirname "${0}")/.."
rootPath="$(realpath "${relativeRootPath}")"
local task="${1}" ; shift
if [[ "${task}" == "ensure-in-vscode" ]] ; then
ensure-in-vscode-task
fi
local codeServerVersion="${1}" ; shift
local vscodeVersion="${1}" ; shift
local target="${1}" ; shift
local arch="${1}" ; shift
local ci="${CI:-}"
local relativeRootPath
local rootPath
relativeRootPath="$(dirname "${0}")/.."
rootPath="$(realpath "${relativeRootPath}")"
# This lets you build in a separate directory since building within this
# directory while developing makes it hard to keep developing since compiling
# will compile everything in the build directory as well.
@ -241,15 +307,9 @@ function main() {
# If we're inside a vscode directory, assume we want to develop. In that case
# we should set an OUT directory and not build in this directory.
if [[ "${outPath}" == "${rootPath}" ]] ; then
local maybeVscode
local dirName
maybeVscode="$(realpath "${outPath}/../../..")"
dirName="$(basename "${maybeVscode}")"
if [[ "${dirName}" == "vscode" ]] ; then
log "Set the OUT environment variable to something outside ${maybeVscode}" "error"
exit 1
fi
if in-vscode "${outPath}" ; then
log "Set the OUT environment variable to something outside of VS Code" "error"
exit 1
fi
local releasePath="${outPath}/release"

View file

@ -6,7 +6,7 @@ import { Emitter, Event } from "vs/base/common/event";
import { IDisposable } from "vs/base/common/lifecycle";
import { OS } from "vs/base/common/platform";
import { URI, UriComponents } from "vs/base/common/uri";
import { URITransformer, IRawURITransformer, transformOutgoingURIs } from "vs/base/common/uriIpc";
import { transformOutgoingURIs } from "vs/base/common/uriIpc";
import { IServerChannel } from "vs/base/parts/ipc/common/ipc";
import { IDiagnosticInfo } from "vs/platform/diagnostics/common/diagnosticsService";
import { IEnvironmentService } from "vs/platform/environment/common/environment";
@ -19,6 +19,8 @@ import { IRemoteAgentEnvironment } from "vs/platform/remote/common/remoteAgentEn
import { ExtensionScanner, ExtensionScannerInput } from "vs/workbench/services/extensions/node/extensionPoints";
import { DiskFileSystemProvider } from "vs/workbench/services/files/node/diskFileSystemProvider";
import { getUriTransformer } from "vs/server/src/util";
/**
* Extend the file provider to allow unwatching.
*/
@ -262,11 +264,3 @@ export class ExtensionEnvironmentChannel implements IServerChannel {
throw new Error("not implemented");
}
}
export const uriTransformerPath = getPathFromAmdModule(require, "vs/server/uriTransformer");
export const getUriTransformer = (remoteAuthority: string): URITransformer => {
const rawURITransformerFactory = <any>require.__$__nodeRequire(uriTransformerPath);
const rawURITransformer = <IRawURITransformer>rawURITransformerFactory(remoteAuthority);
return new URITransformer(rawURITransformer);
};

View file

@ -1,12 +1,15 @@
import * as os from "os";
import { validatePaths } from "vs/code/node/paths";
import { parseMainProcessArgv } from "vs/platform/environment/node/argvHelper";
import { ParsedArgs } from "vs/platform/environment/common/environment";
import { buildHelpMessage, buildVersionMessage, options } from "vs/platform/environment/node/argv";
import product from "vs/platform/product/node/product";
import pkg from "vs/platform/product/node/package";
import { MainServer, WebviewServer } from "vs/server/server";
import "vs/server/tar";
import { MainServer, WebviewServer } from "vs/server/src/server";
import "vs/server/src/tar";
import { generateCertificate } from "vs/server/src/util";
interface Args extends ParsedArgs {
"allow-http"?: boolean;
@ -111,14 +114,41 @@ const main = async (): Promise<void> => {
return process.exit(0);
}
const webviewServer = new WebviewServer(typeof args["webview-port"] !== "undefined" && parseInt(args["webview-port"], 10) || 8444);
const server = new MainServer(typeof args.port !== "undefined" && parseInt(args.port, 10) || 8443, webviewServer, args);
const options = {
host: args["host"]
|| (args["no-auth"] || args["allow-http"] ? "localhost" : "0.0.0.0"),
allowHttp: args["allow-http"],
cert: args["cert"],
certKey: args["cert"],
};
if (!options.allowHttp && (!options.cert || !options.certKey)) {
const { cert, certKey } = await generateCertificate();
options.cert = cert;
options.certKey = certKey;
}
const webviewPort = typeof args["webview-port"] !== "undefined"
&& parseInt(args["webview-port"], 10) || 8444;
const webviewServer = new WebviewServer({
...options,
port: webviewPort,
socket: args["webview-socket"],
});
const port = typeof args.port !== "undefined" && parseInt(args.port, 10) || 8443;
const server = new MainServer({
...options,
port,
socket: args.socket,
}, webviewServer, args);
const [webviewAddress, serverAddress] = await Promise.all([
webviewServer.listen(),
server.listen()
]);
console.log(`Main server serving ${serverAddress}`);
console.log(`Webview server serving ${webviewAddress}`);
console.log(`Main server listening on ${serverAddress}`);
console.log(`Webview server listening on ${webviewAddress}`);
};
main().catch((error) => {

View file

@ -6,10 +6,10 @@ import { Emitter } from "vs/base/common/event";
import { ISocket } from "vs/base/parts/ipc/common/ipc.net";
import { NodeSocket, WebSocketNodeSocket } from "vs/base/parts/ipc/node/ipc.net";
import { ILogService } from "vs/platform/log/common/log";
import { uriTransformerPath } from "vs/server/channel";
import { IExtHostReadyMessage, IExtHostSocketMessage } from "vs/workbench/services/extensions/common/extensionHostProtocol";
import { Protocol } from "vs/server/protocol";
import { Protocol } from "vs/server/src/protocol";
import { uriTransformerPath } from "vs/server/src/util";
export abstract class Connection {
private readonly _onClose = new Emitter<void>();
@ -126,7 +126,7 @@ export class ExtensionHostConnection extends Connection {
getPathFromAmdModule(require, "bootstrap-fork"),
[
"--type=extensionHost",
`--uriTransformerPath=${uriTransformerPath}`
`--uriTransformerPath=${uriTransformerPath()}`
],
{
env: {

View file

@ -1,7 +1,9 @@
import * as fs from "fs";
import * as http from "http";
import * as https from "https";
import * as net from "net";
import * as path from "path";
import * as tls from "tls";
import * as util from "util";
import * as url from "url";
@ -44,9 +46,10 @@ import { RemoteExtensionLogFileName } from "vs/workbench/services/remote/common/
// import { TelemetryService } from "vs/workbench/services/telemetry/electron-browser/telemetryService";
import { IWorkbenchConstructionOptions } from "vs/workbench/workbench.web.api";
import { Connection, ManagementConnection, ExtensionHostConnection } from "vs/server/connection";
import { ExtensionEnvironmentChannel, FileProviderChannel, getUriTransformer } from "vs/server/channel";
import { Protocol } from "vs/server/protocol";
import { Connection, ManagementConnection, ExtensionHostConnection } from "vs/server/src/connection";
import { ExtensionEnvironmentChannel, FileProviderChannel , } from "vs/server/src/channel";
import { Protocol } from "vs/server/src/protocol";
import { getUriTransformer, useHttpsTransformer } from "vs/server/src/util";
export enum HttpCode {
Ok = 200,
@ -76,71 +79,51 @@ export class HttpError extends Error {
}
}
export interface ServerOptions {
readonly port: number;
readonly host: string;
readonly socket?: string;
readonly allowHttp?: boolean;
readonly cert?: string;
readonly certKey?: string;
}
export abstract class Server {
// The underlying web server.
protected readonly server: http.Server;
protected readonly server: http.Server | https.Server;
protected rootPath = path.resolve(__dirname, "../../..");
private listenPromise: Promise<string> | undefined;
public constructor(private readonly port: number) {
this.server = http.createServer(async (request, response): Promise<void> => {
try {
if (request.method !== "GET") {
throw new HttpError(
`Unsupported method ${request.method}`,
HttpCode.BadRequest,
);
}
const parsedUrl = url.parse(request.url || "", true);
const fullPath = decodeURIComponent(parsedUrl.pathname || "/");
const match = fullPath.match(/^(\/?[^/]*)(.*)$/);
const [, base, requestPath] = match
? match.map((p) => p !== "/" ? p.replace(/\/$/, "") : p)
: ["", "", ""];
const { content, headers, code } = await this.handleRequest(
base, requestPath, parsedUrl, request,
);
response.writeHead(code || HttpCode.Ok, {
"Cache-Control": "max-age=86400",
// TODO: ETag?
...headers,
});
response.end(content);
} catch (error) {
if (error.code === "ENOENT" || error.code === "EISDIR") {
error = new HttpError("Not found", HttpCode.NotFound);
}
response.writeHead(typeof error.code === "number" ? error.code : 500);
response.end(error.message);
}
});
public constructor(private readonly options: ServerOptions) {
if (this.options.cert && this.options.certKey) {
useHttpsTransformer();
const httpolyglot = require.__$__nodeRequire(path.resolve(__dirname, "../node_modules/httpolyglot/lib/index")) as typeof import("httpolyglot");
this.server = httpolyglot.createServer({
cert: fs.readFileSync(this.options.cert),
key: fs.readFileSync(this.options.certKey),
}, this.onRequest);
} else {
this.server = http.createServer(this.onRequest);
}
}
public listen(): Promise<string> {
if (!this.listenPromise) {
this.listenPromise = new Promise((resolve, reject) => {
this.server.on("error", reject);
this.server.listen(this.port, () => {
resolve(this.address());
});
const onListen = () => resolve(this.address(this.server, this.options.allowHttp));
if (this.options.socket) {
this.server.listen(this.options.socket, onListen);
} else {
this.server.listen(this.options.port, this.options.host, onListen);
}
});
}
return this.listenPromise;
}
public address(): string {
const address = this.server.address();
const endpoint = typeof address !== "string"
? ((address.address === "::" ? "localhost" : address.address) + ":" + address.port)
: address;
return `http://${endpoint}`;
}
protected abstract handleRequest(
base: string,
requestPath: string,
@ -162,6 +145,57 @@ export abstract class Server {
},
};
}
private onRequest = async (request: http.IncomingMessage, response: http.ServerResponse): Promise<void> => {
const secure = (request.connection as tls.TLSSocket).encrypted;
if (!this.options.allowHttp && !secure) {
response.writeHead(302, {
Location: "https://" + request.headers.host + request.url,
});
return response.end();
}
try {
if (request.method !== "GET") {
throw new HttpError(
`Unsupported method ${request.method}`,
HttpCode.BadRequest,
);
}
const parsedUrl = url.parse(request.url || "", true);
const fullPath = decodeURIComponent(parsedUrl.pathname || "/");
const match = fullPath.match(/^(\/?[^/]*)(.*)$/);
const [, base, requestPath] = match
? match.map((p) => p !== "/" ? p.replace(/\/$/, "") : p)
: ["", "", ""];
const { content, headers, code } = await this.handleRequest(
base, requestPath, parsedUrl, request,
);
response.writeHead(code || HttpCode.Ok, {
"Cache-Control": "max-age=86400",
// TODO: ETag?
...headers,
});
response.end(content);
} catch (error) {
if (error.code === "ENOENT" || error.code === "EISDIR") {
error = new HttpError("Not found", HttpCode.NotFound);
}
response.writeHead(typeof error.code === "number" ? error.code : 500);
response.end(error.message);
}
}
private address(server: net.Server, http?: boolean): string {
const address = server.address();
const endpoint = typeof address !== "string"
? ((address.address === "::" ? "localhost" : address.address) + ":" + address.port)
: address;
return `${http ? "http" : "https"}://${endpoint}`;
}
}
export class MainServer extends Server {
@ -179,11 +213,11 @@ export class MainServer extends Server {
private readonly services = new ServiceCollection();
public constructor(
port: number,
options: ServerOptions,
private readonly webviewServer: WebviewServer,
args: ParsedArgs,
) {
super(port);
super(options);
this.server.on("upgrade", async (request, socket) => {
const protocol = this.createProtocol(request, socket);

View file

@ -1,9 +1,10 @@
import * as nls from "vs/nls";
import * as vszip from "vs/base/node/zip";
import * as fs from "fs";
import * as path from "path";
import * as tarStream from "tar-stream";
import { promisify } from "util";
import * as nls from "vs/nls";
import * as vszip from "vs/base/node/zip";
import { CancellationToken } from "vs/base/common/cancellation";
import { mkdirp } from "vs/base/node/pfs";

View file

@ -0,0 +1,3 @@
module.exports = (remoteAuthority) => {
return require("./uriTransformerHttp")(remoteAuthority, true);
};

60
src/util.ts Normal file
View file

@ -0,0 +1,60 @@
import * as fs from "fs";
import * as os from "os";
import * as path from "path";
import * as util from "util";
import { getPathFromAmdModule } from "vs/base/common/amd";
import { URITransformer, IRawURITransformer } from "vs/base/common/uriIpc";
import { mkdirp } from "vs/base/node/pfs";
export const tmpdir = path.join(os.tmpdir(), "code-server");
export const generateCertificate = async (): Promise<{ cert: string, certKey: string }> => {
const paths = {
cert: path.join(tmpdir, "self-signed.cert"),
certKey: path.join(tmpdir, "self-signed.key"),
};
const exists = await Promise.all([
util.promisify(fs.exists)(paths.cert),
util.promisify(fs.exists)(paths.certKey),
]);
await mkdirp(tmpdir);
if (!exists[0] || !exists[1]) {
const pem = require.__$__nodeRequire(path.resolve(__dirname, "../node_modules/pem/lib/pem")) as typeof import("pem");
const certs = await new Promise<import("pem").CertificateCreationResult>((resolve, reject): void => {
pem.createCertificate({ selfSigned: true }, (error, result) => {
if (error) {
return reject(error);
}
resolve(result);
});
});
await Promise.all([
util.promisify(fs.writeFile)(paths.cert, certs.certificate),
util.promisify(fs.writeFile)(paths.certKey, certs.serviceKey),
]);
}
return paths;
};
let secure: boolean;
export const useHttpsTransformer = (): void => {
secure = true;
};
export const uriTransformerPath = (): string => {
return getPathFromAmdModule(
require,
"vs/server/src/uriTransformerHttp" + (secure ? "s": ""),
);
};
export const getUriTransformer = (remoteAuthority: string): URITransformer => {
const rawURITransformerFactory = <any>require.__$__nodeRequire(uriTransformerPath());
const rawURITransformer = <IRawURITransformer>rawURITransformerFactory(remoteAuthority);
return new URITransformer(rawURITransformer);
};

7
typings/httpolyglot.d.ts vendored Normal file
View file

@ -0,0 +1,7 @@
declare module "httpolyglot" {
import * as http from "http";
import * as https from "https";
function createServer(requestListener?: (req: http.IncomingMessage, res: http.ServerResponse) => void): http.Server;
function createServer(options: https.ServerOptions, requestListener?: (req: http.IncomingMessage, res: http.ServerResponse) => void): https.Server;
}

View file

@ -1,3 +0,0 @@
module.exports = (remoteAuthority) => {
return require("./uriTransformer")(remoteAuthority, true);
};

130
yarn.lock
View file

@ -7,6 +7,18 @@
resolved "https://registry.yarnpkg.com/@types/node/-/node-10.14.12.tgz#0eec3155a46e6c4db1f27c3e588a205f767d622f"
integrity sha512-QcAKpaO6nhHLlxWBvpc4WeLrTvPqlHOvaj0s5GriKkA1zq+bsFBPpfYCvQhLqLgYlIko8A9YrPdaMHCo5mBcpg==
"@types/pem@^1.9.5":
version "1.9.5"
resolved "https://registry.yarnpkg.com/@types/pem/-/pem-1.9.5.tgz#cd5548b5e0acb4b41a9e21067e9fcd8c57089c99"
integrity sha512-C0txxEw8B7DCoD85Ko7SEvzUogNd5VDJ5/YBG8XUcacsOGqxr5Oo4g3OUAfdEDUbhXanwUoVh/ZkMFw77FGPQQ==
dependencies:
"@types/node" "*"
"@types/safe-compare@^1.1.0":
version "1.1.0"
resolved "https://registry.yarnpkg.com/@types/safe-compare/-/safe-compare-1.1.0.tgz#47ed9b9ca51a3a791b431cd59b28f47fa9bf1224"
integrity sha512-1ri+LJhh0gRxIa37IpGytdaW7yDEHeJniBSMD1BmitS07R1j63brcYCzry+l0WJvGdEKQNQ7DYXO2epgborWPw==
"@types/tar-stream@^1.6.1":
version "1.6.1"
resolved "https://registry.yarnpkg.com/@types/tar-stream/-/tar-stream-1.6.1.tgz#67d759068ff781d976cad978893bb7a334ec8809"
@ -122,13 +134,6 @@ binary-extensions@^1.0.0:
resolved "https://registry.yarnpkg.com/binary-extensions/-/binary-extensions-1.12.0.tgz#c2d780f53d45bba8317a8902d4ceeaf3a6385b14"
integrity sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==
bl@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/bl/-/bl-3.0.0.tgz#3611ec00579fd18561754360b21e9f784500ff88"
integrity sha512-EUAyP5UHU5hxF8BPT0LKW8gjYLhq1DQIcneOX/pL/m2Alo+OYDQAJlHq+yseMP50Os2nHXOSic6Ss3vSQeyf4A==
dependencies:
readable-stream "^3.0.1"
boxen@^1.2.1:
version "1.3.0"
resolved "https://registry.yarnpkg.com/boxen/-/boxen-1.3.0.tgz#55c6c39a8ba58d9c61ad22cd877532deb665a20b"
@ -166,6 +171,24 @@ braces@^2.3.1, braces@^2.3.2:
split-string "^3.0.2"
to-regex "^3.0.1"
buffer-alloc-unsafe@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0"
integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg==
buffer-alloc@^1.2.0:
version "1.2.0"
resolved "https://registry.yarnpkg.com/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec"
integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow==
dependencies:
buffer-alloc-unsafe "^1.1.0"
buffer-fill "^1.0.0"
buffer-fill@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c"
integrity sha1-+PeLdniYiO858gXNY39o5wISKyw=
cache-base@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2"
@ -200,6 +223,11 @@ chalk@^2.0.1:
escape-string-regexp "^1.0.5"
supports-color "^5.3.0"
charenc@~0.0.1:
version "0.0.2"
resolved "https://registry.yarnpkg.com/charenc/-/charenc-0.0.2.tgz#c0a1d2f3a7092e03774bfa83f14c0fc5790a8667"
integrity sha1-wKHS86cJLgN3S/qD8UwPxXkKhmc=
chokidar@^2.1.5:
version "2.1.6"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.6.tgz#b6cad653a929e244ce8a834244164d241fa954c5"
@ -322,6 +350,11 @@ cross-spawn@^5.0.1:
shebang-command "^1.2.0"
which "^1.2.9"
crypt@~0.0.1:
version "0.0.2"
resolved "https://registry.yarnpkg.com/crypt/-/crypt-0.0.2.tgz#88d7ff7ec0dfb86f713dc87bbb42d044d3e6c41b"
integrity sha1-iNf/fsDfuG9xPch7u0LQRNPmxBs=
crypto-random-string@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/crypto-random-string/-/crypto-random-string-1.0.0.tgz#a230f64f568310e1498009940790ec99545bca7e"
@ -395,12 +428,10 @@ duplexer3@^0.1.4:
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
end-of-stream@^1.4.1:
version "1.4.1"
resolved "https://registry.yarnpkg.com/end-of-stream/-/end-of-stream-1.4.1.tgz#ed29634d19baba463b6ce6b80a37213eab71ec43"
integrity sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==
dependencies:
once "^1.4.0"
es6-promisify@^6.0.0:
version "6.0.1"
resolved "https://registry.yarnpkg.com/es6-promisify/-/es6-promisify-6.0.1.tgz#6edaa45f3bd570ffe08febce66f7116be4b1cdb6"
integrity sha512-J3ZkwbEnnO+fGAKrjVpeUAnZshAdfZvbhQpqfIH9kSAspReRC4nJnu8ewm55b4y9ElyeuhCTzJD0XiH8Tsbhlw==
escape-string-regexp@^1.0.5:
version "1.0.5"
@ -484,11 +515,6 @@ fragment-cache@^0.2.1:
dependencies:
map-cache "^0.2.2"
fs-constants@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/fs-constants/-/fs-constants-1.0.0.tgz#6be0de9be998ce16af8afc24497b9ee9b7ccd9ad"
integrity sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==
fs-minipass@^1.2.5:
version "1.2.5"
resolved "https://registry.yarnpkg.com/fs-minipass/-/fs-minipass-1.2.5.tgz#06c277218454ec288df77ada54a03b8702aacb9d"
@ -623,6 +649,11 @@ has-values@^1.0.0:
is-number "^3.0.0"
kind-of "^4.0.0"
httpolyglot@^0.1.2:
version "0.1.2"
resolved "https://registry.yarnpkg.com/httpolyglot/-/httpolyglot-0.1.2.tgz#e4d347fe8984a62f467d4060df527f1851f6997b"
integrity sha1-5NNH/omEpi9GfUBg31J/GFH2mXs=
iconv-lite@^0.4.4:
version "0.4.24"
resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b"
@ -691,7 +722,7 @@ is-binary-path@^1.0.0:
dependencies:
binary-extensions "^1.0.0"
is-buffer@^1.1.5:
is-buffer@^1.1.5, is-buffer@~1.1.1:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
@ -922,6 +953,15 @@ map-visit@^1.0.0:
dependencies:
object-visit "^1.0.0"
md5@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/md5/-/md5-2.2.1.tgz#53ab38d5fe3c8891ba465329ea23fac0540126f9"
integrity sha1-U6s41f48iJG6RlMp6iP6wFQBJvk=
dependencies:
charenc "~0.0.1"
crypt "~0.0.1"
is-buffer "~1.1.1"
micromatch@^3.1.10, micromatch@^3.1.4:
version "3.1.10"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
@ -1151,7 +1191,7 @@ object.pick@^1.3.0:
dependencies:
isobject "^3.0.1"
once@^1.3.0, once@^1.4.0:
once@^1.3.0:
version "1.4.0"
resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1"
integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E=
@ -1163,7 +1203,7 @@ os-homedir@^1.0.0:
resolved "https://registry.yarnpkg.com/os-homedir/-/os-homedir-1.0.2.tgz#ffbc4988336e0e833de0c168c7ef152121aa7fb3"
integrity sha1-/7xJiDNuDoM94MFox+8VISGqf7M=
os-tmpdir@^1.0.0:
os-tmpdir@^1.0.0, os-tmpdir@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=
@ -1216,6 +1256,16 @@ path-key@^2.0.0:
resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40"
integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A=
pem@^1.14.2:
version "1.14.2"
resolved "https://registry.yarnpkg.com/pem/-/pem-1.14.2.tgz#ab29350416bc3a532c30beeee0d541af897fb9ac"
integrity sha512-TOnPtq3ZFnCniOZ+rka4pk8UIze9xG1qI+wNE7EmkiR/cg+53uVvk5QbkWZ7M6RsuOxzz62FW1hlAobJr/lTOA==
dependencies:
es6-promisify "^6.0.0"
md5 "^2.2.1"
os-tmpdir "^1.0.1"
which "^1.3.1"
pify@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176"
@ -1269,15 +1319,6 @@ readable-stream@^2.0.2, readable-stream@^2.0.6:
string_decoder "~1.1.1"
util-deprecate "~1.0.1"
readable-stream@^3.0.1, readable-stream@^3.1.1:
version "3.4.0"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-3.4.0.tgz#a51c26754658e0a3c21dbf59163bd45ba6f447fc"
integrity sha512-jItXPLmrSR8jmTRmRWJXCnGJsfy85mB3Wd/uINMXA65yrnFo0cPClFIUWzo2najVNSl+mx7/4W8ttlLWJe99pQ==
dependencies:
inherits "^2.0.3"
string_decoder "^1.1.1"
util-deprecate "^1.0.1"
readdirp@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-2.2.1.tgz#0e87622a3325aa33e892285caf8b4e846529a525"
@ -1347,6 +1388,13 @@ safe-buffer@^5.0.1, safe-buffer@^5.1.2, safe-buffer@~5.1.0, safe-buffer@~5.1.1:
resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d"
integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==
safe-compare@^1.1.4:
version "1.1.4"
resolved "https://registry.yarnpkg.com/safe-compare/-/safe-compare-1.1.4.tgz#5e0128538a82820e2e9250cd78e45da6786ba593"
integrity sha512-b9wZ986HHCo/HbKrRpBJb2kqXMK9CEWIE1egeEvZsYn69ay3kdfl9nG3RyOcR+jInTDf7a86WQ1d4VJX7goSSQ==
dependencies:
buffer-alloc "^1.2.0"
safe-regex@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e"
@ -1506,13 +1554,6 @@ string-width@^1.0.1:
is-fullwidth-code-point "^2.0.0"
strip-ansi "^4.0.0"
string_decoder@^1.1.1:
version "1.2.0"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.2.0.tgz#fe86e738b19544afe70469243b2a1ee9240eae8d"
integrity sha512-6YqyX6ZWEYguAxgZzHGL7SsCeGx3V2TtOTqZz1xSTSWnqsbWwbptafNyvf/ACquZUXV3DANr5BDIwNYe1mN42w==
dependencies:
safe-buffer "~5.1.0"
string_decoder@~1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/string_decoder/-/string_decoder-1.1.1.tgz#9cf1611ba62685d7030ae9e4ba34149c3af03fc8"
@ -1551,17 +1592,6 @@ supports-color@^5.2.0, supports-color@^5.3.0:
dependencies:
has-flag "^3.0.0"
tar-stream@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/tar-stream/-/tar-stream-2.1.0.tgz#d1aaa3661f05b38b5acc9b7020efdca5179a2cc3"
integrity sha512-+DAn4Nb4+gz6WZigRzKEZl1QuJVOLtAwwF+WUxy1fJ6X63CaGaUAxJRD2KEn1OMfcbCjySTYpNC6WmfQoIEOdw==
dependencies:
bl "^3.0.0"
end-of-stream "^1.4.1"
fs-constants "^1.0.0"
inherits "^2.0.3"
readable-stream "^3.1.1"
tar@^4:
version "4.4.8"
resolved "https://registry.yarnpkg.com/tar/-/tar-4.4.8.tgz#b19eec3fde2a96e64666df9fdb40c5ca1bc3747d"
@ -1694,12 +1724,12 @@ use@^3.1.0:
resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f"
integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==
util-deprecate@^1.0.1, util-deprecate@~1.0.1:
util-deprecate@~1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
which@^1.2.9:
which@^1.2.9, which@^1.3.1:
version "1.3.1"
resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a"
integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==