Skip to content

Commit 31b1968

Browse files
committed
fix: respect raw media fetch cap (#6639) (thanks @davidiach)
1 parent 2e1e7bf commit 31b1968

File tree

2 files changed

+25
-4
lines changed

2 files changed

+25
-4
lines changed

src/web/media.test.ts

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import path from "node:path";
44
import sharp from "sharp";
55
import { afterEach, describe, expect, it, vi } from "vitest";
66
import { optimizeImageToPng } from "../media/image-ops.js";
7-
import { loadWebMedia, optimizeImageToJpeg } from "./media.js";
7+
import { loadWebMedia, loadWebMediaRaw, optimizeImageToJpeg } from "./media.js";
88

99
const tmpFiles: string[] = [];
1010

@@ -106,6 +106,22 @@ describe("web media loading", () => {
106106
fetchMock.mockRestore();
107107
});
108108

109+
it("respects maxBytes for raw URL fetches", async () => {
110+
const fetchMock = vi.spyOn(globalThis, "fetch").mockResolvedValueOnce({
111+
ok: true,
112+
body: true,
113+
arrayBuffer: async () => Buffer.alloc(2048).buffer,
114+
headers: { get: () => "image/png" },
115+
status: 200,
116+
} as Response);
117+
118+
await expect(loadWebMediaRaw("https://example.com/too-big.png", 1024)).rejects.toThrow(
119+
/exceeds maxBytes 1024/i,
120+
);
121+
122+
fetchMock.mockRestore();
123+
});
124+
109125
it("uses content-disposition filename when available", async () => {
110126
const fetchMock = vi.spyOn(globalThis, "fetch").mockResolvedValueOnce({
111127
ok: true,

src/web/media.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -201,9 +201,14 @@ async function loadWebMediaInternal(
201201

202202
if (/^https?:\/\//i.test(mediaUrl)) {
203203
// Enforce a download cap during fetch to avoid unbounded memory usage.
204-
// Use the largest per-kind cap (documents) to allow oversize images to
205-
// be fetched and then compressed under a smaller maxBytes.
206-
const fetchCap = Math.max(maxBytes ?? 0, maxBytesForKind("unknown"));
204+
// For optimized images, allow fetching larger payloads before compression.
205+
const defaultFetchCap = maxBytesForKind("unknown");
206+
const fetchCap =
207+
maxBytes === undefined
208+
? defaultFetchCap
209+
: optimizeImages
210+
? Math.max(maxBytes, defaultFetchCap)
211+
: maxBytes;
207212
const fetched = await fetchRemoteMedia({ url: mediaUrl, maxBytes: fetchCap });
208213
const { buffer, contentType, fileName } = fetched;
209214
const kind = mediaKindFromMime(contentType);

0 commit comments

Comments
 (0)