feat(smart-proxy): add socket-handler relay, fast-path port-only forwarding, metrics and bridge improvements, and various TS/Rust integration fixes
This commit is contained in:
@@ -1,13 +1,37 @@
|
||||
import { tap, expect } from '@git.zone/tstest/tapbundle';
|
||||
import * as plugins from '../ts/plugins.js';
|
||||
import * as http from 'http';
|
||||
import { SmartProxy, SocketHandlers } from '../ts/index.js';
|
||||
|
||||
/**
|
||||
* Helper to make HTTP requests using Node's http module (unlike fetch/undici,
|
||||
* http.request doesn't keep the event loop alive via a connection pool).
|
||||
*/
|
||||
function httpRequest(url: string, options: { method?: string; headers?: Record<string, string> } = {}): Promise<{ status: number; headers: http.IncomingHttpHeaders; body: string }> {
|
||||
return new Promise((resolve, reject) => {
|
||||
const parsed = new URL(url);
|
||||
const req = http.request({
|
||||
hostname: parsed.hostname,
|
||||
port: parsed.port,
|
||||
path: parsed.pathname + parsed.search,
|
||||
method: options.method || 'GET',
|
||||
headers: options.headers,
|
||||
}, (res) => {
|
||||
let body = '';
|
||||
res.on('data', (chunk: Buffer) => { body += chunk.toString(); });
|
||||
res.on('end', () => resolve({ status: res.statusCode!, headers: res.headers, body }));
|
||||
});
|
||||
req.on('error', reject);
|
||||
req.end();
|
||||
});
|
||||
}
|
||||
|
||||
tap.test('should handle HTTP requests on port 80 for ACME challenges', async (tools) => {
|
||||
tools.timeout(10000);
|
||||
|
||||
|
||||
// Track HTTP requests that are handled
|
||||
const handledRequests: any[] = [];
|
||||
|
||||
|
||||
const settings = {
|
||||
routes: [
|
||||
{
|
||||
@@ -24,7 +48,7 @@ tap.test('should handle HTTP requests on port 80 for ACME challenges', async (to
|
||||
method: req.method,
|
||||
headers: req.headers
|
||||
});
|
||||
|
||||
|
||||
// Simulate ACME challenge response
|
||||
const token = req.url?.split('/').pop() || '';
|
||||
res.header('Content-Type', 'text/plain');
|
||||
@@ -34,40 +58,31 @@ tap.test('should handle HTTP requests on port 80 for ACME challenges', async (to
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
const proxy = new SmartProxy(settings);
|
||||
|
||||
// Mock NFTables manager
|
||||
(proxy as any).nftablesManager = {
|
||||
ensureNFTablesSetup: async () => {},
|
||||
stop: async () => {}
|
||||
};
|
||||
|
||||
|
||||
await proxy.start();
|
||||
|
||||
|
||||
// Make an HTTP request to the challenge endpoint
|
||||
const response = await fetch('http://localhost:18080/.well-known/acme-challenge/test-token', {
|
||||
method: 'GET'
|
||||
});
|
||||
|
||||
const response = await httpRequest('http://localhost:18080/.well-known/acme-challenge/test-token');
|
||||
|
||||
// Verify response
|
||||
expect(response.status).toEqual(200);
|
||||
const body = await response.text();
|
||||
expect(body).toEqual('challenge-response-for-test-token');
|
||||
|
||||
expect(response.body).toEqual('challenge-response-for-test-token');
|
||||
|
||||
// Verify request was handled
|
||||
expect(handledRequests.length).toEqual(1);
|
||||
expect(handledRequests[0].path).toEqual('/.well-known/acme-challenge/test-token');
|
||||
expect(handledRequests[0].method).toEqual('GET');
|
||||
|
||||
|
||||
await proxy.stop();
|
||||
});
|
||||
|
||||
tap.test('should parse HTTP headers correctly', async (tools) => {
|
||||
tools.timeout(10000);
|
||||
|
||||
|
||||
const capturedContext: any = {};
|
||||
|
||||
|
||||
const settings = {
|
||||
routes: [
|
||||
{
|
||||
@@ -92,36 +107,30 @@ tap.test('should parse HTTP headers correctly', async (tools) => {
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
|
||||
const proxy = new SmartProxy(settings);
|
||||
|
||||
// Mock NFTables manager
|
||||
(proxy as any).nftablesManager = {
|
||||
ensureNFTablesSetup: async () => {},
|
||||
stop: async () => {}
|
||||
};
|
||||
|
||||
|
||||
await proxy.start();
|
||||
|
||||
|
||||
// Make request with custom headers
|
||||
const response = await fetch('http://localhost:18081/test', {
|
||||
const response = await httpRequest('http://localhost:18081/test', {
|
||||
method: 'POST',
|
||||
headers: {
|
||||
'X-Custom-Header': 'test-value',
|
||||
'User-Agent': 'test-agent'
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
expect(response.status).toEqual(200);
|
||||
const body = await response.json();
|
||||
|
||||
const body = JSON.parse(response.body);
|
||||
|
||||
// Verify headers were parsed correctly
|
||||
expect(capturedContext.headers['x-custom-header']).toEqual('test-value');
|
||||
expect(capturedContext.headers['user-agent']).toEqual('test-agent');
|
||||
expect(capturedContext.method).toEqual('POST');
|
||||
expect(capturedContext.path).toEqual('/test');
|
||||
|
||||
|
||||
await proxy.stop();
|
||||
});
|
||||
|
||||
export default tap.start();
|
||||
export default tap.start();
|
||||
|
||||
Reference in New Issue
Block a user