Fix regression in HttpPostStandardRequestDecoder to always decode + to whitespace (#10285)

Motivations
-----------
HttpPostStandardRequestDecoder was changed in 4.1.50 to provide its own
ByteBuf UrlDecoder. Prior to this change, it was using the decodeComponent
method from QueryStringDecoder which decoded + characters to
whitespaces. This behavior needs to be preserved to maintain backward
compatibility.

Modifications
-------------
Changed HttpPostStandardRequestDecoder to detect + bytes and decode them
toe whitespaces. Added a test.

Results
-------
Addresses issues#10284
This commit is contained in:
Fabien Renaud 2020-05-14 00:28:40 -07:00 committed by GitHub
parent caf51b7284
commit d5087deec6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 16 additions and 3 deletions

View File

@ -656,7 +656,7 @@ public class HttpPostStandardRequestDecoder implements InterfaceHttpPostRequestD
} }
private static ByteBuf decodeAttribute(ByteBuf b, Charset charset) { private static ByteBuf decodeAttribute(ByteBuf b, Charset charset) {
int firstEscaped = b.forEachByte(new ByteProcessor.IndexOfProcessor((byte) '%')); int firstEscaped = b.forEachByte(new UrlEncodedDetector());
if (firstEscaped == -1) { if (firstEscaped == -1) {
return null; // nothing to decode return null; // nothing to decode
} }
@ -714,6 +714,13 @@ public class HttpPostStandardRequestDecoder implements InterfaceHttpPostRequestD
factory.removeHttpDataFromClean(request, data); factory.removeHttpDataFromClean(request, data);
} }
private static final class UrlEncodedDetector implements ByteProcessor {
@Override
public boolean process(byte value) throws Exception {
return value != '%' && value != '+';
}
}
private static final class UrlDecoder implements ByteProcessor { private static final class UrlDecoder implements ByteProcessor {
private final ByteBuf output; private final ByteBuf output;
@ -742,6 +749,8 @@ public class HttpPostStandardRequestDecoder implements InterfaceHttpPostRequestD
} }
} else if (value == '%') { } else if (value == '%') {
nextEscapedIdx = 1; nextEscapedIdx = 1;
} else if (value == '+') {
output.writeByte(' ');
} else { } else {
output.writeByte(value); output.writeByte(value);
} }

View File

@ -829,7 +829,7 @@ public class HttpPostRequestDecoderTest {
@Test @Test
public void testDecodeFullHttpRequestWithUrlEncodedBody() throws Exception { public void testDecodeFullHttpRequestWithUrlEncodedBody() throws Exception {
byte[] bodyBytes = "foo=bar&a=b&empty=&city=%3c%22new%22%20york%20city%3e".getBytes(); byte[] bodyBytes = "foo=bar&a=b&empty=&city=%3c%22new%22%20york%20city%3e&other_city=los+angeles".getBytes();
ByteBuf content = Unpooled.directBuffer(bodyBytes.length); ByteBuf content = Unpooled.directBuffer(bodyBytes.length);
content.writeBytes(bodyBytes); content.writeBytes(bodyBytes);
@ -838,7 +838,7 @@ public class HttpPostRequestDecoderTest {
assertFalse(decoder.getBodyHttpDatas().isEmpty()); assertFalse(decoder.getBodyHttpDatas().isEmpty());
assertFalse(decoder.getBodyHttpDatas().isEmpty()); assertFalse(decoder.getBodyHttpDatas().isEmpty());
assertEquals(4, decoder.getBodyHttpDatas().size()); assertEquals(5, decoder.getBodyHttpDatas().size());
Attribute attr = (Attribute) decoder.getBodyHttpData("foo"); Attribute attr = (Attribute) decoder.getBodyHttpData("foo");
assertTrue(attr.getByteBuf().isDirect()); assertTrue(attr.getByteBuf().isDirect());
@ -856,6 +856,10 @@ public class HttpPostRequestDecoderTest {
assertTrue(attr.getByteBuf().isDirect()); assertTrue(attr.getByteBuf().isDirect());
assertEquals("<\"new\" york city>", attr.getValue()); assertEquals("<\"new\" york city>", attr.getValue());
attr = (Attribute) decoder.getBodyHttpData("other_city");
assertTrue(attr.getByteBuf().isDirect());
assertEquals("los angeles", attr.getValue());
decoder.destroy(); decoder.destroy();
req.release(); req.release();
} }