diff --git a/src/changes/changes.xml b/src/changes/changes.xml index 3dc2f6c409..b0428fc45b 100644 --- a/src/changes/changes.xml +++ b/src/changes/changes.xml @@ -45,6 +45,7 @@ The type attribute can be add,update,fix,remove. + PercentCodec loses literal '+' when plusForSpace is enabled. Digest ALL reuses System.in, so only the first algorithm sees the real input (#431). diff --git a/src/main/java/org/apache/commons/codec/net/PercentCodec.java b/src/main/java/org/apache/commons/codec/net/PercentCodec.java index 1d11b09693..c7244397f6 100644 --- a/src/main/java/org/apache/commons/codec/net/PercentCodec.java +++ b/src/main/java/org/apache/commons/codec/net/PercentCodec.java @@ -44,6 +44,11 @@ public class PercentCodec implements BinaryEncoder, BinaryDecoder { */ private static final byte ESCAPE_CHAR = '%'; + /** + * The plus character used to encode spaces when plusForSpace is true. + */ + private static final byte PLUS_CHAR = '+'; + /** * The bit set used to store the character that should be always encoded. */ @@ -80,6 +85,9 @@ public PercentCodec() { public PercentCodec(final byte[] alwaysEncodeChars, final boolean plusForSpace) { this.plusForSpace = plusForSpace; insertAlwaysEncodeChars(alwaysEncodeChars); + if (plusForSpace) { + insertAlwaysEncodeChar(PLUS_CHAR); + } } private boolean canEncode(final byte c) { diff --git a/src/test/java/org/apache/commons/codec/net/PercentCodecTest.java b/src/test/java/org/apache/commons/codec/net/PercentCodecTest.java index 960aac14bb..ece15c167a 100644 --- a/src/test/java/org/apache/commons/codec/net/PercentCodecTest.java +++ b/src/test/java/org/apache/commons/codec/net/PercentCodecTest.java @@ -131,6 +131,28 @@ void testPercentEncoderDecoderWithPlusForSpace() throws Exception { assertEquals(new String(decode, StandardCharsets.UTF_8), input, "PercentCodec plus for space decoding test"); } + @Test + void testPercentEncoderDecoderWithPlusForSpaceEscapesLiteralPlus() throws Exception { + final String input = "a+b c"; + final PercentCodec percentCodec = new PercentCodec(null, true); + final byte[] encoded = percentCodec.encode(input.getBytes(StandardCharsets.UTF_8)); + final String encodedS = new String(encoded, StandardCharsets.UTF_8); + assertEquals("a%2Bb+c", encodedS, "PercentCodec plus for space should escape literal plus"); + final byte[] decode = percentCodec.decode(encoded); + assertEquals(new String(decode, StandardCharsets.UTF_8), input, "PercentCodec literal plus decoding test"); + } + + @Test + void testPercentEncoderDecoderWithPlusForSpaceEscapesLiteralPlusWithoutSpaces() throws Exception { + final String input = "a+b"; + final PercentCodec percentCodec = new PercentCodec(null, true); + final byte[] encoded = percentCodec.encode(input.getBytes(StandardCharsets.UTF_8)); + final String encodedS = new String(encoded, StandardCharsets.UTF_8); + assertEquals("a%2Bb", encodedS, "PercentCodec plus for space should escape literal plus without spaces"); + final byte[] decode = percentCodec.decode(encoded); + assertEquals(new String(decode, StandardCharsets.UTF_8), input, "PercentCodec literal plus decoding test"); + } + @Test void testSafeCharEncodeDecodeObject() throws Exception { final PercentCodec percentCodec = new PercentCodec(null, true);