Skip to content

Commit 733393c

Browse files
committed
fix(appsec): use CharsetDecoder with REPORT for charset fallback in FileItemContentReader
1 parent 045ea63 commit 733393c

2 files changed

Lines changed: 20 additions & 2 deletions

File tree

dd-java-agent/instrumentation/commons-fileupload-1.5/src/main/java/datadog/trace/instrumentation/commons/fileupload/FileItemContentReader.java

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,10 @@
22

33
import java.io.IOException;
44
import java.io.InputStream;
5+
import java.nio.ByteBuffer;
6+
import java.nio.charset.CharacterCodingException;
57
import java.nio.charset.Charset;
8+
import java.nio.charset.CodingErrorAction;
69
import java.nio.charset.StandardCharsets;
710
import java.util.ArrayList;
811
import java.util.List;
@@ -47,8 +50,13 @@ static String decodeBytes(byte[] buf, int length, String contentType) {
4750
Charset charset = extractCharset(contentType);
4851
if (charset == null) charset = StandardCharsets.UTF_8;
4952
try {
50-
return new String(buf, 0, length, charset);
51-
} catch (Exception e) {
53+
return charset
54+
.newDecoder()
55+
.onMalformedInput(CodingErrorAction.REPORT)
56+
.onUnmappableCharacter(CodingErrorAction.REPORT)
57+
.decode(ByteBuffer.wrap(buf, 0, length))
58+
.toString();
59+
} catch (CharacterCodingException e) {
5260
return new String(buf, 0, length, StandardCharsets.ISO_8859_1);
5361
}
5462
}

dd-java-agent/instrumentation/commons-fileupload-1.5/src/test/groovy/FileItemContentReaderTest.groovy

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,16 @@ class FileItemContentReaderTest extends Specification {
6666
FileItemContentReader.readContent(item) == text
6767
}
6868

69+
void 'readContent falls back to ISO-8859-1 when bytes are invalid UTF-8'() {
70+
given:
71+
// 0xE9 is 'é' in ISO-8859-1 but an invalid lone UTF-8 byte
72+
byte[] iso88591Bytes = 'café'.getBytes('ISO-8859-1')
73+
def item = fileItemFromBytes(iso88591Bytes, 'file.txt', null)
74+
75+
expect:
76+
FileItemContentReader.readContent(item) == 'café'
77+
}
78+
6979
void 'readContents returns content for each non-form file with a name'() {
7080
given:
7181
def items = [fileItem('content-a', 'file-a.txt'), fileItem('content-b', 'file-b.txt'),]

0 commit comments

Comments
 (0)