Skip to content

OG route buffers full 2 MB response though only <head> is needed #1610

Description

@Sravanjangam

Problem

apps/web/app/api/og/route.ts:readBoundedText buffers the full response body (up to MAX_HTML_BYTES = 2_000_000) before returning, even though OG meta tags only live in <head>. The function's own comment states the intent — "OG parsing only needs <head>, so cap the read rather than buffering the whole body" — but the implementation does the opposite.

Impact

Per /api/og request:

  • Memory: ~6-8 MB peak (2 MB chunks: Uint8Array[] + 2 MB merged buffer + 2-4 MB UTF-16 string after TextDecoder).
  • CPU: 6 regex matches over the full 2 MB string, scanning ~12 MB of bytes to extract meta tags that exist in the first 20-40 KB.
  • Network: full body downloaded end-to-end even though we throw away everything after </head>.

At link-preview scale (e.g. 20 URLs unfurled in a single chat message), peak RSS in the worker approaches 150-200 MB, and the first byte of any preview is gated on the slowest of N full-body fetches serialised through one isolate.

Suggested fix

Replace the full-body read with a streaming reader that:

  1. Reads chunks into a small growing buffer (cap ~64 KB).
  2. Scans for </head> after each chunk (case-insensitive).
  3. Cancels the reader and returns the partial string as soon as the tag is found.
  4. Returns null (→ 413) if the cap is hit before </head> is seen.

The existing 6 regex patterns in processHtml stay unchanged — they just run over a 30-40 KB string instead of 2 MB, which is the actual win.

Scope

Single file change. No new dependencies, no API surface change, no client-side impact. The 2 MB hard cap becomes a 64 KB <head>-only cap, but OG tags live entirely within that bound in practice (current upstream sites rarely exceed 20 KB for the head).

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions