Skip to content

Commit fcb7cdc

Browse files
committed
internal-api: accept whitespace around = in MultipartContentDecoder charset param
extractCharset() only matched the literal token "charset=", so "charset = X" or "charset =X" (whitespace around the equals sign) was treated as no-charset-declared and silently overridden with UTF-8.
1 parent 46aace9 commit fcb7cdc

2 files changed

Lines changed: 27 additions & 8 deletions

File tree

internal-api/src/main/java/datadog/trace/api/http/MultipartContentDecoder.java

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -39,18 +39,26 @@ public static String decodeBytes(byte[] buf, int length, String contentType) {
3939

4040
public static Charset extractCharset(String contentType) {
4141
if (contentType == null) return null;
42+
int len = contentType.length();
4243
int searchFrom = 0;
4344
while (true) {
44-
int idx = indexOfIgnoreAsciiCase(contentType, "charset=", searchFrom);
45+
int idx = indexOfIgnoreAsciiCase(contentType, "charset", searchFrom);
4546
if (idx < 0) return null;
46-
// Require a parameter boundary before "charset=" so "xcharset=..." is not matched.
47+
// Require a parameter boundary before "charset" so "xcharset=..." is not matched.
4748
// RFC 7230 optional whitespace (OWS) allows both space and horizontal tab.
48-
if (idx == 0
49-
|| contentType.charAt(idx - 1) == ';'
50-
|| contentType.charAt(idx - 1) == ' '
51-
|| contentType.charAt(idx - 1) == '\t') {
52-
int nameStart = idx + 8;
53-
int end = contentType.length();
49+
boolean boundaryOk =
50+
idx == 0
51+
|| contentType.charAt(idx - 1) == ';'
52+
|| contentType.charAt(idx - 1) == ' '
53+
|| contentType.charAt(idx - 1) == '\t';
54+
// Also allow OWS around the "=", e.g. "charset = ISO-8859-1".
55+
int j = idx + 7;
56+
while (j < len && (contentType.charAt(j) == ' ' || contentType.charAt(j) == '\t')) j++;
57+
if (boundaryOk && j < len && contentType.charAt(j) == '=') {
58+
j++;
59+
while (j < len && (contentType.charAt(j) == ' ' || contentType.charAt(j) == '\t')) j++;
60+
int nameStart = j;
61+
int end = len;
5462
for (int i = nameStart; i < end; i++) {
5563
char c = contentType.charAt(i);
5664
if (c == ';' || c == ',' || c == ' ') {

internal-api/src/test/java/datadog/trace/api/http/MultipartContentDecoderTest.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,17 @@ void extractCharsetAcceptsTabAsParameterBoundary(String contentType) {
123123
assertEquals("ISO-8859-1", MultipartContentDecoder.extractCharset(contentType).name());
124124
}
125125

126+
@ParameterizedTest
127+
@ValueSource(
128+
strings = {
129+
"text/plain; charset = ISO-8859-1",
130+
"text/plain; charset =ISO-8859-1",
131+
"text/plain; charset= ISO-8859-1"
132+
})
133+
void extractCharsetAcceptsWhitespaceAroundEqualsSign(String contentType) {
134+
assertEquals("ISO-8859-1", MultipartContentDecoder.extractCharset(contentType).name());
135+
}
136+
126137
@Test
127138
void extractCharsetIgnoresSubstringMatchInParameterName() {
128139
// "xcharset=UTF-16" must not match; the real "charset=UTF-8" that follows must be used

0 commit comments

Comments
 (0)