





















@@ -568,4 +568,137 @@ describe("verifyGoogleChatRequest", () => {
568568});
569569expect(release).toHaveBeenCalledOnce();
570570});
571+572+describe("bounded JSON read (readProviderJsonResponse delegation)", () => {
573+afterEach(() => {
574+authTesting.resetGoogleChatAuthForTests();
575+mocks.fetchWithSsrFGuard.mockClear();
576+vi.unstubAllGlobals();
577+});
578+579+it("cancels oversized cert fetch JSON body via the 16 MiB provider cap", async () => {
580+const ONE_MIB = 1024 * 1024;
581+const TOTAL_CHUNKS = 32;
582+const chunk = new Uint8Array(ONE_MIB);
583+584+let bytesPulled = 0;
585+let canceled = false;
586+const oversizedJson = new Response(
587+new ReadableStream<Uint8Array>({
588+pull(controller) {
589+if (bytesPulled >= TOTAL_CHUNKS * ONE_MIB) {
590+controller.close();
591+return;
592+}
593+bytesPulled += chunk.length;
594+controller.enqueue(chunk);
595+},
596+cancel() {
597+canceled = true;
598+},
599+}),
600+{ status: 200, headers: { "Content-Type": "application/json" } },
601+);
602+const release = vi.fn(async () => {});
603+mocks.fetchWithSsrFGuard.mockResolvedValueOnce({
604+response: oversizedJson,
605+ release,
606+});
607+608+const result = await verifyGoogleChatRequest({
609+bearer: "token",
610+audienceType: "project-number",
611+audience: "123456789",
612+});
613+614+expect(result.ok).toBe(false);
615+expect(result.reason).toMatch(/JSON response exceeds 16777216 bytes/);
616+expect(canceled).toBe(true);
617+expect(bytesPulled).toBeLessThan(TOTAL_CHUNKS * ONE_MIB);
618+expect(release).toHaveBeenCalledOnce();
619+});
620+621+it("rejects oversized sendMessage JSON body via the 16 MiB provider cap", async () => {
622+const ONE_MIB = 1024 * 1024;
623+const TOTAL_CHUNKS = 32;
624+const chunk = new Uint8Array(ONE_MIB);
625+626+let bytesPulled = 0;
627+let canceled = false;
628+const oversizedJson = new Response(
629+new ReadableStream<Uint8Array>({
630+pull(controller) {
631+if (bytesPulled >= TOTAL_CHUNKS * ONE_MIB) {
632+controller.close();
633+return;
634+}
635+bytesPulled += chunk.length;
636+controller.enqueue(chunk);
637+},
638+cancel() {
639+canceled = true;
640+},
641+}),
642+{ status: 200, headers: { "Content-Type": "application/json" } },
643+);
644+const release = vi.fn(async () => {});
645+mocks.fetchWithSsrFGuard.mockResolvedValueOnce({
646+response: oversizedJson,
647+ release,
648+});
649+650+await expect(
651+sendGoogleChatMessage({
652+ account,
653+space: "spaces/AAA",
654+text: "hello",
655+}),
656+).rejects.toThrow(/Google Chat API request failed: JSON response exceeds 16777216 bytes/);
657+658+expect(canceled).toBe(true);
659+expect(bytesPulled).toBeLessThan(TOTAL_CHUNKS * ONE_MIB);
660+});
661+662+it("caps non-OK sendMessage error bodies before formatting the API error", async () => {
663+const ONE_MIB = 1024 * 1024;
664+const TOTAL_CHUNKS = 32;
665+const chunk = new TextEncoder().encode("x".repeat(ONE_MIB));
666+667+let bytesPulled = 0;
668+let canceled = false;
669+const oversizedError = new Response(
670+new ReadableStream<Uint8Array>({
671+pull(controller) {
672+if (bytesPulled >= TOTAL_CHUNKS * ONE_MIB) {
673+controller.close();
674+return;
675+}
676+bytesPulled += chunk.length;
677+controller.enqueue(chunk);
678+},
679+cancel() {
680+canceled = true;
681+},
682+}),
683+{ status: 500, statusText: "Internal Server Error" },
684+);
685+const release = vi.fn(async () => {});
686+mocks.fetchWithSsrFGuard.mockResolvedValueOnce({
687+response: oversizedError,
688+ release,
689+});
690+691+await expect(
692+sendGoogleChatMessage({
693+ account,
694+space: "spaces/AAA",
695+text: "hello",
696+}),
697+).rejects.toThrow(/^Google Chat API 500: x+/);
698+699+expect(canceled).toBe(true);
700+expect(bytesPulled).toBeLessThan(TOTAL_CHUNKS * ONE_MIB);
701+expect(release).toHaveBeenCalledOnce();
702+});
703+});
571704});
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。