Skip to content

Commit

Permalink
Improve handling of debugging WebSocket messages (#1258)
Browse files Browse the repository at this point in the history
  • Loading branch information
isc-bsaviano authored Oct 26, 2023
1 parent a1ff0ed commit 9809670
Show file tree
Hide file tree
Showing 3 changed files with 45 additions and 30 deletions.
36 changes: 18 additions & 18 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -1685,7 +1685,7 @@
"@types/mocha": "^7.0.2",
"@types/node": "^14.18.0",
"@types/vscode": "1.75.0",
"@types/ws": "^7.2.5",
"@types/ws": "8.5.4",
"@types/xmldom": "^0.1.29",
"@typescript-eslint/eslint-plugin": "^4.32.0",
"@typescript-eslint/parser": "^4.32.0",
Expand Down Expand Up @@ -1720,6 +1720,6 @@
"@vscode/debugadapter": "^1.61.0",
"@vscode/debugprotocol": "^1.61.0",
"vscode-extension-telemetry": "^0.1.6",
"ws": "^7.4.6"
"ws": "^8.14.2"
}
}
35 changes: 25 additions & 10 deletions src/debug/dbgp.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,23 @@ export class DbgpConnection extends EventEmitter {
private _chunks: Buffer[];
private _dataLength: number;
private _parser: DOMParser;
private _messages: Buffer[] = [];
private _processingMessages = false;

public constructor(socket: WebSocket) {
super();
this._socket = socket;
this._parsingState = ParsingState.DataLength;
this._chunksDataLength = 0;
this._chunks = [];
socket.on("message", (data: string): void => this._handleDataChunk(Buffer.from(data)));
socket.on("message", (data: string): void => {
this._messages.push(Buffer.from(data));
if (!this._processingMessages) {
this._processingMessages = true;
this._handleDataChunk();
this._processingMessages = false;
}
});
socket.on("error", (error: Error): boolean => this.emit("error", error));
socket.on("close", (): boolean => this.emit("close"));
this._parser = new DOMParser({
Expand Down Expand Up @@ -61,7 +70,9 @@ export class DbgpConnection extends EventEmitter {
});
}

private _handleDataChunk(data: Buffer) {
private _handleDataChunk() {
if (!this._messages.length) return; // Shouldn't ever happen
const data: Buffer = this._messages.shift();
if (this._parsingState === ParsingState.DataLength) {
// does data contain a NULL byte?
const separatorIndex = data.indexOf("|");
Expand All @@ -80,11 +91,13 @@ export class DbgpConnection extends EventEmitter {
if (data.length > separatorIndex + 1) {
// handle the rest of the packet as part of the response
const rest = data.slice(separatorIndex + 1, this._dataLength + separatorIndex + 1);
this._handleDataChunk(rest);
this._messages.unshift(rest);
this._handleDataChunk();
// more then one data chunk in one message
const restData = data.slice(this._dataLength + separatorIndex + 1);
if (restData.length) {
this._handleDataChunk(restData);
this._messages.unshift(restData);
this._handleDataChunk();
}
}
} else {
Expand All @@ -99,7 +112,7 @@ export class DbgpConnection extends EventEmitter {
// append the last piece of the response
const lastResponsePiece = data.slice(0, this._dataLength - this._chunksDataLength);
this._chunks.push(lastResponsePiece);
this._chunksDataLength += data.length;
this._chunksDataLength += lastResponsePiece.length;
const response = Buffer.concat(this._chunks, this._chunksDataLength).toString("ascii");
// call response handler
const xml = iconv.decode(Buffer.from(response, "base64"), ENCODING);
Expand All @@ -110,17 +123,19 @@ export class DbgpConnection extends EventEmitter {
this._chunksDataLength = 0;
// switch to data length parsing state
this._parsingState = ParsingState.DataLength;
// if data contains more info (except the NULL byte)
if (data.length > lastResponsePiece.length + 1) {
// handle the rest of the packet (after the NULL byte) as data length
const rest = data.slice(lastResponsePiece.length + 1);
this._handleDataChunk(rest);
// if data contains more info
if (data.length > lastResponsePiece.length) {
// handle the rest of the packet as data length
const rest = data.slice(lastResponsePiece.length);
this._messages.unshift(rest);
this._handleDataChunk();
}
} else {
// NO -> this is not the whole response yet. We buffer it and wait for the next data event.
this._chunks.push(data);
this._chunksDataLength += data.length;
}
}
while (this._messages.length) this._handleDataChunk();
}
}

0 comments on commit 9809670

Please sign in to comment.