From b1247c6b065350a4268f9df767ca33f21af74e7d Mon Sep 17 00:00:00 2001 From: DudaGod Date: Wed, 31 Jul 2019 07:39:42 +0300 Subject: [PATCH] fix: correctly close half-opened ws socket --- lib/http-proxy/passes/ws-incoming.js | 5 ++++- lib/http-proxy/ws/interceptor.js | 23 +++++++++++++---------- 2 files changed, 17 insertions(+), 11 deletions(-) diff --git a/lib/http-proxy/passes/ws-incoming.js b/lib/http-proxy/passes/ws-incoming.js index 8e510737b..bafdf567d 100644 --- a/lib/http-proxy/passes/ws-incoming.js +++ b/lib/http-proxy/passes/ws-incoming.js @@ -131,10 +131,13 @@ module.exports = { // The pipe below will end proxySocket if socket closes cleanly, but not // if it errors (eg, vanishes from the net and starts returning // EHOSTUNREACH). We need to do that explicitly. - socket.on('error', function () { + socket.on('error', function (err) { + console.error('ERROR: socket closed with:', err); proxySocket.end(); }); + socket.on('end', () => socket.end()); + common.setupSocket(proxySocket); if (proxyHead && proxyHead.length) proxySocket.unshift(proxyHead); diff --git a/lib/http-proxy/ws/interceptor.js b/lib/http-proxy/ws/interceptor.js index 10a6ffd9d..a3f2c6bbc 100644 --- a/lib/http-proxy/ws/interceptor.js +++ b/lib/http-proxy/ws/interceptor.js @@ -31,15 +31,15 @@ module.exports = class Interceptor { this._proxyReq = proxyReq; this._proxyRes = proxyRes; this._proxySocket = proxySocket; - this._isSocketOpened = true; + this._isClientSocketOpen = true; + this._isServerSocketOpen = true; this._configure(); } _configure() { - this._proxySocket.on('close', () => { - this._isSocketOpened = false; - }); + this._proxySocket.on('close', () => this._isClientSocketOpen = false); + this._socket.on('close', () => this._isServerSocketOpen = false); const secWsExtensions = this._proxyRes.headers['sec-websocket-extensions']; const extensions = Extensions.parse(secWsExtensions); @@ -50,10 +50,11 @@ module.exports = class Interceptor { this._serverExtensions = this._isCompressed ? acceptExtensions({extensions, isServer: true}) : null; } - _getDataSender({sender, event, options}) { + _getDataSender({sender, dataSendCond, event, options}) { return ({data, binary = false}) => { const opts = Object.assign({fin: true, compress: this._isCompressed, binary}, options); - sender.send(data, opts); + + dataSendCond() && sender.send(data, opts); this._proxyReq.emit(event, {data, binary}); }; @@ -82,11 +83,12 @@ module.exports = class Interceptor { // frame must be masked when send from client to server - https://tools.ietf.org/html/rfc6455#section-5.3 const options = {mask: true}; - const dataSender = this._getDataSender({sender, event: 'wsClientMsg', options}); + const dataSendCond = () => this._isClientSocketOpen; + const dataSender = this._getDataSender({sender, dataSendCond, event: 'wsClientMsg', options}); receiver.ontext = this._getMsgHandler({interceptor: this._options.wsInterceptClientMsg, dataSender, binary: false}); receiver.onbinary = this._getMsgHandler({interceptor: this._options.wsInterceptClientMsg, dataSender, binary: true}); - receiver.onclose = (code, msg, {masked: mask}) => this._isSocketOpened && sender.close(code, msg, mask); + receiver.onclose = (code, msg, {masked: mask}) => this._isClientSocketOpen && sender.close(code, msg, mask); this._socket.on('data', (data) => receiver.add(data)); } @@ -97,11 +99,12 @@ module.exports = class Interceptor { this._proxyReq.emit('serverSenderInited', sender); const options = {mask: false}; - const dataSender = this._getDataSender({sender, event: 'wsServerMsg', options}); + const dataSendCond = () => this._isServerSocketOpen; + const dataSender = this._getDataSender({sender, dataSendCond, event: 'wsServerMsg', options}); receiver.ontext = this._getMsgHandler({interceptor: this._options.wsInterceptServerMsg, dataSender, binary: false}); receiver.onbinary = this._getMsgHandler({interceptor: this._options.wsInterceptServerMsg, dataSender, binary: true}); - receiver.onclose = (code, msg, {masked: mask}) => this._isSocketOpened && sender.close(code, msg, mask); + receiver.onclose = (code, msg, {masked: mask}) => this._isServerSocketOpen && sender.close(code, msg, mask); this._proxySocket.on('data', (data) => receiver.add(data)); }