Stream read errors result in uncaught exceptions
hansonw opened this issue · 11 comments
Currently, message errors from StreamMessageReader's onData method end up as uncaught exceptions, which can be very difficult to handle when used in server contexts.
Would it be reasonable to convert such errors into error events (via this.fireError
) so that the stream owner can perform shutdown / restart steps as necessary? I can submit a PR to do so. cc @ljw1004
Yes, but we should clearly defined that the readere then moves into an error state and doesn't process any new onData events since it can not meaningful recover from a missing content length.
Any workaround? It is really really bad if your server crashes just because some LSP stream got broken. Depending on context, could be a security vulnerability.
The got improved already an errors are now reported on the connection. What esle do you expect the reader to do if it receives a broken message
When an error occurs, the entire Node.js process is crashed for me. Do I have to register an error handler to prevent this from happening, or am I doing something else wrong that is causing me to mistakenly blame this package?
Not sure I understand that correctly. The server node process crashes ?
Yes. The Node.js process that is running vscode-languageserver-node crashes (after printing stack trace from vscode-languageserver-node).
What seems strange to me is that the node process crashes. It shouldn't :-)
But I am open for a PR that converts the exception into a fireError.
In particular this is what is printed before the server crashes.
/home/docker/src/node_modules/vscode-jsonrpc/lib/messageReader.js:163
throw new Error('Header must provide a Content-Length property.');
^
Error: Header must provide a Content-Length property.
at StreamMessageReader.onData (/home/docker/src/node_modules/vscode-jsonrpc/lib/messageReader.js:163:27)
at Socket.<anonymous> (/home/docker/src/node_modules/vscode-jsonrpc/lib/messageReader.js:148:18)
at Socket.emit (events.js:314:20)
at addChunk (_stream_readable.js:303:12)
at readableAddChunk (_stream_readable.js:279:9)
at Socket.Readable.push (_stream_readable.js:218:10)
at Pipe.onStreamRead (internal/stream_base_commons.js:188:23)
What seems strange to me is that the node process crashes. It shouldn't :-)
I just tested, and uncaught exceptions do (in general) crash Node. I believe this is intended behavior. Test:
% node -e "setTimeout(() => { throw new Error('foo') }, 1000); setTimeout(() => console.log('done'), 2000)"
[eval]:1
setTimeout(() => { throw new Error('foo') }, 1000); setTimeout(() => console.log('done'), 2000)
^
Error: foo
at Timeout._onTimeout ([eval]:1:26)
at listOnTimeout (internal/timers.js:551:17)
at processTimers (internal/timers.js:494:7)
OK. Now I understand. Under crash I was assuming a real process crash.
For the servers I maintain I have a process.on('uncaughtException', (error: any) => { ... })
handler since exception can occur in other parts of your server as well.
This got addressed in the meantime. The exception are now reported via the onError
event.