feat(proxy-protocol): add PROXY protocol v2 support to the Rust passthrough listener and streamline TypeScript proxy protocol exports
This commit is contained in:
@@ -15,4 +15,3 @@ export * from './lifecycle-component.js';
|
||||
export * from './binary-heap.js';
|
||||
export * from './enhanced-connection-pool.js';
|
||||
export * from './socket-utils.js';
|
||||
export * from './proxy-protocol.js';
|
||||
|
||||
@@ -1,129 +0,0 @@
|
||||
import * as plugins from '../../plugins.js';
|
||||
import { logger } from './logger.js';
|
||||
import { ProxyProtocolParser as ProtocolParser, type IProxyInfo, type IProxyParseResult } from '../../protocols/proxy/index.js';
|
||||
|
||||
// Re-export types from protocols for backward compatibility
|
||||
export type { IProxyInfo, IProxyParseResult } from '../../protocols/proxy/index.js';
|
||||
|
||||
/**
|
||||
* Parser for PROXY protocol v1 (text format)
|
||||
* Spec: https://www.haproxy.org/download/1.8/doc/proxy-protocol.txt
|
||||
*
|
||||
* This class now delegates to the protocol parser but adds
|
||||
* smartproxy-specific features like socket reading and logging
|
||||
*/
|
||||
export class ProxyProtocolParser {
|
||||
static readonly PROXY_V1_SIGNATURE = ProtocolParser.PROXY_V1_SIGNATURE;
|
||||
static readonly MAX_HEADER_LENGTH = ProtocolParser.MAX_HEADER_LENGTH;
|
||||
static readonly HEADER_TERMINATOR = ProtocolParser.HEADER_TERMINATOR;
|
||||
|
||||
/**
|
||||
* Parse PROXY protocol v1 header from buffer
|
||||
* Returns proxy info and remaining data after header
|
||||
*/
|
||||
static parse(data: Buffer): IProxyParseResult {
|
||||
// Delegate to protocol parser
|
||||
return ProtocolParser.parse(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate PROXY protocol v1 header
|
||||
*/
|
||||
static generate(info: IProxyInfo): Buffer {
|
||||
// Delegate to protocol parser
|
||||
return ProtocolParser.generate(info);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate IP address format
|
||||
*/
|
||||
private static isValidIP(ip: string, protocol: 'TCP4' | 'TCP6' | 'UNKNOWN'): boolean {
|
||||
return ProtocolParser.isValidIP(ip, protocol);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to read a complete PROXY protocol header from a socket
|
||||
* Returns null if no PROXY protocol detected or incomplete
|
||||
*/
|
||||
static async readFromSocket(socket: plugins.net.Socket, timeout: number = 5000): Promise<IProxyParseResult | null> {
|
||||
return new Promise((resolve) => {
|
||||
let buffer = Buffer.alloc(0);
|
||||
let resolved = false;
|
||||
|
||||
const cleanup = () => {
|
||||
socket.removeListener('data', onData);
|
||||
socket.removeListener('error', onError);
|
||||
clearTimeout(timer);
|
||||
};
|
||||
|
||||
const timer = setTimeout(() => {
|
||||
if (!resolved) {
|
||||
resolved = true;
|
||||
cleanup();
|
||||
resolve({
|
||||
proxyInfo: null,
|
||||
remainingData: buffer
|
||||
});
|
||||
}
|
||||
}, timeout);
|
||||
|
||||
const onData = (chunk: Buffer) => {
|
||||
buffer = Buffer.concat([buffer, chunk]);
|
||||
|
||||
// Check if we have enough data
|
||||
if (!buffer.toString('ascii', 0, Math.min(6, buffer.length)).startsWith(this.PROXY_V1_SIGNATURE)) {
|
||||
// Not PROXY protocol
|
||||
resolved = true;
|
||||
cleanup();
|
||||
resolve({
|
||||
proxyInfo: null,
|
||||
remainingData: buffer
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// Try to parse
|
||||
try {
|
||||
const result = this.parse(buffer);
|
||||
if (result.proxyInfo) {
|
||||
// Successfully parsed
|
||||
resolved = true;
|
||||
cleanup();
|
||||
resolve(result);
|
||||
} else if (buffer.length > this.MAX_HEADER_LENGTH) {
|
||||
// Header too long
|
||||
resolved = true;
|
||||
cleanup();
|
||||
resolve({
|
||||
proxyInfo: null,
|
||||
remainingData: buffer
|
||||
});
|
||||
}
|
||||
// Otherwise continue reading
|
||||
} catch (error) {
|
||||
// Parse error
|
||||
logger.log('error', `PROXY protocol parse error: ${error.message}`);
|
||||
resolved = true;
|
||||
cleanup();
|
||||
resolve({
|
||||
proxyInfo: null,
|
||||
remainingData: buffer
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const onError = (error: Error) => {
|
||||
logger.log('error', `Socket error while reading PROXY protocol: ${error.message}`);
|
||||
resolved = true;
|
||||
cleanup();
|
||||
resolve({
|
||||
proxyInfo: null,
|
||||
remainingData: buffer
|
||||
});
|
||||
};
|
||||
|
||||
socket.on('data', onData);
|
||||
socket.on('error', onError);
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user