Skip to content

Commit 864c8c5

Browse files
authored
Dbaeumer/frail-salamander-amber (#1311)
* Improve error handling. * Fix tests
1 parent fb0a3d4 commit 864c8c5

File tree

4 files changed

+48
-40
lines changed

4 files changed

+48
-40
lines changed

client/src/common/client.ts

+4-1
Original file line numberDiff line numberDiff line change
@@ -1636,10 +1636,13 @@ export abstract class BaseLanguageClient implements FeatureClient<Middleware, La
16361636
private async handleConnectionError(error: Error, message: Message | undefined, count: number | undefined): Promise<void> {
16371637
const handlerResult: ErrorHandlerResult = await this._clientOptions.errorHandler!.error(error, message, count);
16381638
if (handlerResult.action === ErrorAction.Shutdown) {
1639-
this.error(handlerResult.message ?? `Client ${this._name}: connection to server is erroring. Shutting down server.`, undefined, handlerResult.handled === true ? false : 'force');
1639+
this.error(handlerResult.message ?? `Client ${this._name}: connection to server is erroring.\n${error.message}\nShutting down server.`, undefined, handlerResult.handled === true ? false : 'force');
16401640
this.stop().catch((error) => {
16411641
this.error(`Stopping server failed`, error, false);
16421642
});
1643+
} else {
1644+
this.error(handlerResult.message ??
1645+
`Client ${this._name}: connection to server is erroring.\n${error.message}`, undefined, handlerResult.handled === true ? false : 'force');
16431646
}
16441647
}
16451648

jsonrpc/src/common/messageBuffer.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ export abstract class AbstractMessageBuffer implements RAL.MessageBuffer {
100100
const header = headers[i];
101101
const index: number = header.indexOf(':');
102102
if (index === -1) {
103-
throw new Error('Message header must separate key and value using :');
103+
throw new Error(`Message header must separate key and value using ':'\n${header}`);
104104
}
105105
const key = header.substr(0, index);
106106
const value = header.substr(index + 1).trim();

jsonrpc/src/common/messageReader.ts

+41-36
Original file line numberDiff line numberDiff line change
@@ -211,46 +211,51 @@ export class ReadableStreamMessageReader extends AbstractMessageReader {
211211
}
212212

213213
private onData(data: Uint8Array): void {
214-
this.buffer.append(data);
215-
while (true) {
216-
if (this.nextMessageLength === -1) {
217-
const headers = this.buffer.tryReadHeaders(true);
218-
if (!headers) {
219-
return;
220-
}
221-
const contentLength = headers.get('content-length');
222-
if (!contentLength) {
223-
this.fireError(new Error('Header must provide a Content-Length property.'));
224-
return;
214+
try {
215+
216+
this.buffer.append(data);
217+
while (true) {
218+
if (this.nextMessageLength === -1) {
219+
const headers = this.buffer.tryReadHeaders(true);
220+
if (!headers) {
221+
return;
222+
}
223+
const contentLength = headers.get('content-length');
224+
if (!contentLength) {
225+
this.fireError(new Error(`Header must provide a Content-Length property.\n${JSON.stringify(Object.fromEntries(headers))}`));
226+
return;
227+
}
228+
const length = parseInt(contentLength);
229+
if (isNaN(length)) {
230+
this.fireError(new Error(`Content-Length value must be a number. Got ${contentLength}`));
231+
return;
232+
}
233+
this.nextMessageLength = length;
225234
}
226-
const length = parseInt(contentLength);
227-
if (isNaN(length)) {
228-
this.fireError(new Error('Content-Length value must be a number.'));
235+
const body = this.buffer.tryReadBody(this.nextMessageLength);
236+
if (body === undefined) {
237+
/** We haven't received the full message yet. */
238+
this.setPartialMessageTimer();
229239
return;
230240
}
231-
this.nextMessageLength = length;
232-
}
233-
const body = this.buffer.tryReadBody(this.nextMessageLength);
234-
if (body === undefined) {
235-
/** We haven't received the full message yet. */
236-
this.setPartialMessageTimer();
237-
return;
241+
this.clearPartialMessageTimer();
242+
this.nextMessageLength = -1;
243+
// Make sure that we convert one received message after the
244+
// other. Otherwise it could happen that a decoding of a second
245+
// smaller message finished before the decoding of a first larger
246+
// message and then we would deliver the second message first.
247+
this.readSemaphore.lock(async () => {
248+
const bytes: Uint8Array = this.options.contentDecoder !== undefined
249+
? await this.options.contentDecoder.decode(body)
250+
: body;
251+
const message = await this.options.contentTypeDecoder.decode(bytes, this.options);
252+
this.callback(message);
253+
}).catch((error) => {
254+
this.fireError(error);
255+
});
238256
}
239-
this.clearPartialMessageTimer();
240-
this.nextMessageLength = -1;
241-
// Make sure that we convert one received message after the
242-
// other. Otherwise it could happen that a decoding of a second
243-
// smaller message finished before the decoding of a first larger
244-
// message and then we would deliver the second message first.
245-
this.readSemaphore.lock(async () => {
246-
const bytes: Uint8Array = this.options.contentDecoder !== undefined
247-
? await this.options.contentDecoder.decode(body)
248-
: body;
249-
const message = await this.options.contentTypeDecoder.decode(bytes, this.options);
250-
this.callback(message);
251-
}).catch((error) => {
252-
this.fireError(error);
253-
});
257+
} catch (error) {
258+
this.fireError(error);
254259
}
255260
}
256261

jsonrpc/src/node/test/messages.test.ts

+2-2
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ suite('Messages', () => {
329329
assert.fail('Should not parse a message without a Content-Length');
330330
});
331331
reader.onError((err) => {
332-
assert.strictEqual(err.message, 'Header must provide a Content-Length property.');
332+
assert.strictEqual(err.message, 'Header must provide a Content-Length property.\n{"not-content-length":"43"}');
333333
done();
334334
});
335335
readable.push('Not-Content-Length: 43\r\n\r\n{"jsonrpc":"2.0","id":1,"method":"example"}');
@@ -343,7 +343,7 @@ suite('Messages', () => {
343343
assert.fail('Should not parse a message without a Content-Length');
344344
});
345345
reader.onError((err) => {
346-
assert.strictEqual(err.message, 'Content-Length value must be a number.');
346+
assert.strictEqual(err.message, 'Content-Length value must be a number. Got NaN');
347347
done();
348348
});
349349
readable.push('Content-Length: NaN\r\n\r\n{"jsonrpc":"2.0","id":1,"method":"example"}');

0 commit comments

Comments
 (0)