Updates to Holesail
This commit is contained in:
@@ -18,6 +18,12 @@ const MAX_CERT_CACHE_SIZE = parseInt(process.env.MAX_CERT_CACHE_SIZE || '1000',
|
||||
// Store internal domains in module-level variable so it can be updated dynamically
|
||||
let internalDomainsList = ['p2ns.admin']; // Default to p2ns.admin
|
||||
|
||||
function isConnectionRefusedError(err) {
|
||||
if (!err) return false;
|
||||
const msg = err.message || '';
|
||||
return err.code === 'ECONNREFUSED' || msg.includes('ECONNREFUSED');
|
||||
}
|
||||
|
||||
// Helper function to set certificate in cache with size limit enforcement
|
||||
function setCertCache(domain, cert) {
|
||||
// If cache is at limit, remove oldest entries (simple FIFO - remove first key)
|
||||
@@ -405,29 +411,66 @@ async function setupProxyServer() {
|
||||
method: req.method,
|
||||
headers: req.headers,
|
||||
};
|
||||
const supportsAutomaticRetry = ['GET', 'HEAD', 'OPTIONS'].includes((req.method || 'GET').toUpperCase());
|
||||
const timeoutMs = parseInt(process.env.INTERNAL_PROXY_TIMEOUT_MS || '12000', 10);
|
||||
|
||||
const proxyRequest = http.request(options, (proxyRes) => {
|
||||
const headers = {};
|
||||
for (const [key, value] of Object.entries(proxyRes.headers)) {
|
||||
const lowerKey = key.toLowerCase();
|
||||
if (lowerKey !== 'strict-transport-security' && lowerKey !== 'hsts') {
|
||||
headers[key] = value;
|
||||
const sendProxyRequest = (attempt = 0) => {
|
||||
const proxyRequest = http.request(options, (proxyRes) => {
|
||||
const headers = {};
|
||||
for (const [key, value] of Object.entries(proxyRes.headers)) {
|
||||
const lowerKey = key.toLowerCase();
|
||||
if (lowerKey !== 'strict-transport-security' && lowerKey !== 'hsts') {
|
||||
headers[key] = value;
|
||||
}
|
||||
}
|
||||
|
||||
setSecurityHeaders(res);
|
||||
res.writeHead(proxyRes.statusCode, headers);
|
||||
proxyRes.pipe(res, { end: true });
|
||||
});
|
||||
|
||||
proxyRequest.setTimeout(timeoutMs, () => {
|
||||
proxyRequest.destroy(new Error('Internal proxy request timeout'));
|
||||
});
|
||||
|
||||
proxyRequest.on('error', async (err) => {
|
||||
logError('Proxy', `Error proxying request for ${domain}: ${err.message}`);
|
||||
if (isConnectionRefusedError(err)) {
|
||||
try {
|
||||
logWarn('Proxy', `Connection refused for ${domain}, restarting Holesail client ${localIP}:${state.internalPort}`);
|
||||
await restartHolesailClient(domain, hash, localIP, state.internalPort);
|
||||
} catch (restartErr) {
|
||||
logError('Proxy', `Failed to restart Holesail client after ECONNREFUSED for ${domain}: ${restartErr.message}`);
|
||||
}
|
||||
|
||||
if (supportsAutomaticRetry && attempt === 0 && !res.headersSent) {
|
||||
logInfo('Proxy', `Retrying proxy request once for ${domain} after Holesail restart`);
|
||||
sendProxyRequest(1);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!res.headersSent) {
|
||||
setSecurityHeaders(res);
|
||||
res.writeHead(503);
|
||||
res.end('Service Unavailable: reconnecting tunnel, retry in a moment');
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!res.headersSent) {
|
||||
setSecurityHeaders(res);
|
||||
res.writeHead(500);
|
||||
res.end('Internal Server Error');
|
||||
}
|
||||
});
|
||||
|
||||
if (supportsAutomaticRetry) {
|
||||
proxyRequest.end();
|
||||
} else {
|
||||
req.pipe(proxyRequest, { end: true });
|
||||
}
|
||||
|
||||
setSecurityHeaders(res);
|
||||
res.writeHead(proxyRes.statusCode, headers);
|
||||
proxyRes.pipe(res, { end: true });
|
||||
});
|
||||
};
|
||||
|
||||
proxyRequest.on('error', (err) => {
|
||||
logError('Proxy', `Error proxying request for ${domain}: ${err.message}`);
|
||||
setSecurityHeaders(res);
|
||||
res.writeHead(500);
|
||||
res.end('Internal Server Error');
|
||||
});
|
||||
|
||||
req.pipe(proxyRequest, { end: true });
|
||||
sendProxyRequest(0);
|
||||
} catch (err) {
|
||||
logError('Proxy', `Failed to handle request: ${err.message}`);
|
||||
res.writeHead(500);
|
||||
@@ -569,6 +612,13 @@ async function setupProxyServer() {
|
||||
|
||||
clientReq.on('error', (err) => {
|
||||
logError('Proxy', `WebSocket proxy error for ${domain}: ${err.message}`);
|
||||
if (isConnectionRefusedError(err)) {
|
||||
restartHolesailClient(domain, hash, localIP, state.internalPort).catch((restartErr) => {
|
||||
logError('Proxy', `Failed to restart WebSocket Holesail client after ECONNREFUSED for ${domain}: ${restartErr.message}`);
|
||||
});
|
||||
socket.end('HTTP/1.1 503 Service Unavailable\r\n\r\n');
|
||||
return;
|
||||
}
|
||||
socket.end('HTTP/1.1 500 Internal Server Error\r\n\r\n');
|
||||
});
|
||||
} catch (err) {
|
||||
|
||||
Reference in New Issue
Block a user