Files
pikasTech-unidesk/scripts/native/agentrun/git-mirror-proxy-connect.cjs
T

56 lines
2.3 KiB
JavaScript

#!/usr/bin/env node
const net = require("node:net");
const [proxyHost, proxyPortRaw, targetHost, targetPortRaw] = process.argv.slice(2);
const proxyPort = Number.parseInt(proxyPortRaw || "", 10);
const targetPort = Number.parseInt(targetPortRaw || "", 10);
if (!proxyHost || !Number.isInteger(proxyPort) || !targetHost || !Number.isInteger(targetPort)) {
console.error("agentrun managed repository proxy-connect: invalid arguments");
process.exit(64);
}
let settled = false;
let tunnelEstablished = false;
function finish(code, message) {
if (settled) return;
settled = true;
if (message) console.error(`agentrun managed repository proxy-connect: ${message}`);
process.exit(code);
}
const socket = net.createConnection({ host: proxyHost, port: proxyPort });
let buffer = Buffer.alloc(0);
socket.setTimeout(15000, () => {
socket.destroy();
finish(65, "proxy connection timeout");
});
socket.on("connect", () => socket.write(`CONNECT ${targetHost}:${targetPort} HTTP/1.1\r\nHost: ${targetHost}:${targetPort}\r\nProxy-Connection: Keep-Alive\r\n\r\n`));
socket.on("error", (error) => finish(tunnelEstablished ? 69 : 66, error?.message || String(error)));
socket.on("close", () => finish(tunnelEstablished ? 0 : 68, tunnelEstablished ? null : "proxy closed before CONNECT completed"));
socket.on("data", function onData(chunk) {
buffer = Buffer.concat([buffer, chunk]);
const headerEnd = buffer.indexOf("\r\n\r\n");
if (headerEnd === -1 && buffer.length < 8192) return;
if (headerEnd === -1) {
socket.destroy();
finish(68, "proxy response header exceeded 8192 bytes");
return;
}
const statusLine = buffer.subarray(0, headerEnd).toString("latin1").split("\r\n", 1)[0] || "";
const statusCode = Number.parseInt(statusLine.split(" ")[1] || "", 10);
if (!statusLine.startsWith("HTTP/1.") || !Number.isInteger(statusCode) || statusCode < 200 || statusCode > 299) {
socket.destroy();
finish(67, `proxy CONNECT failed: ${statusLine.replace(/[^\x20-\x7e]/g, "?").slice(0, 160)}`);
return;
}
socket.removeListener("data", onData);
socket.setTimeout(0);
tunnelEstablished = true;
const rest = buffer.subarray(headerEnd + 4);
if (rest.length > 0) process.stdout.write(rest);
process.stdin.on("error", () => {});
process.stdout.on("error", () => {});
process.stdin.pipe(socket);
socket.pipe(process.stdout);
});