Improve env variable handling around extension host connection type (#152466)

This commit is contained in:
Alexandru Dima 2022-06-17 15:20:53 +02:00 committed by GitHub
parent 0f05ed4758
commit 47652af0b6
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 106 additions and 7 deletions

View file

@ -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<IProcessEnvironment> {
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;
}

View file

@ -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<IMessagePassingProtocol> {
if (process.env.VSCODE_WILL_SEND_MESSAGE_PORT) {
const extHostConnection = readExtHostConnection(process.env);
if (extHostConnection.type === ExtHostConnectionType.MessagePort) {
return new Promise<IMessagePassingProtocol>((resolve, reject) => {
@ -139,7 +142,7 @@ function _createExtHostProtocol(): Promise<IMessagePassingProtocol> {
});
} else if (process.env.VSCODE_EXTHOST_WILL_SEND_SOCKET) {
} else if (extHostConnection.type === ExtHostConnectionType.Socket) {
return new Promise<PersistentProtocol>((resolve, reject) => {
@ -208,7 +211,7 @@ function _createExtHostProtocol(): Promise<IMessagePassingProtocol> {
} else {
const pipeName = process.env.VSCODE_IPC_HOOK_EXTHOST!;
const pipeName = extHostConnection.pipeName;
return new Promise<PersistentProtocol>((resolve, reject) => {

View file

@ -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;
}

View file

@ -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<IMessagePassingProtocol> {
const { namedPipeServer, pipeName } = prepared;
opts.env['VSCODE_IPC_HOOK_EXTHOST'] = pipeName;
writeExtHostConnection(new IPCExtHostConnection(pipeName), opts.env);
return new Promise<PersistentProtocol>((resolve, reject) => {

View file

@ -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<IMessagePassingProtocol> {
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);