diff --git a/src/vs/server/node/extensionHostConnection.ts b/src/vs/server/node/extensionHostConnection.ts index 9e0a646f225..b2ed76583ce 100644 --- a/src/vs/server/node/extensionHostConnection.ts +++ b/src/vs/server/node/extensionHostConnection.ts @@ -22,6 +22,7 @@ import { logRemoteEntry } from 'vs/workbench/services/extensions/common/remoteCo import { removeDangerousEnvVariables } from 'vs/base/common/processes'; import { IExtensionHostStatusService } from 'vs/server/node/extensionHostStatusService'; import { DisposableStore, toDisposable } from 'vs/base/common/lifecycle'; +import { IPCExtHostConnection, writeExtHostConnection, SocketExtHostConnection } from 'vs/workbench/services/extensions/common/extensionHostEnv'; export async function buildUserEnvironment(startParamsEnv: { [key: string]: string | null } = {}, withUserShellEnvironment: boolean, language: string, isDebug: boolean, environmentService: IServerEnvironmentService, logService: ILogService): Promise { const nlsConfig = await getNLSConfiguration(language, environmentService.userDataPath); @@ -244,11 +245,11 @@ export class ExtensionHostConnection { let extHostNamedPipeServer: net.Server | null; if (this._canSendSocket) { - env['VSCODE_EXTHOST_WILL_SEND_SOCKET'] = 'true'; + writeExtHostConnection(new SocketExtHostConnection(), env); extHostNamedPipeServer = null; } else { const { namedPipeServer, pipeName } = await this._listenOnPipe(); - env['VSCODE_IPC_HOOK_EXTHOST'] = pipeName; + writeExtHostConnection(new IPCExtHostConnection(pipeName), env); extHostNamedPipeServer = namedPipeServer; } diff --git a/src/vs/workbench/api/node/extensionHostProcess.ts b/src/vs/workbench/api/node/extensionHostProcess.ts index 331b384e394..bad55575c87 100644 --- a/src/vs/workbench/api/node/extensionHostProcess.ts +++ b/src/vs/workbench/api/node/extensionHostProcess.ts @@ -24,6 +24,7 @@ import { ProcessTimeRunOnceScheduler } from 'vs/base/common/async'; import { boolean } from 'vs/editor/common/config/editorOptions'; import { createURITransformer } from 'vs/workbench/api/node/uriTransformer'; import { MessagePortMain } from 'electron'; +import { ExtHostConnectionType, readExtHostConnection } from 'vs/workbench/services/extensions/common/extensionHostEnv'; import 'vs/workbench/api/common/extHost.common.services'; import 'vs/workbench/api/node/extHost.node.services'; @@ -110,7 +111,9 @@ let onTerminate = function (reason: string) { }; function _createExtHostProtocol(): Promise { - if (process.env.VSCODE_WILL_SEND_MESSAGE_PORT) { + const extHostConnection = readExtHostConnection(process.env); + + if (extHostConnection.type === ExtHostConnectionType.MessagePort) { return new Promise((resolve, reject) => { @@ -139,7 +142,7 @@ function _createExtHostProtocol(): Promise { }); - } else if (process.env.VSCODE_EXTHOST_WILL_SEND_SOCKET) { + } else if (extHostConnection.type === ExtHostConnectionType.Socket) { return new Promise((resolve, reject) => { @@ -208,7 +211,7 @@ function _createExtHostProtocol(): Promise { } else { - const pipeName = process.env.VSCODE_IPC_HOOK_EXTHOST!; + const pipeName = extHostConnection.pipeName; return new Promise((resolve, reject) => { diff --git a/src/vs/workbench/services/extensions/common/extensionHostEnv.ts b/src/vs/workbench/services/extensions/common/extensionHostEnv.ts new file mode 100644 index 00000000000..9b952930ecd --- /dev/null +++ b/src/vs/workbench/services/extensions/common/extensionHostEnv.ts @@ -0,0 +1,93 @@ +/*--------------------------------------------------------------------------------------------- + * Copyright (c) Microsoft Corporation. All rights reserved. + * Licensed under the MIT License. See License.txt in the project root for license information. + *--------------------------------------------------------------------------------------------*/ + +import { IProcessEnvironment } from 'vs/base/common/platform'; + +export const enum ExtHostConnectionType { + IPC = 1, + Socket = 2, + MessagePort = 3 +} + +/** + * The extension host will connect via named pipe / domain socket to its renderer. + */ +export class IPCExtHostConnection { + public static ENV_KEY = 'VSCODE_EXTHOST_IPC_HOOK'; + + public readonly type = ExtHostConnectionType.IPC; + + constructor( + public readonly pipeName: string + ) { } + + public serialize(env: IProcessEnvironment): void { + env[IPCExtHostConnection.ENV_KEY] = this.pipeName; + } +} + +/** + * The extension host will receive via nodejs IPC the socket to its renderer. + */ +export class SocketExtHostConnection { + public static ENV_KEY = 'VSCODE_EXTHOST_WILL_SEND_SOCKET'; + + public readonly type = ExtHostConnectionType.Socket; + + public serialize(env: IProcessEnvironment): void { + env[SocketExtHostConnection.ENV_KEY] = '1'; + } +} + +/** + * The extension host will receive via nodejs IPC the MessagePort to its renderer. + */ +export class MessagePortExtHostConnection { + public static ENV_KEY = 'VSCODE_WILL_SEND_MESSAGE_PORT'; + + public readonly type = ExtHostConnectionType.MessagePort; + + public serialize(env: IProcessEnvironment): void { + env[MessagePortExtHostConnection.ENV_KEY] = '1'; + } +} + +export type ExtHostConnection = IPCExtHostConnection | SocketExtHostConnection | MessagePortExtHostConnection; + +function clean(env: IProcessEnvironment): void { + delete env[IPCExtHostConnection.ENV_KEY]; + delete env[SocketExtHostConnection.ENV_KEY]; + delete env[MessagePortExtHostConnection.ENV_KEY]; +} + +/** + * Write `connection` into `env` and clean up `env`. + */ +export function writeExtHostConnection(connection: ExtHostConnection, env: IProcessEnvironment): void { + // Avoid having two different keys that might introduce amiguity or problems. + clean(env); + connection.serialize(env); +} + +/** + * Read `connection` from `env` and clean up `env`. + */ +export function readExtHostConnection(env: IProcessEnvironment): ExtHostConnection { + if (env[IPCExtHostConnection.ENV_KEY]) { + return cleanAndReturn(env, new IPCExtHostConnection(env[IPCExtHostConnection.ENV_KEY]!)); + } + if (env[SocketExtHostConnection.ENV_KEY]) { + return cleanAndReturn(env, new SocketExtHostConnection()); + } + if (env[MessagePortExtHostConnection.ENV_KEY]) { + return cleanAndReturn(env, new MessagePortExtHostConnection()); + } + throw new Error(`No connection information defined in environment!`); +} + +function cleanAndReturn(env: IProcessEnvironment, result: ExtHostConnection): ExtHostConnection { + clean(env); + return result; +} diff --git a/src/vs/workbench/services/extensions/electron-browser/nativeLocalProcessExtensionHost.ts b/src/vs/workbench/services/extensions/electron-browser/nativeLocalProcessExtensionHost.ts index d5bcf07f039..888db160609 100644 --- a/src/vs/workbench/services/extensions/electron-browser/nativeLocalProcessExtensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-browser/nativeLocalProcessExtensionHost.ts @@ -12,6 +12,7 @@ import { PersistentProtocol } from 'vs/base/parts/ipc/common/ipc.net'; import { createRandomIPCHandle, NodeSocket } from 'vs/base/parts/ipc/node/ipc.net'; import { IExtensionHostProcessOptions } from 'vs/platform/extensions/common/extensionHostStarter'; import { ILogService } from 'vs/platform/log/common/log'; +import { IPCExtHostConnection, writeExtHostConnection } from 'vs/workbench/services/extensions/common/extensionHostEnv'; import { createMessageOfType, MessageType } from 'vs/workbench/services/extensions/common/extensionHostProtocol'; import { ExtensionHostProcess, ExtHostMessagePortCommunication, IExtHostCommunication, SandboxLocalProcessExtensionHost } from 'vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost'; @@ -64,7 +65,7 @@ class ExtHostNamedPipeCommunication extends Disposable implements IExtHostCommun establishProtocol(prepared: INamedPipePreparedData, extensionHostProcess: ExtensionHostProcess, opts: IExtensionHostProcessOptions): Promise { const { namedPipeServer, pipeName } = prepared; - opts.env['VSCODE_IPC_HOOK_EXTHOST'] = pipeName; + writeExtHostConnection(new IPCExtHostConnection(pipeName), opts.env); return new Promise((resolve, reject) => { diff --git a/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts b/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts index cb7abfcbf53..2932c6be3ef 100644 --- a/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts +++ b/src/vs/workbench/services/extensions/electron-sandbox/localProcessExtensionHost.ts @@ -45,6 +45,7 @@ import { IUserDataProfilesService } from 'vs/platform/userDataProfile/common/use import { generateUuid } from 'vs/base/common/uuid'; import { acquirePort } from 'vs/base/parts/ipc/electron-sandbox/ipc.mp'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; +import { MessagePortExtHostConnection, writeExtHostConnection } from 'vs/workbench/services/extensions/common/extensionHostEnv'; export interface ILocalProcessExtensionHostInitData { readonly autoStart: boolean; @@ -620,7 +621,7 @@ export class ExtHostMessagePortCommunication extends Disposable implements IExtH establishProtocol(prepared: void, extensionHostProcess: ExtensionHostProcess, opts: IExtensionHostProcessOptions): Promise { - opts.env['VSCODE_WILL_SEND_MESSAGE_PORT'] = 'true'; + writeExtHostConnection(new MessagePortExtHostConnection(), opts.env); // Get ready to acquire the message port from the shared process worker const portPromise = acquirePort(undefined /* we trigger the request via service call! */, opts.responseChannel, opts.responseNonce);