import { tap, expect } from '@git.zone/tstest/tapbundle'; import { SmartProxy } from '../ts/index.js'; import * as net from 'net'; // Test that verifies HTTP connections on ports configured in useHttpProxy are properly forwarded tap.test('should detect and forward non-TLS connections on HttpProxy ports', async (tapTest) => { // Track whether the connection was forwarded to HttpProxy let forwardedToHttpProxy = false; let connectionPath = ''; // Create a SmartProxy instance first const proxy = new SmartProxy({ useHttpProxy: [8080], httpProxyPort: 8844, routes: [{ name: 'test-http-forward', match: { ports: 8080 }, action: { type: 'forward', target: { host: 'localhost', port: 8181 } } }] }); // Mock the HttpProxy forwarding on the instance const originalForward = (proxy as any).httpProxyBridge.forwardToHttpProxy; (proxy as any).httpProxyBridge.forwardToHttpProxy = async function(...args: any[]) { forwardedToHttpProxy = true; connectionPath = 'httpproxy'; console.log('Mock: Connection forwarded to HttpProxy'); // Just close the connection for the test args[1].end(); // socket.end() }; // Add detailed logging to the existing proxy instance proxy.settings.enableDetailedLogging = true; // Override the HttpProxy initialization to avoid actual HttpProxy setup proxy['httpProxyBridge'].getHttpProxy = () => ({} as any); await proxy.start(); // Make a connection to port 8080 const client = new net.Socket(); await new Promise((resolve, reject) => { client.connect(8080, 'localhost', () => { console.log('Client connected to proxy on port 8080'); // Send a non-TLS HTTP request client.write('GET / HTTP/1.1\r\nHost: test.local\r\n\r\n'); resolve(); }); client.on('error', reject); }); // Give it a moment to process await new Promise(resolve => setTimeout(resolve, 100)); // Verify the connection was forwarded to HttpProxy expect(forwardedToHttpProxy).toEqual(true); expect(connectionPath).toEqual('httpproxy'); client.destroy(); await proxy.stop(); // Restore original method // Restore original method (proxy as any).httpProxyBridge.forwardToHttpProxy = originalForward; }); // Test that verifies the fix detects non-TLS connections tap.test('should properly detect non-TLS connections on HttpProxy ports', async (tapTest) => { const targetPort = 8182; let receivedConnection = false; // Create a target server that never receives the connection (because it goes to HttpProxy) const targetServer = net.createServer((socket) => { receivedConnection = true; socket.end(); }); await new Promise((resolve) => { targetServer.listen(targetPort, () => { console.log(`Target server listening on port ${targetPort}`); resolve(); }); }); // Mock HttpProxyBridge to track forwarding let httpProxyForwardCalled = false; const proxy = new SmartProxy({ useHttpProxy: [8080], httpProxyPort: 8844, routes: [{ name: 'test-route', match: { ports: 8080 }, action: { type: 'forward', target: { host: 'localhost', port: targetPort } } }] }); // Override the forwardToHttpProxy method to track calls const originalForward = proxy['httpProxyBridge'].forwardToHttpProxy; proxy['httpProxyBridge'].forwardToHttpProxy = async function(...args: any[]) { httpProxyForwardCalled = true; console.log('HttpProxy forward called with connectionId:', args[0]); // Just end the connection args[1].end(); }; // Mock getHttpProxy to return a truthy value proxy['httpProxyBridge'].getHttpProxy = () => ({} as any); await proxy.start(); // Make a non-TLS connection const client = new net.Socket(); await new Promise((resolve, reject) => { client.connect(8080, 'localhost', () => { console.log('Connected to proxy'); client.write('GET / HTTP/1.1\r\nHost: test.local\r\n\r\n'); resolve(); }); client.on('error', () => resolve()); // Ignore errors since we're ending the connection }); await new Promise(resolve => setTimeout(resolve, 100)); // Verify that HttpProxy was called, not direct connection expect(httpProxyForwardCalled).toEqual(true); expect(receivedConnection).toEqual(false); // Target should not receive direct connection client.destroy(); await proxy.stop(); await new Promise((resolve) => { targetServer.close(() => resolve()); }); // Restore original method proxy['httpProxyBridge'].forwardToHttpProxy = originalForward; }); tap.start();