2025-07-21 19:40:01 +00:00
|
|
|
/**
|
|
|
|
* Buffer manipulation utilities for protocol detection
|
|
|
|
*/
|
|
|
|
|
2025-07-21 22:37:45 +00:00
|
|
|
// Import from protocols
|
|
|
|
import { HttpParser } from '../../protocols/http/index.js';
|
|
|
|
|
2025-07-21 19:40:01 +00:00
|
|
|
/**
|
|
|
|
* BufferAccumulator class for handling fragmented data
|
|
|
|
*/
|
|
|
|
export class BufferAccumulator {
|
|
|
|
private chunks: Buffer[] = [];
|
|
|
|
private totalLength = 0;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Append data to the accumulator
|
|
|
|
*/
|
|
|
|
append(data: Buffer): void {
|
|
|
|
this.chunks.push(data);
|
|
|
|
this.totalLength += data.length;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the accumulated buffer
|
|
|
|
*/
|
|
|
|
getBuffer(): Buffer {
|
|
|
|
if (this.chunks.length === 0) {
|
|
|
|
return Buffer.alloc(0);
|
|
|
|
}
|
|
|
|
if (this.chunks.length === 1) {
|
|
|
|
return this.chunks[0];
|
|
|
|
}
|
|
|
|
return Buffer.concat(this.chunks, this.totalLength);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get current buffer length
|
|
|
|
*/
|
|
|
|
length(): number {
|
|
|
|
return this.totalLength;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Clear all accumulated data
|
|
|
|
*/
|
|
|
|
clear(): void {
|
|
|
|
this.chunks = [];
|
|
|
|
this.totalLength = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if accumulator has minimum bytes
|
|
|
|
*/
|
|
|
|
hasMinimumBytes(minBytes: number): boolean {
|
|
|
|
return this.totalLength >= minBytes;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Read a big-endian 16-bit integer from buffer
|
|
|
|
*/
|
|
|
|
export function readUInt16BE(buffer: Buffer, offset: number): number {
|
|
|
|
if (offset + 2 > buffer.length) {
|
|
|
|
throw new Error('Buffer too short for UInt16BE read');
|
|
|
|
}
|
|
|
|
return (buffer[offset] << 8) | buffer[offset + 1];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Read a big-endian 24-bit integer from buffer
|
|
|
|
*/
|
|
|
|
export function readUInt24BE(buffer: Buffer, offset: number): number {
|
|
|
|
if (offset + 3 > buffer.length) {
|
|
|
|
throw new Error('Buffer too short for UInt24BE read');
|
|
|
|
}
|
|
|
|
return (buffer[offset] << 16) | (buffer[offset + 1] << 8) | buffer[offset + 2];
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Find a byte sequence in a buffer
|
|
|
|
*/
|
|
|
|
export function findSequence(buffer: Buffer, sequence: Buffer, startOffset = 0): number {
|
|
|
|
if (sequence.length === 0) {
|
|
|
|
return startOffset;
|
|
|
|
}
|
|
|
|
|
|
|
|
const searchLength = buffer.length - sequence.length + 1;
|
|
|
|
for (let i = startOffset; i < searchLength; i++) {
|
|
|
|
let found = true;
|
|
|
|
for (let j = 0; j < sequence.length; j++) {
|
|
|
|
if (buffer[i + j] !== sequence[j]) {
|
|
|
|
found = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (found) {
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Extract a line from buffer (up to CRLF or LF)
|
|
|
|
*/
|
|
|
|
export function extractLine(buffer: Buffer, startOffset = 0): { line: string; nextOffset: number } | null {
|
2025-07-21 22:37:45 +00:00
|
|
|
// Delegate to protocol parser
|
|
|
|
return HttpParser.extractLine(buffer, startOffset);
|
2025-07-21 19:40:01 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if buffer starts with a string (case-insensitive)
|
|
|
|
*/
|
|
|
|
export function startsWithString(buffer: Buffer, str: string, offset = 0): boolean {
|
|
|
|
if (offset + str.length > buffer.length) {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
const bufferStr = buffer.slice(offset, offset + str.length).toString('utf8');
|
|
|
|
return bufferStr.toLowerCase() === str.toLowerCase();
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Safe buffer slice that doesn't throw on out-of-bounds
|
|
|
|
*/
|
|
|
|
export function safeSlice(buffer: Buffer, start: number, end?: number): Buffer {
|
|
|
|
const safeStart = Math.max(0, Math.min(start, buffer.length));
|
|
|
|
const safeEnd = end === undefined
|
|
|
|
? buffer.length
|
|
|
|
: Math.max(safeStart, Math.min(end, buffer.length));
|
|
|
|
|
|
|
|
return buffer.slice(safeStart, safeEnd);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Check if buffer contains printable ASCII
|
|
|
|
*/
|
|
|
|
export function isPrintableAscii(buffer: Buffer, length?: number): boolean {
|
2025-07-21 22:37:45 +00:00
|
|
|
// Delegate to protocol parser
|
|
|
|
return HttpParser.isPrintableAscii(buffer, length);
|
2025-07-21 19:40:01 +00:00
|
|
|
}
|