support skip tls per request

This commit is contained in:
miloschwartz
2026-08-05 17:53:28 -04:00
parent 3d7e322bf9
commit aba27a7bbf
2 changed files with 74 additions and 20 deletions
+68
View File
@@ -0,0 +1,68 @@
import http from "node:http";
import https from "node:https";
import { Readable } from "node:stream";
type UpstreamFetchInit = {
method: string;
headers: Record<string, string>;
body?: string;
skipTlsVerification?: boolean;
};
const insecureHttpsAgent = new https.Agent({
rejectUnauthorized: false,
keepAlive: true
});
export function aiGatewayUpstreamFetch(
url: string,
init: UpstreamFetchInit
): Promise<Response> {
const parsed = new URL(url);
const isHttps = parsed.protocol === "https:";
const lib = isHttps ? https : http;
const agent =
isHttps && init.skipTlsVerification ? insecureHttpsAgent : undefined;
return new Promise((resolve, reject) => {
const req = lib.request(
url,
{
method: init.method,
headers: init.headers,
agent
},
(res) => {
const headers = new Headers();
for (const [key, value] of Object.entries(res.headers)) {
if (value === undefined) {
continue;
}
if (Array.isArray(value)) {
for (const entry of value) {
headers.append(key, entry);
}
} else {
headers.set(key, value);
}
}
const body = Readable.toWeb(res) as ReadableStream<Uint8Array>;
resolve(
new Response(body, {
status: res.statusCode ?? 502,
statusText: res.statusMessage,
headers
})
);
}
);
req.on("error", reject);
if (init.body !== undefined) {
req.write(init.body);
}
req.end();
});
}
+6 -20
View File
@@ -38,6 +38,7 @@ import { localCache } from "@server/lib/cache";
import logger from "@server/logger"; import logger from "@server/logger";
import HttpCode from "@server/types/HttpCode"; import HttpCode from "@server/types/HttpCode";
import type { ModelAccessMode } from "@server/lib/aiInferenceResource"; import type { ModelAccessMode } from "@server/lib/aiInferenceResource";
import { aiGatewayUpstreamFetch } from "@server/lib/aiGatewayUpstreamFetch";
// Short-lived local caches so a burst of requests from the same IP/user // Short-lived local caches so a burst of requests from the same IP/user
// doesn't hit the database on every single request. None of this is // doesn't hit the database on every single request. None of this is
@@ -544,15 +545,6 @@ export async function handleAiGatewayProxy(
); );
applyAiProviderAuthHeaders(headers, authType, apiKey); applyAiProviderAuthHeaders(headers, authType, apiKey);
// No dedicated per-request TLS agent is wired up (no extra deps for
// this v1 gateway) - toggle the process-wide Node TLS check instead.
// Known limitation: this is not safe under concurrent requests mixing
// skipTlsVerification providers with strict ones.
const restoreTlsReject = process.env.NODE_TLS_REJECT_UNAUTHORIZED;
if (provider.skipTlsVerification) {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = "0";
}
const body = JSON.stringify(req.body); const body = JSON.stringify(req.body);
logger.debug("AI gateway upstream request", { logger.debug("AI gateway upstream request", {
@@ -560,15 +552,17 @@ export async function handleAiGatewayProxy(
url: targetUrl, url: targetUrl,
method: "POST", method: "POST",
headers, headers,
body: req.body body: req.body,
skipTlsVerification: provider.skipTlsVerification
}); });
let upstreamRes: globalThis.Response; let upstreamRes: globalThis.Response;
try { try {
upstreamRes = await fetch(targetUrl, { upstreamRes = await aiGatewayUpstreamFetch(targetUrl, {
method: "POST", method: "POST",
headers, headers,
body body,
skipTlsVerification: provider.skipTlsVerification
}); });
} catch (fetchError) { } catch (fetchError) {
logger.error({ logger.error({
@@ -581,14 +575,6 @@ export async function handleAiGatewayProxy(
: undefined : undefined
}); });
throw fetchError; throw fetchError;
} finally {
if (provider.skipTlsVerification) {
if (restoreTlsReject === undefined) {
delete process.env.NODE_TLS_REJECT_UNAUTHORIZED;
} else {
process.env.NODE_TLS_REJECT_UNAUTHORIZED = restoreTlsReject;
}
}
} }
const contentType = upstreamRes.headers.get("content-type") || ""; const contentType = upstreamRes.headers.get("content-type") || "";