2025-07-21 19:40:01 +00:00
|
|
|
/**
|
2025-07-22 00:19:59 +00:00
|
|
|
* HTTP Protocol Detector
|
|
|
|
*
|
|
|
|
* Simplified HTTP detection using the new architecture
|
2025-07-21 19:40:01 +00:00
|
|
|
*/
|
|
|
|
|
|
|
|
import type { IProtocolDetector } from '../models/interfaces.js';
|
2025-07-22 00:19:59 +00:00
|
|
|
import type { IDetectionResult, IDetectionOptions } from '../models/detection-types.js';
|
|
|
|
import type { IProtocolDetectionResult, IConnectionContext } from '../../protocols/common/types.js';
|
|
|
|
import type { THttpMethod } from '../../protocols/http/index.js';
|
|
|
|
import { QuickProtocolDetector } from './quick-detector.js';
|
|
|
|
import { RoutingExtractor } from './routing-extractor.js';
|
|
|
|
import { DetectionFragmentManager } from '../utils/fragment-manager.js';
|
2025-07-21 19:40:01 +00:00
|
|
|
|
|
|
|
/**
|
2025-07-22 00:19:59 +00:00
|
|
|
* Simplified HTTP detector
|
2025-07-21 19:40:01 +00:00
|
|
|
*/
|
|
|
|
export class HttpDetector implements IProtocolDetector {
|
2025-07-22 00:19:59 +00:00
|
|
|
private quickDetector = new QuickProtocolDetector();
|
|
|
|
private fragmentManager: DetectionFragmentManager;
|
|
|
|
|
|
|
|
constructor(fragmentManager?: DetectionFragmentManager) {
|
|
|
|
this.fragmentManager = fragmentManager || new DetectionFragmentManager();
|
|
|
|
}
|
2025-07-21 19:40:01 +00:00
|
|
|
|
|
|
|
/**
|
2025-07-22 00:19:59 +00:00
|
|
|
* Check if buffer can be handled by this detector
|
2025-07-21 19:40:01 +00:00
|
|
|
*/
|
2025-07-22 00:19:59 +00:00
|
|
|
canHandle(buffer: Buffer): boolean {
|
|
|
|
const result = this.quickDetector.quickDetect(buffer);
|
|
|
|
return result.protocol === 'http' && result.confidence > 50;
|
|
|
|
}
|
2025-07-21 19:40:01 +00:00
|
|
|
|
|
|
|
/**
|
2025-07-22 00:19:59 +00:00
|
|
|
* Get minimum bytes needed for detection
|
2025-07-21 19:40:01 +00:00
|
|
|
*/
|
2025-07-22 00:19:59 +00:00
|
|
|
getMinimumBytes(): number {
|
|
|
|
return 4; // "GET " minimum
|
|
|
|
}
|
2025-07-21 19:40:01 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* Detect HTTP protocol from buffer
|
|
|
|
*/
|
|
|
|
detect(buffer: Buffer, options?: IDetectionOptions): IDetectionResult | null {
|
2025-07-22 00:19:59 +00:00
|
|
|
// Quick detection first
|
|
|
|
const quickResult = this.quickDetector.quickDetect(buffer);
|
2025-07-21 19:40:01 +00:00
|
|
|
|
2025-07-22 00:19:59 +00:00
|
|
|
if (quickResult.protocol !== 'http' || quickResult.confidence < 50) {
|
2025-07-21 19:40:01 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
2025-07-22 00:19:59 +00:00
|
|
|
// Extract routing information
|
|
|
|
const routing = RoutingExtractor.extract(buffer, 'http');
|
2025-07-21 19:40:01 +00:00
|
|
|
|
2025-07-22 00:19:59 +00:00
|
|
|
// If we don't need full headers, we can return early
|
|
|
|
if (quickResult.confidence >= 95 && !options?.extractFullHeaders) {
|
2025-07-21 19:40:01 +00:00
|
|
|
return {
|
|
|
|
protocol: 'http',
|
2025-07-22 00:19:59 +00:00
|
|
|
connectionInfo: {
|
|
|
|
protocol: 'http',
|
|
|
|
method: quickResult.metadata?.method as THttpMethod,
|
|
|
|
domain: routing?.domain,
|
|
|
|
path: routing?.path
|
|
|
|
},
|
2025-07-21 19:40:01 +00:00
|
|
|
isComplete: true
|
|
|
|
};
|
|
|
|
}
|
|
|
|
|
2025-07-22 00:19:59 +00:00
|
|
|
// Check if we have complete headers
|
|
|
|
const headersEnd = buffer.indexOf('\r\n\r\n');
|
|
|
|
const isComplete = headersEnd !== -1;
|
2025-07-21 19:40:01 +00:00
|
|
|
|
2025-07-22 00:19:59 +00:00
|
|
|
return {
|
|
|
|
protocol: 'http',
|
|
|
|
connectionInfo: {
|
|
|
|
protocol: 'http',
|
|
|
|
domain: routing?.domain,
|
|
|
|
path: routing?.path,
|
|
|
|
method: quickResult.metadata?.method as THttpMethod
|
|
|
|
},
|
|
|
|
isComplete,
|
|
|
|
bytesNeeded: isComplete ? undefined : buffer.length + 512 // Need more for headers
|
|
|
|
};
|
2025-07-21 19:40:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2025-07-22 00:19:59 +00:00
|
|
|
* Handle fragmented detection
|
2025-07-21 19:40:01 +00:00
|
|
|
*/
|
2025-07-22 00:19:59 +00:00
|
|
|
detectWithContext(
|
2025-07-21 19:40:01 +00:00
|
|
|
buffer: Buffer,
|
2025-07-22 00:19:59 +00:00
|
|
|
context: IConnectionContext,
|
2025-07-21 19:40:01 +00:00
|
|
|
options?: IDetectionOptions
|
|
|
|
): IDetectionResult | null {
|
2025-07-22 00:19:59 +00:00
|
|
|
const handler = this.fragmentManager.getHandler('http');
|
|
|
|
const connectionId = DetectionFragmentManager.createConnectionId(context);
|
2025-07-21 19:40:01 +00:00
|
|
|
|
2025-07-22 00:19:59 +00:00
|
|
|
// Add fragment
|
|
|
|
const result = handler.addFragment(connectionId, buffer);
|
2025-07-21 19:40:01 +00:00
|
|
|
|
2025-07-22 00:19:59 +00:00
|
|
|
if (result.error) {
|
|
|
|
handler.complete(connectionId);
|
2025-07-21 19:40:01 +00:00
|
|
|
return null;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try detection on accumulated buffer
|
2025-07-22 00:19:59 +00:00
|
|
|
const detectResult = this.detect(result.buffer!, options);
|
2025-07-21 19:40:01 +00:00
|
|
|
|
2025-07-22 00:19:59 +00:00
|
|
|
if (detectResult && detectResult.isComplete) {
|
|
|
|
handler.complete(connectionId);
|
2025-07-21 19:40:01 +00:00
|
|
|
}
|
|
|
|
|
2025-07-22 00:19:59 +00:00
|
|
|
return detectResult;
|
2025-07-21 19:40:01 +00:00
|
|
|
}
|
|
|
|
}
|