From 4d3d1b844defc5a3be6316148f61992daf39d72d Mon Sep 17 00:00:00 2001 From: Asher Date: Tue, 2 Mar 2021 16:42:25 -0600 Subject: [PATCH] Handle permessage-deflate on sockets With this the extension host is working again. --- lib/vscode/src/vs/server/entry.ts | 2 +- lib/vscode/src/vs/server/ipc.d.ts | 1 + lib/vscode/src/vs/server/node/connection.ts | 15 +++++++++++---- lib/vscode/src/vs/server/node/protocol.ts | 10 +++++++++- lib/vscode/src/vs/server/node/server.ts | 3 ++- src/node/routes/vscode.ts | 5 ++++- src/node/vscode.ts | 4 ++-- 7 files changed, 30 insertions(+), 10 deletions(-) diff --git a/lib/vscode/src/vs/server/entry.ts b/lib/vscode/src/vs/server/entry.ts index 85b306ab0..89a872d45 100644 --- a/lib/vscode/src/vs/server/entry.ts +++ b/lib/vscode/src/vs/server/entry.ts @@ -68,7 +68,7 @@ process.on('message', async (message: CodeServerMessage, socket) => { } break; case 'socket': - vscode.handleWebSocket(socket, message.query); + vscode.handleWebSocket(socket, message.query, message.permessageDeflate); break; } }); diff --git a/lib/vscode/src/vs/server/ipc.d.ts b/lib/vscode/src/vs/server/ipc.d.ts index bc605f038..a729a835f 100644 --- a/lib/vscode/src/vs/server/ipc.d.ts +++ b/lib/vscode/src/vs/server/ipc.d.ts @@ -19,6 +19,7 @@ export type Query = { [key: string]: string | string[] | undefined | Query | Que export interface SocketMessage { type: 'socket'; query: Query; + permessageDeflate: boolean; } export interface CliMessage { diff --git a/lib/vscode/src/vs/server/node/connection.ts b/lib/vscode/src/vs/server/node/connection.ts index 51ca4d097..3b4d54ab9 100644 --- a/lib/vscode/src/vs/server/node/connection.ts +++ b/lib/vscode/src/vs/server/node/connection.ts @@ -4,7 +4,7 @@ import { VSBuffer } from 'vs/base/common/buffer'; import { Emitter } from 'vs/base/common/event'; import { FileAccess } from 'vs/base/common/network'; import { ISocket } from 'vs/base/parts/ipc/common/ipc.net'; -import { NodeSocket } from 'vs/base/parts/ipc/node/ipc.net'; +import { WebSocketNodeSocket } from 'vs/base/parts/ipc/node/ipc.net'; import { INativeEnvironmentService } from 'vs/platform/environment/common/environment'; import { getNlsConfiguration } from 'vs/server/node/nls'; import { Protocol } from 'vs/server/node/protocol'; @@ -88,7 +88,7 @@ export class ExtensionHostConnection extends Connection { private readonly logger: Logger; public constructor( - locale:string, protocol: Protocol, buffer: VSBuffer, token: string, + locale: string, protocol: Protocol, buffer: VSBuffer, token: string, private readonly environment: INativeEnvironmentService, ) { super(protocol, token); @@ -115,11 +115,18 @@ export class ExtensionHostConnection extends Connection { private sendInitMessage(buffer: VSBuffer): void { const socket = this.protocol.getUnderlyingSocket(); socket.pause(); + + const wrapperSocket = this.protocol.getSocket(); + this.logger.trace('Sending socket'); this.process!.send({ // Process must be set at this point. type: 'VSCODE_EXTHOST_IPC_SOCKET', - initialDataChunk: (buffer.buffer as Buffer).toString('base64'), - skipWebSocketFrames: this.protocol.getSocket() instanceof NodeSocket, + initialDataChunk: Buffer.from(buffer.buffer).toString('base64'), + skipWebSocketFrames: !(wrapperSocket instanceof WebSocketNodeSocket), + permessageDeflate: this.protocol.options.permessageDeflate, + inflateBytes: wrapperSocket instanceof WebSocketNodeSocket + ? Buffer.from(wrapperSocket.recordedInflateBytes.buffer).toString('base64') + : undefined, }, socket); } diff --git a/lib/vscode/src/vs/server/node/protocol.ts b/lib/vscode/src/vs/server/node/protocol.ts index af9bd1d99..15fa414e4 100644 --- a/lib/vscode/src/vs/server/node/protocol.ts +++ b/lib/vscode/src/vs/server/node/protocol.ts @@ -10,6 +10,9 @@ export interface SocketOptions { readonly reconnectionToken: string; readonly reconnection: boolean; readonly skipWebSocketFrames: boolean; + readonly permessageDeflate?: boolean; + readonly inflateBytes?: VSBuffer; + readonly recordInflateBytes?: boolean; } export class Protocol extends PersistentProtocol { @@ -17,7 +20,12 @@ export class Protocol extends PersistentProtocol { super( options.skipWebSocketFrames ? new NodeSocket(socket) - : new WebSocketNodeSocket(new NodeSocket(socket), false, null, false), + : new WebSocketNodeSocket( + new NodeSocket(socket), + options.permessageDeflate || false, + options.inflateBytes || null, + options.recordInflateBytes || false, + ), ); } diff --git a/lib/vscode/src/vs/server/node/server.ts b/lib/vscode/src/vs/server/node/server.ts index 65bb31f9e..c1b6e95ca 100644 --- a/lib/vscode/src/vs/server/node/server.ts +++ b/lib/vscode/src/vs/server/node/server.ts @@ -120,7 +120,7 @@ export class Vscode { }; } - public async handleWebSocket(socket: net.Socket, query: Query): Promise { + public async handleWebSocket(socket: net.Socket, query: Query, _permessageDeflate: boolean): Promise { if (!query.reconnectionToken) { throw new Error('Reconnection token is missing from query parameters'); } @@ -128,6 +128,7 @@ export class Vscode { reconnectionToken: query.reconnectionToken, reconnection: query.reconnection === 'true', skipWebSocketFrames: query.skipWebSocketFrames === 'true', + // TODO: permessageDeflate, }); try { await this.connect(await protocol.handshake(), protocol); diff --git a/src/node/routes/vscode.ts b/src/node/routes/vscode.ts index 38ac42bb1..4f1d14e9a 100644 --- a/src/node/routes/vscode.ts +++ b/src/node/routes/vscode.ts @@ -207,5 +207,8 @@ wsRouter.ws("/", ensureAuthenticated, async (req) => { `Sec-WebSocket-Accept: ${reply}`, ].join("\r\n") + "\r\n\r\n", ) - await vscode.sendWebsocket(req.ws, req.query) + // TODO: Parse this header properly. Currently unused so haven't bothered. + const extensions = req.headers["sec-websocket-extensions"] + const permessageDeflate = extensions ? extensions.includes("permessage-deflate") : false + await vscode.sendWebsocket(req.ws, req.query, permessageDeflate) }) diff --git a/src/node/vscode.ts b/src/node/vscode.ts index efdd74cad..44b46ec71 100644 --- a/src/node/vscode.ts +++ b/src/node/vscode.ts @@ -120,12 +120,12 @@ export class VscodeProvider { /** * VS Code expects a raw socket. It will handle all the web socket frames. */ - public async sendWebsocket(socket: net.Socket, query: ipc.Query): Promise { + public async sendWebsocket(socket: net.Socket, query: ipc.Query, permessageDeflate: boolean): Promise { const vscode = await this._vscode // TLS sockets cannot be transferred to child processes so we need an // in-between. Non-TLS sockets will be returned as-is. const socketProxy = await this.socketProvider.createProxy(socket) - this.send({ type: "socket", query }, vscode, socketProxy) + this.send({ type: "socket", query, permessageDeflate }, vscode, socketProxy) } private send(message: ipc.CodeServerMessage, vscode?: cp.ChildProcess, socket?: net.Socket): void {