From 046de5fc51700bf8d75232b5963127630dcf19ec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christoph=20L=C3=A4ubrich?= Date: Fri, 21 Jun 2024 08:16:20 +0200 Subject: [PATCH] Only cap the input if content length header is given Currently RqLengthAware uses the InputStream#available to cap the input if no Content-Length header is given, but the return value does not say anything about the real content length, only how many bytes can be read without blocking (what might be 0). This now only returns a CapInputStream when a Content-Length is given in the request and adds a testcase for the given case. --- src/main/java/org/takes/rq/RqLengthAware.java | 23 +++++++++++---- .../java/org/takes/rq/RqLengthAwareTest.java | 28 +++++++++++++++++++ 2 files changed, 45 insertions(+), 6 deletions(-) diff --git a/src/main/java/org/takes/rq/RqLengthAware.java b/src/main/java/org/takes/rq/RqLengthAware.java index 0436b0d74..71177d259 100644 --- a/src/main/java/org/takes/rq/RqLengthAware.java +++ b/src/main/java/org/takes/rq/RqLengthAware.java @@ -51,6 +51,10 @@ */ @EqualsAndHashCode(callSuper = true) public final class RqLengthAware extends RqWrap { + /** + * Constant for the Content-Length header. + */ + private static final String CONTENT_LENGTH = "Content-Length"; /** * Ctor. @@ -68,14 +72,21 @@ public RqLengthAware(final Request req) { */ private static InputStream cap(final Request req) throws IOException { final Iterator hdr = new RqHeaders.Base(req) - .header("Content-Length").iterator(); - InputStream body = req.body(); - long length = (long) body.available(); + .header(RqLengthAware.CONTENT_LENGTH).iterator(); + final InputStream result; if (hdr.hasNext()) { - length = Long.parseLong(hdr.next()); + final String value = hdr.next(); + try { + result = new CapInputStream(req.body(), Long.parseLong(value)); + } catch (final NumberFormatException ex) { + final String msg = "Invalid %s header: %s"; + final String formated = String.format(msg, RqLengthAware.CONTENT_LENGTH, value); + throw new IOException(formated, ex); + } + } else { + result = req.body(); } - body = new CapInputStream(body, length); - return body; + return result; } } diff --git a/src/test/java/org/takes/rq/RqLengthAwareTest.java b/src/test/java/org/takes/rq/RqLengthAwareTest.java index 4fe943c8f..aa9222be3 100644 --- a/src/test/java/org/takes/rq/RqLengthAwareTest.java +++ b/src/test/java/org/takes/rq/RqLengthAwareTest.java @@ -23,6 +23,8 @@ */ package org.takes.rq; +import java.io.ByteArrayInputStream; +import java.io.FilterInputStream; import java.io.IOException; import java.io.InputStream; import java.util.Arrays; @@ -96,6 +98,32 @@ void readsByte() throws IOException { ); } + @Test + void noContentLength() throws IOException { + final byte[] bytes = "test".getBytes(); + final InputStream data = new FilterInputStream(new ByteArrayInputStream(bytes)) { + @Override + public int available() throws IOException { + return 1; + } + }; + final InputStream stream = new RqLengthAware( + new RqFake( + Arrays.asList( + "GET /test1", + "Host: b.example.com" + ), + data + ) + ).body(); + for (final byte element : bytes) { + MatcherAssert.assertThat( + stream.read(), + Matchers.equalTo(element & 0xFF) + ); + } + } + @Test void readsByteArray() throws IOException { final String data = "array";