Skip to content

Commit 518a718

Browse files
committed
fix: correctly close half-opened socket
1 parent e9ef418 commit 518a718

File tree

2 files changed

+20
-11
lines changed

2 files changed

+20
-11
lines changed

lib/http-proxy/passes/ws-incoming.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -131,10 +131,13 @@ module.exports = {
131131
// The pipe below will end proxySocket if socket closes cleanly, but not
132132
// if it errors (eg, vanishes from the net and starts returning
133133
// EHOSTUNREACH). We need to do that explicitly.
134-
socket.on('error', function () {
134+
socket.on('error', function (err) {
135+
console.warn('WARN: socket closed with error:', err);
135136
proxySocket.end();
136137
});
137138

139+
socket.on('end', () => socket.end());
140+
138141
common.setupSocket(proxySocket);
139142

140143
if (proxyHead && proxyHead.length) proxySocket.unshift(proxyHead);

lib/http-proxy/ws/interceptor.js

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,15 @@ module.exports = class Interceptor {
3131
this._proxyReq = proxyReq;
3232
this._proxyRes = proxyRes;
3333
this._proxySocket = proxySocket;
34-
this._isSocketOpened = true;
34+
this._isClientSocketOpened = true;
35+
this._isServerSocketOpened = true;
3536

3637
this._configure();
3738
}
3839

3940
_configure() {
40-
this._proxySocket.on('close', () => {
41-
this._isSocketOpened = false;
42-
});
41+
this._proxySocket.on('close', () => this._isClientSocketOpened = false);
42+
this._socket.on('close', () => this._isServerSocketOpened = false);
4343

4444
const secWsExtensions = this._proxyRes.headers['sec-websocket-extensions'];
4545
const extensions = Extensions.parse(secWsExtensions);
@@ -50,10 +50,12 @@ module.exports = class Interceptor {
5050
this._serverExtensions = this._isCompressed ? acceptExtensions({extensions, isServer: true}) : null;
5151
}
5252

53-
_getDataSender({sender, event, options}) {
53+
_getDataSender({sender, type, event, options}) {
5454
return ({data, binary = false}) => {
5555
const opts = Object.assign({fin: true, compress: this._isCompressed, binary}, options);
56-
sender.send(data, opts);
56+
const condition = type === 'client' ? this._isClientSocketOpened : this._isServerSocketOpened;
57+
58+
condition && sender.send(data, opts);
5759

5860
this._proxyReq.emit(event, {data, binary});
5961
};
@@ -82,11 +84,13 @@ module.exports = class Interceptor {
8284

8385
// frame must be masked when send from client to server - https://tools.ietf.org/html/rfc6455#section-5.3
8486
const options = {mask: true};
85-
const dataSender = this._getDataSender({sender, event: 'wsClientMsg', options});
87+
const dataSender = this._getDataSender({sender, type: 'client', event: 'wsClientMsg', options});
8688

8789
receiver.ontext = this._getMsgHandler({interceptor: this._options.wsInterceptClientMsg, dataSender, binary: false});
8890
receiver.onbinary = this._getMsgHandler({interceptor: this._options.wsInterceptClientMsg, dataSender, binary: true});
89-
receiver.onclose = (code, msg, {masked: mask}) => this._isSocketOpened && sender.close(code, msg, mask);
91+
receiver.onclose = (code, msg, {masked: mask}) => {
92+
this._isClientSocketOpened && sender.close(code, msg, mask);
93+
};
9094

9195
this._socket.on('data', (data) => receiver.add(data));
9296
}
@@ -97,11 +101,13 @@ module.exports = class Interceptor {
97101
this._proxyReq.emit('serverSenderInited', sender);
98102

99103
const options = {mask: false};
100-
const dataSender = this._getDataSender({sender, event: 'wsServerMsg', options});
104+
const dataSender = this._getDataSender({sender, type: 'server', event: 'wsServerMsg', options});
101105

102106
receiver.ontext = this._getMsgHandler({interceptor: this._options.wsInterceptServerMsg, dataSender, binary: false});
103107
receiver.onbinary = this._getMsgHandler({interceptor: this._options.wsInterceptServerMsg, dataSender, binary: true});
104-
receiver.onclose = (code, msg, {masked: mask}) => this._isSocketOpened && sender.close(code, msg, mask);
108+
receiver.onclose = (code, msg, {masked: mask}) => {
109+
this._isServerSocketOpened && sender.close(code, msg, mask);
110+
};
105111

106112
this._proxySocket.on('data', (data) => receiver.add(data));
107113
}

0 commit comments

Comments
 (0)