review feedback

This commit is contained in:
Max Schmitt 2024-07-26 11:22:57 +02:00
parent f8d0ed0861
commit f09410885e

View file

@ -81,23 +81,19 @@ class SocksProxyConnection {
target!: net.Socket; target!: net.Socket;
// In case of http, we just pipe data to the target socket and they are |undefined|. // In case of http, we just pipe data to the target socket and they are |undefined|.
internal: stream.Duplex | undefined; internal: stream.Duplex | undefined;
_interceptClose = false; private _targetCloseEventListener: () => void;
constructor(socksProxy: ClientCertificatesProxy, uid: string, host: string, port: number) { constructor(socksProxy: ClientCertificatesProxy, uid: string, host: string, port: number) {
this.socksProxy = socksProxy; this.socksProxy = socksProxy;
this.uid = uid; this.uid = uid;
this.host = host; this.host = host;
this.port = port; this.port = port;
this._targetCloseEventListener = () => this.socksProxy._socksProxy.sendSocketEnd({ uid: this.uid });
} }
async connect() { async connect() {
this.target = await createSocket(rewriteToLocalhostIfNeeded(this.host), this.port); this.target = await createSocket(rewriteToLocalhostIfNeeded(this.host), this.port);
this.target.on('close', () => { this.target.on('close', this._targetCloseEventListener);
// In case of an 'error' event on the target connection, we still need to perform the http2 handshake on the browser side.
// This is an async operation, so we need to intercept the close event to prevent the socket from being closed too early.
if (!this._interceptClose)
this.socksProxy._socksProxy.sendSocketEnd({ uid: this.uid });
});
this.target.on('error', error => this.socksProxy._socksProxy.sendSocketError({ uid: this.uid, error: error.message })); this.target.on('error', error => this.socksProxy._socksProxy.sendSocketError({ uid: this.uid, error: error.message }));
this.socksProxy._socksProxy.socketConnected({ this.socksProxy._socksProxy.socketConnected({
uid: this.uid, uid: this.uid,
@ -181,9 +177,11 @@ class SocksProxyConnection {
if (internalTLS?.alpnProtocol === 'h2') { if (internalTLS?.alpnProtocol === 'h2') {
// This method is available only in Node.js 20+ // This method is available only in Node.js 20+
if ('performServerHandshake' in http2) { if ('performServerHandshake' in http2) {
this._interceptClose = true; // In case of an 'error' event on the target connection, we still need to perform the http2 handshake on the browser side.
// This is an async operation, so we need to intercept the close event to prevent the socket from being closed too early.
this.target.removeListener('close', this._targetCloseEventListener);
// @ts-expect-error // @ts-expect-error
const session = http2.performServerHandshake(internalTLS); const session: http2.ServerHttp2Session = http2.performServerHandshake(internalTLS);
session.on('stream', (stream: http2.ServerHttp2Stream) => { session.on('stream', (stream: http2.ServerHttp2Stream) => {
stream.respond({ stream.respond({
'content-type': 'text/html', 'content-type': 'text/html',
@ -193,6 +191,7 @@ class SocksProxyConnection {
session.close(); session.close();
closeBothSockets(); closeBothSockets();
}); });
stream.on('error', () => closeBothSockets());
}); });
} else { } else {
closeBothSockets(); closeBothSockets();