HttpUtil#normalizeAndGetContentLength() should handle empty value (#11409)

__Motivation__

`HttpUtil#normalizeAndGetContentLength()` throws `StringIndexOutOfBoundsException` for empty `content-length` values, it should instead throw `IllegalArgumentException` for all invalid values.

__Modification__

- Throw `IllegalArgumentException` if the `content-length` value is empty.
- Add tests

__Result__

Fixes https://github.com/netty/netty/issues/11408
This commit is contained in:
Nitesh Kant 2021-06-23 03:07:16 -07:00 committed by GitHub
parent 98a3a0c0cb
commit 5a658bb887
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 34 additions and 7 deletions

View File

@ -602,7 +602,7 @@ public final class HttpUtil {
} }
// Ensure we not allow sign as part of the content-length: // Ensure we not allow sign as part of the content-length:
// See https://github.com/squid-cache/squid/security/advisories/GHSA-qf3v-rc95-96j5 // See https://github.com/squid-cache/squid/security/advisories/GHSA-qf3v-rc95-96j5
if (!Character.isDigit(firstField.charAt(0))) { if (firstField.isEmpty() || !Character.isDigit(firstField.charAt(0))) {
// Reject the message as invalid // Reject the message as invalid
throw new IllegalArgumentException( throw new IllegalArgumentException(
"Content-Length value is not a number: " + firstField); "Content-Length value is not a number: " + firstField);

View File

@ -15,21 +15,24 @@
*/ */
package io.netty.handler.codec.http; package io.netty.handler.codec.http;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;
import org.junit.Test;
import org.junit.jupiter.api.function.Executable;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.nio.charset.StandardCharsets; import java.nio.charset.StandardCharsets;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.List; import java.util.List;
import io.netty.util.CharsetUtil;
import io.netty.util.ReferenceCountUtil;
import org.junit.Test;
import static io.netty.handler.codec.http.HttpHeadersTestUtils.of; import static io.netty.handler.codec.http.HttpHeadersTestUtils.of;
import static io.netty.handler.codec.http.HttpUtil.normalizeAndGetContentLength;
import static java.util.Collections.singletonList;
import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNull; import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assertions.fail;
@ -246,7 +249,7 @@ public class HttpUtilTest {
HttpMessage message = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK); HttpMessage message = new DefaultHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK);
message.headers().add(HttpHeaderNames.TRANSFER_ENCODING, "chunked"); message.headers().add(HttpHeaderNames.TRANSFER_ENCODING, "chunked");
HttpUtil.setTransferEncodingChunked(message, true); HttpUtil.setTransferEncodingChunked(message, true);
List<String> expected = Collections.singletonList("chunked"); List<String> expected = singletonList("chunked");
assertEquals(expected, message.headers().getAll(HttpHeaderNames.TRANSFER_ENCODING)); assertEquals(expected, message.headers().getAll(HttpHeaderNames.TRANSFER_ENCODING));
} }
@ -395,4 +398,28 @@ public class HttpUtilTest {
HttpHeaderNames.CONNECTION, HttpHeaderValues.UPGRADE + ", " + HttpHeaderValues.KEEP_ALIVE); HttpHeaderNames.CONNECTION, HttpHeaderValues.UPGRADE + ", " + HttpHeaderValues.KEEP_ALIVE);
assertTrue(HttpUtil.isKeepAlive(http11Message)); assertTrue(HttpUtil.isKeepAlive(http11Message));
} }
@Test
public void normalizeAndGetContentLengthEmpty() {
testNormalizeAndGetContentLengthInvalidContentLength("");
}
@Test
public void normalizeAndGetContentLengthNotANumber() {
testNormalizeAndGetContentLengthInvalidContentLength("foo");
}
@Test
public void normalizeAndGetContentLengthNegative() {
testNormalizeAndGetContentLengthInvalidContentLength("-1");
}
private static void testNormalizeAndGetContentLengthInvalidContentLength(final String contentLengthField) {
assertThrows(IllegalArgumentException.class, new Executable() {
@Override
public void execute() {
normalizeAndGetContentLength(singletonList(contentLengthField), false, false);
}
});
}
} }