96 lines
3.0 KiB
Bash
96 lines
3.0 KiB
Bash
HWLAB_PROXY_PROBE_PHASE=__HWLAB_PROXY_PHASE_SHELL__ HWLAB_PROXY_PROBE_URL=__HWLAB_PROXY_TARGET_SHELL__ node <<'NODE' || echo '{"event":"dependency-proxy-probe-nonblocking","phase":"__HWLAB_PROXY_PHASE__","ok":false,"reason":"probe-failed-but-continuing"}'
|
|
const net = require("node:net");
|
|
|
|
const phase = process.env.HWLAB_PROXY_PROBE_PHASE || "unknown";
|
|
const target = new URL(process.env.HWLAB_PROXY_PROBE_URL || "http://deb.debian.org/debian/dists/bookworm/InRelease");
|
|
const proxyRaw = process.env.HTTP_PROXY || process.env.http_proxy || "";
|
|
|
|
function redactProxy(value) {
|
|
if (!value) return "";
|
|
try {
|
|
const parsed = new URL(value);
|
|
if (parsed.username || parsed.password) {
|
|
parsed.username = "***";
|
|
parsed.password = "";
|
|
}
|
|
return parsed.toString();
|
|
} catch {
|
|
return "<invalid-proxy-url>";
|
|
}
|
|
}
|
|
|
|
function emit(payload, exitCode = 0) {
|
|
console.log(JSON.stringify({
|
|
event: "dependency-proxy-probe",
|
|
phase,
|
|
target: target.href,
|
|
proxy: redactProxy(proxyRaw),
|
|
...payload
|
|
}));
|
|
if (exitCode) process.exit(exitCode);
|
|
}
|
|
|
|
if (!proxyRaw) emit({ ok: false, reason: "proxy-env-missing" }, 21);
|
|
|
|
let proxy;
|
|
try {
|
|
proxy = new URL(proxyRaw);
|
|
} catch (error) {
|
|
emit({ ok: false, reason: "proxy-url-invalid", error: error.message }, 22);
|
|
}
|
|
|
|
if (proxy.protocol !== "http:" && proxy.protocol !== "https:") {
|
|
emit({ ok: false, reason: "http-proxy-required", protocol: proxy.protocol }, 23);
|
|
}
|
|
|
|
const startedAt = Date.now();
|
|
const socket = net.createConnection({ host: proxy.hostname, port: Number(proxy.port || (proxy.protocol === "https:" ? 443 : 80)) });
|
|
let bytes = 0;
|
|
let firstByteMs = null;
|
|
let responseHead = "";
|
|
let finished = false;
|
|
|
|
const timeout = setTimeout(() => {
|
|
if (finished) return;
|
|
finished = true;
|
|
socket.destroy();
|
|
emit({ ok: false, reason: "timeout", timeoutMs: 15000 }, 24);
|
|
}, 15000);
|
|
|
|
socket.on("connect", () => {
|
|
socket.write("GET " + target.href + " HTTP/1.1\r\nHost: " + target.host + "\r\nUser-Agent: hwlab-node-proxy-probe\r\nConnection: close\r\n\r\n");
|
|
});
|
|
|
|
socket.on("data", (chunk) => {
|
|
if (firstByteMs === null) firstByteMs = Date.now() - startedAt;
|
|
bytes += chunk.length;
|
|
if (responseHead.length < 240) responseHead += chunk.toString("utf8", 0, Math.min(chunk.length, 240 - responseHead.length));
|
|
});
|
|
|
|
socket.on("end", () => {
|
|
if (finished) return;
|
|
finished = true;
|
|
clearTimeout(timeout);
|
|
const totalMs = Date.now() - startedAt;
|
|
const statusLine = responseHead.split("\r\n", 1)[0] || "";
|
|
const statusCode = Number(statusLine.split(" ")[1] || 0);
|
|
const ok = statusLine.startsWith("HTTP/") && statusCode >= 200 && statusCode < 400;
|
|
emit({
|
|
ok,
|
|
reason: ok ? null : "bad-http-status",
|
|
statusLine,
|
|
statusCode,
|
|
firstByteMs,
|
|
totalMs,
|
|
bytes,
|
|
speedBytesPerSecond: totalMs > 0 ? Math.round(bytes * 1000 / totalMs) : 0
|
|
}, ok ? 0 : 25);
|
|
});
|
|
|
|
socket.on("error", (error) => {
|
|
if (finished) return;
|
|
finished = true;
|
|
clearTimeout(timeout);
|
|
emit({ ok: false, reason: "proxy-connect-failed", error: error.message, totalMs: Date.now() - startedAt }, 26);
|
|
});
|
|
NODE |