-
-
Notifications
You must be signed in to change notification settings - Fork 2.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ws Server
errors on Node.js v10-12 http
server don't immediately destroy the Socket
like in Node 14+
#1940
Comments
This is probably caused by 8806aa9 but I'm not sure why behavior is different in Node.js <= 12. |
I think there is a race condition:
This guess is supported by the fact that I cannot reproduce the issue if I use a small buffer ( As a temporary workaround you can call |
I'm seeing the same behavior for a small buffer of Quite the tricky race condition here! I played around with the Observation: |
Yes, but I don't understand why the data is not flowing again after the error is emitted. Will dig more tomorrow. |
Here is a test case: const net = require('net');
const stream = require('stream');
const data = Buffer.alloc(15 * 1024 * 1024);
const server = net.createServer(function (socket) {
function onData(chunk) {
if (!writable.write(chunk)) {
socket.pause();
}
}
const writable = new stream.Writable({
write(chunk, encoding, callback) {
callback(new Error('Oops'));
}
});
writable.on('error', function (err) {
console.error(err);
socket.end();
socket.removeListener('data', onData);
socket.resume();
});
socket.on('data', onData);
socket.on('end', function () {
console.log('server end');
});
});
server.listen(function () {
const { port } = server.address();
const socket = net.createConnection({ port });
socket.on('connect', function () {
socket.write(data);
});
socket.on('end', function () {
console.log('client end');
});
socket.resume();
}); The problem is that the The following patch should fix the issue. diff --git a/lib/websocket.js b/lib/websocket.js
index f0b6eb5..142975e 100644
--- a/lib/websocket.js
+++ b/lib/websocket.js
@@ -1,3 +1,5 @@
+/* eslint no-unused-vars: ["error", { "varsIgnorePattern": "^Readable$" }] */
+
'use strict';
const EventEmitter = require('events');
@@ -6,6 +8,7 @@ const http = require('http');
const net = require('net');
const tls = require('tls');
const { randomBytes, createHash } = require('crypto');
+const { Readable } = require('stream');
const { URL } = require('url');
const PerMessageDeflate = require('./permessage-deflate');
@@ -983,7 +986,7 @@ function receiverOnError(err) {
const websocket = this[kWebSocket];
websocket._socket.removeListener('data', socketOnData);
- websocket._socket.resume();
+ process.nextTick(resume, websocket._socket);
websocket.close(err[kStatusCode]);
websocket.emit('error', err);
@@ -1032,6 +1035,16 @@ function receiverOnPong(data) {
this[kWebSocket].emit('pong', data);
}
+/**
+ * Resume a readable stream
+ *
+ * @param {Readable} stream The readable stream
+ * @private
+ */
+function resume(stream) {
+ stream.resume();
+}
+
/**
* The listener of the `net.Socket` `'close'` event.
* |
The same issue also occurred, on all Node.js versions, upon receipt of a large enough chunk of data that included a close frame. Thank you for reporting. |
Ensure that `socket.resume()` is called after `socket.pause()`. Fixes #1940
Ensure that `socket.resume()` is called after `socket.pause()`. Fixes #1940
In Node 14+
Socket
defaults to settingautoDestroy: true
. Thehttp
library uses these defaults internally. Thews
library behaves differently on Node v10-12 than it does on Node 14+ because of this internal change.In the example program below you'll find that on Node v10-12 the websocket connection will take exactly 30 seconds to close after a
maxPayload
size error occurs. But on Node v14 and up the closure is nearly instantaneous.I've been able to hack together a potential work around by listening for the
socket
's"finish"
event, and then forceablly callingincomingMessage.destroy()
:I doubt this is a good approach, especially across Node versions, as this is certainly calling
destroy
outside the socket's proper closure lifecycle. I know that in Node 14 this end up destroying the socket many process ticks before it would normally be destroyed. That said, maybe it is fine to calldestroy
here? It's difficulty to tell as I don't know Node.js Sockets well enough to be sure.I understand if this will not be considered an issue with the
ws
library, so please don't hesitate to close if that's the case; but hopefully this issue may shed light on the problem from someone else in the future either way.The text was updated successfully, but these errors were encountered: