


























@@ -60,6 +60,33 @@ function responseFromReaderText(text: string, releaseLock: () => void): Response
6060} as Response;
6161}
626263+function streamingProxyErrorResponse(params: { chunkCount: number; chunkSize: number }): {
64+response: Response;
65+getReadCount: () => number;
66+} {
67+let reads = 0;
68+const encoder = new TextEncoder();
69+const stream = new ReadableStream<Uint8Array>({
70+pull(controller) {
71+if (reads >= params.chunkCount) {
72+controller.close();
73+return;
74+}
75+reads += 1;
76+controller.enqueue(encoder.encode("a".repeat(params.chunkSize)));
77+},
78+});
79+80+return {
81+response: new Response(stream, {
82+status: 502,
83+statusText: "Bad Gateway",
84+headers: { "Content-Type": "application/json" },
85+}),
86+getReadCount: () => reads,
87+};
88+}
89+6390describe("streamProxy", () => {
6491afterEach(() => {
6592vi.unstubAllGlobals();
@@ -168,6 +195,30 @@ describe("streamProxy", () => {
168195expect(releaseLock).toHaveBeenCalledTimes(1);
169196});
170197198+it("stops reading oversized proxy error JSON responses", async () => {
199+const streamed = streamingProxyErrorResponse({ chunkCount: 20, chunkSize: 1024 * 1024 });
200+vi.stubGlobal(
201+"fetch",
202+vi.fn(async () => streamed.response),
203+);
204+205+const stream = streamProxy(model, context, {
206+authToken: "token",
207+proxyUrl: "https://proxy.example",
208+});
209+const events = [];
210+for await (const event of stream) {
211+events.push(event);
212+}
213+214+expect(events.at(-1)?.type).toBe("error");
215+await expect(stream.result()).resolves.toMatchObject({
216+stopReason: "error",
217+errorMessage: "Proxy error: 502 Bad Gateway",
218+});
219+expect(streamed.getReadCount()).toBeLessThan(20);
220+});
221+171222it("returns an error result when EOF arrives without a terminal event", async () => {
172223vi.stubGlobal(
173224"fetch",
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。