mirror of
https://github.com/openclaw/openclaw.git
synced 2026-08-28 05:16:23 -06:00
perf(copilot): avoid duplicating BYOK request bodies (#131145)
This commit is contained in:
committed by
GitHub
parent
9be3cefabd
commit
3f3ccd2b40
@@ -15,6 +15,7 @@ vi.mock("openclaw/plugin-sdk/ssrf-runtime", async (importOriginal) => ({
|
||||
describe("createCopilotByokProxy", () => {
|
||||
afterEach(() => {
|
||||
ssrfRuntimeMock.fetchWithSsrFGuard.mockReset();
|
||||
vi.restoreAllMocks();
|
||||
});
|
||||
|
||||
it("presents a loopback SDK endpoint and forwards through guarded fetch", async () => {
|
||||
@@ -82,6 +83,77 @@ describe("createCopilotByokProxy", () => {
|
||||
}
|
||||
});
|
||||
|
||||
it.each([307, 308])("preserves binary request bytes across a %i redirect", async (status) => {
|
||||
const { fetchWithSsrFGuard } = await vi.importActual<
|
||||
typeof import("openclaw/plugin-sdk/ssrf-runtime")
|
||||
>("openclaw/plugin-sdk/ssrf-runtime");
|
||||
ssrfRuntimeMock.fetchWithSsrFGuard.mockImplementation(fetchWithSsrFGuard);
|
||||
const clientFetch = globalThis.fetch;
|
||||
const received: Buffer[] = [];
|
||||
const upstreamFetch = vi.spyOn(globalThis, "fetch").mockImplementation(async (url, init) => {
|
||||
const request = new Request(url, init);
|
||||
expect(request.method).toBe("POST");
|
||||
received.push(Buffer.from(await request.arrayBuffer()));
|
||||
return received.length === 1
|
||||
? new Response(null, { status, headers: { location: "/v1/replayed" } })
|
||||
: new Response("ok");
|
||||
});
|
||||
const proxy = await createCopilotByokProxy(
|
||||
resolveCopilotProvider({
|
||||
model: {
|
||||
provider: "custom-proxy",
|
||||
api: "openai-responses",
|
||||
id: "proxy-model",
|
||||
baseUrl: "https://proxy.example/v1",
|
||||
},
|
||||
}),
|
||||
);
|
||||
// Keep invalid UTF-8 and a nonzero offset: forwarding the backing pool would leak other bytes.
|
||||
const body = Buffer.from([42, 0, 255, 128, 192, 10, 42]).subarray(1, -1);
|
||||
try {
|
||||
const response = await clientFetch(`${proxy?.provider.provider?.baseUrl}/responses`, {
|
||||
method: "POST",
|
||||
body,
|
||||
});
|
||||
expect(response.status).toBe(200);
|
||||
expect(await response.text()).toBe("ok");
|
||||
expect(upstreamFetch).toHaveBeenCalledTimes(2);
|
||||
expect(received).toEqual([body, body]);
|
||||
} finally {
|
||||
await proxy?.close();
|
||||
}
|
||||
});
|
||||
|
||||
it.each(["GET", "HEAD", "POST"])(
|
||||
"forwards an empty %s request without a body",
|
||||
async (method) => {
|
||||
ssrfRuntimeMock.fetchWithSsrFGuard.mockResolvedValue({
|
||||
response: new Response(null, { status: 204 }),
|
||||
release: vi.fn(async () => undefined),
|
||||
});
|
||||
const proxy = await createCopilotByokProxy(
|
||||
resolveCopilotProvider({
|
||||
model: {
|
||||
provider: "custom-proxy",
|
||||
api: "openai-responses",
|
||||
id: "proxy-model",
|
||||
baseUrl: "https://proxy.example/v1",
|
||||
},
|
||||
}),
|
||||
);
|
||||
try {
|
||||
const response = await fetch(`${proxy?.provider.provider?.baseUrl}/responses`, { method });
|
||||
expect(response.status).toBe(204);
|
||||
expect(ssrfRuntimeMock.fetchWithSsrFGuard).toHaveBeenCalledWith(
|
||||
expect.objectContaining({ init: expect.objectContaining({ method }) }),
|
||||
);
|
||||
expect(ssrfRuntimeMock.fetchWithSsrFGuard.mock.calls[0]?.[0].init.body).toBeUndefined();
|
||||
} finally {
|
||||
await proxy?.close();
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
it("injects resolved bearer auth when the SDK request omits Authorization", async () => {
|
||||
ssrfRuntimeMock.fetchWithSsrFGuard.mockResolvedValue({
|
||||
response: new Response("ok", { status: 200 }),
|
||||
|
||||
@@ -126,7 +126,7 @@ async function handleProxyRequest(
|
||||
: undefined,
|
||||
}),
|
||||
signal: upstreamAbort.signal,
|
||||
...(body ? { body: toFetchBody(body) } : {}),
|
||||
...(body ? { body } : {}),
|
||||
},
|
||||
auditContext: "copilot-byok-provider",
|
||||
requireHttps: true,
|
||||
@@ -210,7 +210,7 @@ function isNonceProtectedProxyRequest(req: IncomingMessage, proxyPathPrefix: str
|
||||
);
|
||||
}
|
||||
|
||||
async function readBody(req: IncomingMessage): Promise<Buffer | undefined> {
|
||||
async function readBody(req: IncomingMessage): Promise<Buffer<ArrayBuffer> | undefined> {
|
||||
const chunks: Buffer[] = [];
|
||||
for await (const chunk of req) {
|
||||
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
||||
@@ -218,12 +218,6 @@ async function readBody(req: IncomingMessage): Promise<Buffer | undefined> {
|
||||
return chunks.length > 0 ? Buffer.concat(chunks) : undefined;
|
||||
}
|
||||
|
||||
function toFetchBody(body: Buffer): Uint8Array<ArrayBuffer> {
|
||||
const copy = new Uint8Array(body.byteLength);
|
||||
copy.set(body);
|
||||
return copy;
|
||||
}
|
||||
|
||||
function normalizeProxyRequestHeaders(headers: IncomingMessage["headers"]): Record<string, string> {
|
||||
const out: Record<string, string> = {};
|
||||
for (const [key, value] of Object.entries(headers)) {
|
||||
|
||||
Reference in New Issue
Block a user