Handle permessage-deflate on sockets

With this the extension host is working again.
This commit is contained in:
Asher 2021-03-02 16:42:25 -06:00
parent 150138e04b
commit 4d3d1b844d
No known key found for this signature in database
GPG Key ID: D63C1EF81242354A
7 changed files with 30 additions and 10 deletions

View File

@ -68,7 +68,7 @@ process.on('message', async (message: CodeServerMessage, socket) => {
} }
break; break;
case 'socket': case 'socket':
vscode.handleWebSocket(socket, message.query); vscode.handleWebSocket(socket, message.query, message.permessageDeflate);
break; break;
} }
}); });

View File

@ -19,6 +19,7 @@ export type Query = { [key: string]: string | string[] | undefined | Query | Que
export interface SocketMessage { export interface SocketMessage {
type: 'socket'; type: 'socket';
query: Query; query: Query;
permessageDeflate: boolean;
} }
export interface CliMessage { export interface CliMessage {

View File

@ -4,7 +4,7 @@ import { VSBuffer } from 'vs/base/common/buffer';
import { Emitter } from 'vs/base/common/event'; import { Emitter } from 'vs/base/common/event';
import { FileAccess } from 'vs/base/common/network'; import { FileAccess } from 'vs/base/common/network';
import { ISocket } from 'vs/base/parts/ipc/common/ipc.net'; 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 { INativeEnvironmentService } from 'vs/platform/environment/common/environment';
import { getNlsConfiguration } from 'vs/server/node/nls'; import { getNlsConfiguration } from 'vs/server/node/nls';
import { Protocol } from 'vs/server/node/protocol'; import { Protocol } from 'vs/server/node/protocol';
@ -115,11 +115,18 @@ export class ExtensionHostConnection extends Connection {
private sendInitMessage(buffer: VSBuffer): void { private sendInitMessage(buffer: VSBuffer): void {
const socket = this.protocol.getUnderlyingSocket(); const socket = this.protocol.getUnderlyingSocket();
socket.pause(); socket.pause();
const wrapperSocket = this.protocol.getSocket();
this.logger.trace('Sending socket'); this.logger.trace('Sending socket');
this.process!.send({ // Process must be set at this point. this.process!.send({ // Process must be set at this point.
type: 'VSCODE_EXTHOST_IPC_SOCKET', type: 'VSCODE_EXTHOST_IPC_SOCKET',
initialDataChunk: (buffer.buffer as Buffer).toString('base64'), initialDataChunk: Buffer.from(buffer.buffer).toString('base64'),
skipWebSocketFrames: this.protocol.getSocket() instanceof NodeSocket, skipWebSocketFrames: !(wrapperSocket instanceof WebSocketNodeSocket),
permessageDeflate: this.protocol.options.permessageDeflate,
inflateBytes: wrapperSocket instanceof WebSocketNodeSocket
? Buffer.from(wrapperSocket.recordedInflateBytes.buffer).toString('base64')
: undefined,
}, socket); }, socket);
} }

View File

@ -10,6 +10,9 @@ export interface SocketOptions {
readonly reconnectionToken: string; readonly reconnectionToken: string;
readonly reconnection: boolean; readonly reconnection: boolean;
readonly skipWebSocketFrames: boolean; readonly skipWebSocketFrames: boolean;
readonly permessageDeflate?: boolean;
readonly inflateBytes?: VSBuffer;
readonly recordInflateBytes?: boolean;
} }
export class Protocol extends PersistentProtocol { export class Protocol extends PersistentProtocol {
@ -17,7 +20,12 @@ export class Protocol extends PersistentProtocol {
super( super(
options.skipWebSocketFrames options.skipWebSocketFrames
? new NodeSocket(socket) ? 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,
),
); );
} }

View File

@ -120,7 +120,7 @@ export class Vscode {
}; };
} }
public async handleWebSocket(socket: net.Socket, query: Query): Promise<true> { public async handleWebSocket(socket: net.Socket, query: Query, _permessageDeflate: boolean): Promise<true> {
if (!query.reconnectionToken) { if (!query.reconnectionToken) {
throw new Error('Reconnection token is missing from query parameters'); throw new Error('Reconnection token is missing from query parameters');
} }
@ -128,6 +128,7 @@ export class Vscode {
reconnectionToken: <string>query.reconnectionToken, reconnectionToken: <string>query.reconnectionToken,
reconnection: query.reconnection === 'true', reconnection: query.reconnection === 'true',
skipWebSocketFrames: query.skipWebSocketFrames === 'true', skipWebSocketFrames: query.skipWebSocketFrames === 'true',
// TODO: permessageDeflate,
}); });
try { try {
await this.connect(await protocol.handshake(), protocol); await this.connect(await protocol.handshake(), protocol);

View File

@ -207,5 +207,8 @@ wsRouter.ws("/", ensureAuthenticated, async (req) => {
`Sec-WebSocket-Accept: ${reply}`, `Sec-WebSocket-Accept: ${reply}`,
].join("\r\n") + "\r\n\r\n", ].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)
}) })

View File

@ -120,12 +120,12 @@ export class VscodeProvider {
/** /**
* VS Code expects a raw socket. It will handle all the web socket frames. * VS Code expects a raw socket. It will handle all the web socket frames.
*/ */
public async sendWebsocket(socket: net.Socket, query: ipc.Query): Promise<void> { public async sendWebsocket(socket: net.Socket, query: ipc.Query, permessageDeflate: boolean): Promise<void> {
const vscode = await this._vscode const vscode = await this._vscode
// TLS sockets cannot be transferred to child processes so we need an // TLS sockets cannot be transferred to child processes so we need an
// in-between. Non-TLS sockets will be returned as-is. // in-between. Non-TLS sockets will be returned as-is.
const socketProxy = await this.socketProvider.createProxy(socket) 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 { private send(message: ipc.CodeServerMessage, vscode?: cp.ChildProcess, socket?: net.Socket): void {