Skip to content

[miniflare] isCompressedByCloudflareFL does not normalise Content-Type case or whitespace #14828

Description

@chinesepowered

What versions & operating system are you using?

Miniflare 4.20260722.0, Node v24.11.0, macOS 15 (Darwin 24.6.0). Also present on main @ 3a141ed11.

Please provide a link to a minimal reproduction

No repo needed — the reproduction is a direct call against the helper, included below.

Describe the Bug

isCompressedByCloudflareFL() decides whether Miniflare simulates Cloudflare's edge compression for a response. It compares the media type against an all-lowercase Set, but never normalises the incoming header:

// packages/miniflare/src/shared/mime-types.ts
export function isCompressedByCloudflareFL(
    contentTypeHeader: string | undefined | null
) {
    if (!contentTypeHeader) return true;

    const [contentType] = contentTypeHeader.split(";");

    return compressedByCloudflareFL.has(contentType);  // <-- not trimmed, not lowercased
}

Media types are case-insensitive (RFC 9110 §8.3.1), and optional whitespace is allowed before the ; that starts the parameter section. Both are mishandled:

isCompressedByCloudflareFL("text/html")               // true   (correct)
isCompressedByCloudflareFL("Text/HTML")               // false  (should be true)
isCompressedByCloudflareFL("text/html ; charset=utf-8") // false  (should be true)

Expected: the media type is trimmed and lowercased before lookup, so casing and optional whitespace do not change the result.

Why it matters: the practical effect is that a Worker returning Content-Type: Text/HTML (or with a space before the ;) gets different compression behaviour under wrangler dev than it does when deployed, since Cloudflare's edge treats the media type case-insensitively. That is a local-vs-production divergence, which is the specific thing Miniflare exists to avoid. The helper has two live call sites in the Miniflare response path.

Please provide any relevant error logs

No error is produced — the failure is silent and behavioural (compression is skipped when it should be applied).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    Projects

    Status
    Backlog

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions