PercentCodec decoder to disallow non-ASCII characters in input
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 3e17000..2a7f30b 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 7c1b72a..c6a2b04 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)); + + } + }