diff --git a/httpcore5/src/main/java/org/apache/hc/core5/net/PercentCodec.java b/httpcore5/src/main/java/org/apache/hc/core5/net/PercentCodec.java index 3e1700002..2a7f30b38 100644 --- a/httpcore5/src/main/java/org/apache/hc/core5/net/PercentCodec.java +++ b/httpcore5/src/main/java/org/apache/hc/core5/net/PercentCodec.java @@ -236,7 +236,11 @@ static String decode(final CharSequence content, final Charset charset, final bo } else if (plusAsBlank && c == '+') { bb.put((byte) ' '); } else { - bb.put((byte) c); + if (c > 0x7f) { + bb.put((byte) '?'); + } else { + bb.put((byte) c); + } } } bb.flip(); diff --git a/httpcore5/src/test/java/org/apache/hc/core5/net/TestPercentCodec.java b/httpcore5/src/test/java/org/apache/hc/core5/net/TestPercentCodec.java index 7c1b72aea..c6a2b0459 100644 --- a/httpcore5/src/test/java/org/apache/hc/core5/net/TestPercentCodec.java +++ b/httpcore5/src/test/java/org/apache/hc/core5/net/TestPercentCodec.java @@ -116,4 +116,26 @@ void testPercentCodecEncodeIsNotRfc7639Canonical() { assertEquals("%7C", PercentCodec.encode("|", StandardCharsets.UTF_8)); } + @Test + void decodeIllegalChars() { + assertEquals( + "1?2?3?4", + PercentCodec.decode("1\u012E2\u012E3\u012E4", StandardCharsets.UTF_8)); + } + + @Test + void testDecodeDoesNotCombineEscapedBytesAcrossLiteralCharacters() { + assertEquals( + "\uFFFDx\uFFFD", + PercentCodec.decode("%C3x%A4", StandardCharsets.UTF_8)); + } + + @Test + void testEncodeHonorsUtf16Charset() { + assertEquals( + "%FE%FF%00a%00b%00c", + PercentCodec.encode("abc", StandardCharsets.UTF_16)); + + } + }