update
This commit is contained in:
		| @@ -124,4 +124,4 @@ tap.test('should parse HTTP headers correctly', async (tools) => { | ||||
|   await proxy.stop(); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -159,4 +159,4 @@ tap.test('should return 404 for non-existent challenge tokens', async (tapTest) | ||||
|   await proxy.stop(); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -215,4 +215,4 @@ tap.test('should handle HTTP request parsing correctly', async (tools) => { | ||||
|   await proxy.stop(); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -117,4 +117,4 @@ tap.test('should configure ACME challenge route', async () => { | ||||
|   expect(challengeRoute.action.socketHandler).toBeDefined(); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -119,4 +119,4 @@ tap.test('should defer certificate provisioning until ports are ready', async (t | ||||
|   await proxy.stop(); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -238,4 +238,4 @@ tap.test('should renew certificates', async () => { | ||||
|   await proxy.stop(); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -57,4 +57,4 @@ tap.test('should handle socket handler route type', async () => { | ||||
|   expect(route.action.socketHandler).toBeDefined(); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -143,4 +143,4 @@ tap.test('cleanup queue bug - verify queue processing handles more than batch si | ||||
|   console.log('\n✓ Test complete: Cleanup queue now correctly processes all connections'); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -239,4 +239,4 @@ tap.test('should handle clients that error during connection', async () => { | ||||
|   console.log('\n✅ PASS: Connection error cleanup working correctly!'); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -276,4 +276,4 @@ tap.test('comprehensive connection cleanup test - all scenarios', async () => { | ||||
|   console.log('- NFTables connections'); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -296,4 +296,4 @@ tap.test('Cleanup and shutdown', async () => { | ||||
|   allServers.length = 0; | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -1,286 +0,0 @@ | ||||
| import { expect, tap } from '@git.zone/tstest/tapbundle'; | ||||
| import * as smartproxy from '../ts/index.js'; | ||||
| import * as net from 'net'; | ||||
| import * as crypto from 'crypto'; | ||||
|  | ||||
| tap.test('Connection Stability - Fragment Cleanup', async () => { | ||||
|   // Create a simple TCP server | ||||
|   const server = net.createServer(); | ||||
|   await new Promise<void>((resolve) => { | ||||
|     server.listen(0, '127.0.0.1', () => resolve()); | ||||
|   }); | ||||
|   const serverPort = (server.address() as net.AddressInfo).port; | ||||
|  | ||||
|   // Configure a route | ||||
|   const routes: smartproxy.IRouteConfig[] = [{ | ||||
|     match: { | ||||
|       ports: 9000, | ||||
|       domains: '*' | ||||
|     }, | ||||
|     action: { | ||||
|       type: 'forward', | ||||
|       target: { | ||||
|         host: '127.0.0.1', | ||||
|         port: serverPort | ||||
|       } | ||||
|     } | ||||
|   }]; | ||||
|    | ||||
|   // Create SmartProxy instance with routes | ||||
|   const proxy = new smartproxy.SmartProxy({  | ||||
|     keepAliveTimeoutMs: 5000, | ||||
|     routes  | ||||
|   }); | ||||
|    | ||||
|   await proxy.start(); | ||||
|  | ||||
|   // Test 1: Send fragmented TLS hello | ||||
|   const tlsHello = Buffer.concat([ | ||||
|     Buffer.from([0x16, 0x03, 0x03]), // TLS handshake, version 1.2 | ||||
|     Buffer.from([0x00, 0x50]), // Length: 80 bytes | ||||
|     Buffer.from([0x01]), // ClientHello | ||||
|     Buffer.from([0x00, 0x00, 0x4c]), // Handshake length | ||||
|     Buffer.from([0x03, 0x03]), // TLS 1.2 | ||||
|     crypto.randomBytes(32), // Random | ||||
|     Buffer.from([0x00]), // Session ID length | ||||
|     Buffer.from([0x00, 0x04]), // Cipher suites length | ||||
|     Buffer.from([0xc0, 0x2f, 0xc0, 0x30]), // Cipher suites | ||||
|     Buffer.from([0x01, 0x00]), // Compression methods | ||||
|     Buffer.from([0x00, 0x1f]), // Extensions length | ||||
|     // SNI extension | ||||
|     Buffer.from([0x00, 0x00]), // Server name extension | ||||
|     Buffer.from([0x00, 0x1b]), // Extension length | ||||
|     Buffer.from([0x00, 0x19]), // Server name list length | ||||
|     Buffer.from([0x00]), // Host name type | ||||
|     Buffer.from([0x00, 0x16]), // Name length | ||||
|     Buffer.from('test.example.com') // Server name | ||||
|   ]); | ||||
|  | ||||
|   // Function to check fragment manager size | ||||
|   const getFragmentCount = () => { | ||||
|     // Access the fragment manager through the singleton | ||||
|     const detector = (smartproxy.detection.ProtocolDetector as any).getInstance(); | ||||
|     const tlsFragments = detector.fragmentManager.getHandler('tls'); | ||||
|     const httpFragments = detector.fragmentManager.getHandler('http'); | ||||
|     return tlsFragments.size + httpFragments.size; | ||||
|   }; | ||||
|  | ||||
|   // Test fragmented connections | ||||
|   const connections: net.Socket[] = []; | ||||
|    | ||||
|   // Create multiple fragmented connections | ||||
|   for (let i = 0; i < 5; i++) { | ||||
|     const client = new net.Socket(); | ||||
|     connections.push(client); | ||||
|      | ||||
|     await new Promise<void>((resolve, reject) => { | ||||
|       client.connect(9000, '127.0.0.1', () => { | ||||
|         // Send first fragment | ||||
|         client.write(tlsHello.subarray(0, 20)); | ||||
|         resolve(); | ||||
|       }); | ||||
|       client.on('error', reject); | ||||
|     }); | ||||
|   } | ||||
|  | ||||
|   // Give time for fragments to accumulate | ||||
|   await new Promise(resolve => setTimeout(resolve, 100)); | ||||
|  | ||||
|   // Check that fragments are being tracked | ||||
|   const fragmentCount = getFragmentCount(); | ||||
|   expect(fragmentCount).toBeGreaterThan(0); | ||||
|  | ||||
|   // Send remaining fragments and close connections | ||||
|   for (const client of connections) { | ||||
|     client.write(tlsHello.subarray(20)); | ||||
|     client.end(); | ||||
|   } | ||||
|  | ||||
|   // Wait for connections to close | ||||
|   await new Promise(resolve => setTimeout(resolve, 500)); | ||||
|  | ||||
|   // Check that fragments are cleaned up | ||||
|   const finalFragmentCount = getFragmentCount(); | ||||
|   expect(finalFragmentCount).toEqual(0); | ||||
|  | ||||
|   // Cleanup | ||||
|   await proxy.stop(); | ||||
|   server.close(); | ||||
| }); | ||||
|  | ||||
| tap.test('Connection Stability - Memory Leak Prevention', async () => { | ||||
|   // Create a simple echo server | ||||
|   const server = net.createServer((socket) => { | ||||
|     socket.pipe(socket); | ||||
|   }); | ||||
|    | ||||
|   await new Promise<void>((resolve) => { | ||||
|     server.listen(0, '127.0.0.1', () => resolve()); | ||||
|   }); | ||||
|   const serverPort = (server.address() as net.AddressInfo).port; | ||||
|  | ||||
|   // Configure a route | ||||
|   const routes: smartproxy.IRouteConfig[] = [{ | ||||
|     match: { | ||||
|       ports: 9001, | ||||
|       domains: '*' | ||||
|     }, | ||||
|     action: { | ||||
|       type: 'forward', | ||||
|       target: { | ||||
|         host: '127.0.0.1', | ||||
|         port: serverPort | ||||
|       } | ||||
|     } | ||||
|   }]; | ||||
|    | ||||
|   // Create SmartProxy instance with routes | ||||
|   const proxy = new smartproxy.SmartProxy({  | ||||
|     keepAliveTimeoutMs: 5000, | ||||
|     routes  | ||||
|   }); | ||||
|    | ||||
|   await proxy.start(); | ||||
|  | ||||
|   // Function to get active connection count | ||||
|   const getConnectionCount = () => { | ||||
|     const connectionManager = (proxy as any).connectionManager; | ||||
|     return connectionManager.getActiveConnectionCount(); | ||||
|   }; | ||||
|  | ||||
|   // Create many short-lived connections | ||||
|   const connectionPromises: Promise<void>[] = []; | ||||
|    | ||||
|   for (let i = 0; i < 20; i++) { | ||||
|     const promise = new Promise<void>((resolve, reject) => { | ||||
|       const client = new net.Socket(); | ||||
|        | ||||
|       client.connect(9001, '127.0.0.1', () => { | ||||
|         // Send some data | ||||
|         client.write('Hello World'); | ||||
|          | ||||
|         // Close after a short delay | ||||
|         setTimeout(() => { | ||||
|           client.end(); | ||||
|         }, 50); | ||||
|       }); | ||||
|        | ||||
|       client.on('close', () => resolve()); | ||||
|       client.on('error', reject); | ||||
|     }); | ||||
|      | ||||
|     connectionPromises.push(promise); | ||||
|      | ||||
|     // Stagger connection creation | ||||
|     await new Promise(resolve => setTimeout(resolve, 10)); | ||||
|   } | ||||
|  | ||||
|   // Wait for all connections to complete | ||||
|   await Promise.all(connectionPromises); | ||||
|  | ||||
|   // Give time for cleanup | ||||
|   await new Promise(resolve => setTimeout(resolve, 1000)); | ||||
|  | ||||
|   // Check that all connections are cleaned up | ||||
|   const finalConnectionCount = getConnectionCount(); | ||||
|   expect(finalConnectionCount).toEqual(0); | ||||
|  | ||||
|   // Check fragment cleanup | ||||
|   const fragmentCount = (() => { | ||||
|     const detector = (smartproxy.detection.ProtocolDetector as any).getInstance(); | ||||
|     const tlsFragments = detector.fragmentManager.getHandler('tls'); | ||||
|     const httpFragments = detector.fragmentManager.getHandler('http'); | ||||
|     return tlsFragments.size + httpFragments.size; | ||||
|   })(); | ||||
|    | ||||
|   expect(fragmentCount).toEqual(0); | ||||
|  | ||||
|   // Cleanup | ||||
|   await proxy.stop(); | ||||
|   server.close(); | ||||
| }); | ||||
|  | ||||
| tap.test('Connection Stability - Rapid Connect/Disconnect', async () => { | ||||
|   // Create a server that immediately closes connections | ||||
|   const server = net.createServer((socket) => { | ||||
|     socket.end(); | ||||
|   }); | ||||
|    | ||||
|   await new Promise<void>((resolve) => { | ||||
|     server.listen(0, '127.0.0.1', () => resolve()); | ||||
|   }); | ||||
|   const serverPort = (server.address() as net.AddressInfo).port; | ||||
|  | ||||
|   // Configure a route | ||||
|   const routes: smartproxy.IRouteConfig[] = [{ | ||||
|     match: { | ||||
|       ports: 9002, | ||||
|       domains: '*' | ||||
|     }, | ||||
|     action: { | ||||
|       type: 'forward', | ||||
|       target: { | ||||
|         host: '127.0.0.1', | ||||
|         port: serverPort | ||||
|       } | ||||
|     } | ||||
|   }]; | ||||
|    | ||||
|   // Create SmartProxy instance with routes | ||||
|   const proxy = new smartproxy.SmartProxy({  | ||||
|     keepAliveTimeoutMs: 5000, | ||||
|     routes  | ||||
|   }); | ||||
|    | ||||
|   await proxy.start(); | ||||
|  | ||||
|   let errors = 0; | ||||
|   const connections: Promise<void>[] = []; | ||||
|  | ||||
|   // Create many rapid connections | ||||
|   for (let i = 0; i < 50; i++) { | ||||
|     const promise = new Promise<void>((resolve) => { | ||||
|       const client = new net.Socket(); | ||||
|        | ||||
|       client.on('error', () => { | ||||
|         errors++; | ||||
|         resolve(); | ||||
|       }); | ||||
|        | ||||
|       client.on('close', () => { | ||||
|         resolve(); | ||||
|       }); | ||||
|        | ||||
|       client.connect(9002, '127.0.0.1'); | ||||
|     }); | ||||
|      | ||||
|     connections.push(promise); | ||||
|   } | ||||
|  | ||||
|   // Wait for all to complete | ||||
|   await Promise.all(connections); | ||||
|  | ||||
|   // Give time for cleanup | ||||
|   await new Promise(resolve => setTimeout(resolve, 500)); | ||||
|  | ||||
|   // Check that connections are cleaned up despite rapid connect/disconnect | ||||
|   const connectionManager = (proxy as any).connectionManager; | ||||
|   const finalConnectionCount = connectionManager.getActiveConnectionCount(); | ||||
|   expect(finalConnectionCount).toEqual(0); | ||||
|  | ||||
|   // Check fragment cleanup | ||||
|   const fragmentCount = (() => { | ||||
|     const detector = (smartproxy.detection.ProtocolDetector as any).getInstance(); | ||||
|     const tlsFragments = detector.fragmentManager.getHandler('tls'); | ||||
|     const httpFragments = detector.fragmentManager.getHandler('http'); | ||||
|     return tlsFragments.size + httpFragments.size; | ||||
|   })(); | ||||
|    | ||||
|   expect(fragmentCount).toEqual(0); | ||||
|  | ||||
|   // Cleanup | ||||
|   await proxy.stop(); | ||||
|   server.close(); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| @@ -138,4 +138,9 @@ tap.test('Protocol Detection - Invalid Data', async () => { | ||||
|   expect(result.protocol).toEqual('unknown'); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| tap.test('cleanup detection', async () => { | ||||
|   // Clean up the protocol detector instance | ||||
|   smartproxy.detection.ProtocolDetector.destroy(); | ||||
| }); | ||||
|  | ||||
| export default tap.start(); | ||||
| @@ -79,4 +79,4 @@ tap.test('should verify certificate manager callback is preserved on updateRoute | ||||
|   console.log('Fix verified: Certificate manager callback is preserved on updateRoutes'); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -180,4 +180,4 @@ tap.test('should handle ACME HTTP-01 challenges on port 80 with HttpProxy', asyn | ||||
|   console.log('Test passed: ACME HTTP-01 challenges on port 80 use HttpProxy'); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -242,4 +242,4 @@ tap.test('should handle ACME challenges on port 8080 with improved port binding | ||||
|   } | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -117,4 +117,4 @@ tap.test('Cleanup HttpProxy SecurityManager', async () => { | ||||
|   securityManager.clearIPTracking(); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -247,4 +247,4 @@ tap.test('keepalive support - verify keepalive connections are properly handled' | ||||
|   console.log('  - Zombie detection respects keepalive settings'); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -109,4 +109,4 @@ tap.test('Cleanup deduplicator', async () => { | ||||
|   expect(deduplicator).toBeInstanceOf(LogDeduplicator); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -149,4 +149,4 @@ tap.test('should not have memory leaks in long-running operations', async (tools | ||||
| }); | ||||
|  | ||||
| // Run with: node --expose-gc test.memory-leak-check.node.ts | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -57,4 +57,4 @@ tap.test('memory leak fixes verification', async () => { | ||||
|   console.log('\n✅ All memory leak fixes verified!'); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -128,4 +128,4 @@ tap.test('memory leak fixes - unit tests', async () => { | ||||
|   console.log('\n✅ All memory leak fixes verified!'); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -258,4 +258,4 @@ tap.test('should clean up resources', async () => { | ||||
|   }); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -192,4 +192,4 @@ tap.test('simple proxy chain test - identify connection accumulation', async () | ||||
|   expect(finalCounts.proxy2).toEqual(0); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -130,4 +130,4 @@ tap.test('PROXY protocol v1 generator', async () => { | ||||
| // Skipping integration tests for now - focus on unit tests | ||||
| // Integration tests would require more complex setup and teardown | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -198,4 +198,4 @@ tap.test('should handle routing failures without leaking connections', async () | ||||
|   console.log('\n✅ PASS: Routing failures cleaned up correctly!'); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -113,4 +113,4 @@ tap.test('should set update routes callback on certificate manager', async () => | ||||
|   await proxy.stop(); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -58,4 +58,4 @@ tap.test('route security should be correctly configured', async () => { | ||||
|   expect(isBlockedIPAllowed).toBeFalse(); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -336,4 +336,4 @@ tap.test('real code integration test - verify fix is applied', async () => { | ||||
|   console.log('Real code integration test passed - fix is correctly applied!'); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -154,4 +154,4 @@ tap.test('Cleanup SharedSecurityManager', async () => { | ||||
|   securityManager.clearIPTracking(); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -51,4 +51,4 @@ tap.test('should verify SmartAcme cert managers are accessible', async () => { | ||||
|   expect(memoryCertManager).toBeDefined(); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -141,4 +141,4 @@ tap.test('stuck connection cleanup - verify connections to hanging backends are | ||||
|   console.log('✓ Test complete: Stuck connections are properly detected and cleaned up'); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -155,4 +155,4 @@ tap.test('long-lived connection survival test', async (tools) => { | ||||
|   console.log('✅ Long-lived connection survived past 30-second timeout!'); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -303,4 +303,4 @@ tap.test('zombie connection cleanup - verify inactivity check detects and cleans | ||||
|   expect(details.inner.halfZombies.length).toEqual(0); | ||||
| }); | ||||
|  | ||||
| tap.start(); | ||||
| export default tap.start(); | ||||
| @@ -49,11 +49,15 @@ export class HttpDetector implements IProtocolDetector { | ||||
|       return null; | ||||
|     } | ||||
|      | ||||
|     // Check if we have complete headers first | ||||
|     const headersEnd = buffer.indexOf('\r\n\r\n'); | ||||
|     const isComplete = headersEnd !== -1; | ||||
|      | ||||
|     // Extract routing information | ||||
|     const routing = RoutingExtractor.extract(buffer, 'http'); | ||||
|      | ||||
|     // If we don't need full headers, we can return early | ||||
|     if (quickResult.confidence >= 95 && !options?.extractFullHeaders) { | ||||
|     // If we don't need full headers and we have complete headers, we can return early | ||||
|     if (quickResult.confidence >= 95 && !options?.extractFullHeaders && isComplete) { | ||||
|       return { | ||||
|         protocol: 'http', | ||||
|         connectionInfo: {  | ||||
| @@ -66,10 +70,6 @@ export class HttpDetector implements IProtocolDetector { | ||||
|       }; | ||||
|     } | ||||
|      | ||||
|     // Check if we have complete headers | ||||
|     const headersEnd = buffer.indexOf('\r\n\r\n'); | ||||
|     const isComplete = headersEnd !== -1; | ||||
|      | ||||
|     return { | ||||
|       protocol: 'http', | ||||
|       connectionInfo: { | ||||
|   | ||||
| @@ -18,6 +18,7 @@ export class ProtocolDetector { | ||||
|   private fragmentManager: DetectionFragmentManager; | ||||
|   private tlsDetector: TlsDetector; | ||||
|   private httpDetector: HttpDetector; | ||||
|   private connectionProtocols: Map<string, 'tls' | 'http'> = new Map(); | ||||
|    | ||||
|   constructor() { | ||||
|     this.fragmentManager = new DetectionFragmentManager(); | ||||
| @@ -122,14 +123,25 @@ export class ProtocolDetector { | ||||
|      | ||||
|     const connectionId = DetectionFragmentManager.createConnectionId(context); | ||||
|      | ||||
|     // First peek to determine protocol type | ||||
|     if (this.tlsDetector.canHandle(buffer)) { | ||||
|     // Check if we already know the protocol for this connection | ||||
|     const knownProtocol = this.connectionProtocols.get(connectionId); | ||||
|      | ||||
|     if (knownProtocol === 'http') { | ||||
|       const result = this.httpDetector.detectWithContext(buffer, context, options); | ||||
|       if (result) { | ||||
|         if (result.isComplete) { | ||||
|           this.connectionProtocols.delete(connectionId); | ||||
|         } | ||||
|         return result; | ||||
|       } | ||||
|     } else if (knownProtocol === 'tls') { | ||||
|       // Handle TLS with fragment accumulation | ||||
|       const handler = this.fragmentManager.getHandler('tls'); | ||||
|       const fragmentResult = handler.addFragment(connectionId, buffer); | ||||
|        | ||||
|       if (fragmentResult.error) { | ||||
|         handler.complete(connectionId); | ||||
|         this.connectionProtocols.delete(connectionId); | ||||
|         return { | ||||
|           protocol: 'unknown', | ||||
|           connectionInfo: { protocol: 'unknown' }, | ||||
| @@ -141,17 +153,52 @@ export class ProtocolDetector { | ||||
|       if (result) { | ||||
|         if (result.isComplete) { | ||||
|           handler.complete(connectionId); | ||||
|           this.connectionProtocols.delete(connectionId); | ||||
|         } | ||||
|         return result; | ||||
|       } | ||||
|     } | ||||
|      | ||||
|     // If we don't know the protocol yet, try to detect it | ||||
|     if (!knownProtocol) { | ||||
|       // First peek to determine protocol type | ||||
|       if (this.tlsDetector.canHandle(buffer)) { | ||||
|         this.connectionProtocols.set(connectionId, 'tls'); | ||||
|         // Handle TLS with fragment accumulation | ||||
|         const handler = this.fragmentManager.getHandler('tls'); | ||||
|         const fragmentResult = handler.addFragment(connectionId, buffer); | ||||
|          | ||||
|         if (fragmentResult.error) { | ||||
|           handler.complete(connectionId); | ||||
|           this.connectionProtocols.delete(connectionId); | ||||
|           return { | ||||
|             protocol: 'unknown', | ||||
|             connectionInfo: { protocol: 'unknown' }, | ||||
|             isComplete: true | ||||
|           }; | ||||
|         } | ||||
|          | ||||
|         const result = this.tlsDetector.detect(fragmentResult.buffer!, options); | ||||
|         if (result) { | ||||
|           if (result.isComplete) { | ||||
|             handler.complete(connectionId); | ||||
|             this.connectionProtocols.delete(connectionId); | ||||
|           } | ||||
|           return result; | ||||
|         } | ||||
|       } | ||||
|        | ||||
|       if (this.httpDetector.canHandle(buffer)) { | ||||
|         this.connectionProtocols.set(connectionId, 'http'); | ||||
|         const result = this.httpDetector.detectWithContext(buffer, context, options); | ||||
|         if (result) { | ||||
|           if (result.isComplete) { | ||||
|             this.connectionProtocols.delete(connectionId); | ||||
|           } | ||||
|           return result; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|      | ||||
|     // Can't determine protocol | ||||
|     return { | ||||
| @@ -208,6 +255,9 @@ export class ProtocolDetector { | ||||
|     // Clean up both TLS and HTTP fragments for this connection | ||||
|     instance.fragmentManager.getHandler('tls').complete(connectionId); | ||||
|     instance.fragmentManager.getHandler('http').complete(connectionId); | ||||
|      | ||||
|     // Remove from connection protocols tracking | ||||
|     instance.connectionProtocols.delete(connectionId); | ||||
|   } | ||||
|    | ||||
|   /** | ||||
|   | ||||
		Reference in New Issue
	
	Block a user