Skip to content

Reject MIME type parameters differing only in case#37008

Open
junhyeong9812 wants to merge 1 commit into
spring-projects:mainfrom
junhyeong9812:fix/mimetype-duplicate-parameter-case
Open

Reject MIME type parameters differing only in case#37008
junhyeong9812 wants to merge 1 commit into
spring-projects:mainfrom
junhyeong9812:fix/mimetype-duplicate-parameter-case

Conversation

@junhyeong9812

Copy link
Copy Markdown
Contributor

Overview

MimeTypeUtils rejects duplicate MIME type parameters (gh-36841), but the check is case-sensitive while MIME parameter names are case-insensitive. As a result, duplicates that differ only in case (for example charset and CHARSET) slip through and are silently collapsed to the last value. This aligns the duplicate check with the case-insensitive nature of parameter names.

Problem

When parsing parameters, MimeTypeUtils.parseMimeTypeInternal(...) accumulates them in a LinkedHashMap, and gh-36841 added a duplicate check by throwing when Map#put returns a previous value:

if (parameters.put(attribute, value) != null) {
    throw new InvalidMimeTypeException(mimeType, "duplicate parameter '" + parameter + "'");
}

Because a LinkedHashMap treats charset and CHARSET as distinct keys, a case-variant duplicate never triggers the check:

Input Before
text/plain;dupe="1";dupe="2" rejected (InvalidMimeTypeException)
text/plain;dupe="1";DUPE="2" accepted, silently keeps "2"

This is inconsistent: MIME parameter names are case-insensitive (RFC 2045), and MimeType itself stores parameters in a LinkedCaseInsensitiveMap so that getParameter("CHARSET") and getParameter("charset") resolve to the same value. RFC 6838 section 4.3 (cited by gh-36841) treats duplicate parameters as an error, so a case-only variant is logically the same duplicate.

Fix

Accumulate parameters in a LinkedCaseInsensitiveMap so that a case-variant duplicate maps to the same key, causing put to return the previous value and the existing check to reject it:

// Parameter names are case-insensitive, so use a case-insensitive
// map in order to reject duplicates that differ only in case.
parameters = new LinkedCaseInsensitiveMap<>(4, Locale.ROOT);

Locale.ROOT matches how MimeType builds its own parameter map, keeping case-insensitive comparison locale-independent. The final MimeType is unaffected: its constructor re-copies the parameters into its own LinkedCaseInsensitiveMap, and for non-duplicate input the accumulating map behaves the same as before (same keys, values, and iteration order). Only the duplicate-detection sensitivity changes.

Note on impact

This is a parsing behavior change: Content-Type/Accept-style strings that repeat a parameter with different casing now throw InvalidMimeTypeException instead of parsing successfully. This matches the intent of gh-36841 and the case-insensitive contract of parameter names; valid MIME types are unaffected.

MIME type parameter names are case-insensitive, but the duplicate
parameter check added in spring-projectsgh-36841 accumulated parameters in a
case-sensitive map. As a result, duplicates differing only in case
(such as "charset" and "CHARSET") were not rejected and were
silently collapsed to the last value.

Accumulate parameters in a LinkedCaseInsensitiveMap so that such
duplicates map to the same key and are rejected consistently, matching
the case-insensitive map already used by MimeType for parameter
storage.

Signed-off-by: junhyeong9812 <pickjog@gmail.com>
@spring-projects-issues spring-projects-issues added the status: waiting-for-triage An issue we've not yet triaged or decided on label Jul 6, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

status: waiting-for-triage An issue we've not yet triaged or decided on

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants