diff --git a/commafeed-server/src/main/java/com/commafeed/backend/HttpGetter.java b/commafeed-server/src/main/java/com/commafeed/backend/HttpGetter.java index 4343135f..97b92c0d 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/HttpGetter.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/HttpGetter.java @@ -16,6 +16,7 @@ import lombok.EqualsAndHashCode; import lombok.Getter; import lombok.Lombok; import lombok.RequiredArgsConstructor; +import lombok.experimental.Delegate; import lombok.extern.slf4j.Slf4j; import org.apache.commons.lang3.ArrayUtils; @@ -30,9 +31,12 @@ import org.apache.hc.client5.http.protocol.RedirectLocations; import org.apache.hc.client5.http.utils.DateUtils; import org.apache.hc.core5.concurrent.FutureCallback; import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.EntityDetails; +import org.apache.hc.core5.http.HttpException; import org.apache.hc.core5.http.HttpStatus; import org.apache.hc.core5.http.Message; import org.apache.hc.core5.http.NameValuePair; +import org.apache.hc.core5.http.nio.AsyncEntityConsumer; import org.apache.hc.core5.http.nio.AsyncRequestProducer; import org.apache.hc.core5.http.nio.AsyncResponseConsumer; import org.apache.hc.core5.http.nio.entity.AbstractBinAsyncEntityConsumer; @@ -165,11 +169,12 @@ public class HttpGetter { .setProtocolUpgradeEnabled(false) .build()); + long maxResponseSize = config.httpClient().maxResponseSize().asLongValue(); AsyncRequestProducer req = SimpleRequestProducer.create(request.toSimpleHttpRequest()); AsyncResponseConsumer> resp = new BasicResponseConsumer<>( - new LimitedBytesEntityConsumer( - config.httpClient().maxResponseSize().asLongValue())); + new LimitedContentLengthEntityConsumer( + new LimitedBytesEntityConsumer(maxResponseSize), maxResponseSize)); FutureCallback> callback = new FutureCallback<>() { @Override @@ -281,6 +286,23 @@ public class HttpGetter { .build(); } + private record LimitedContentLengthEntityConsumer( + @Delegate AsyncEntityConsumer delegate, long maxBytes) + implements AsyncEntityConsumer { + + @Override + public void streamStart(EntityDetails entityDetails, FutureCallback resultCallback) + throws HttpException, IOException { + long contentLength = entityDetails.getContentLength(); + if (contentLength > maxBytes) { + throw new IOException( + "Response size (%s bytes) exceeds the maximum allowed size (%s bytes)" + .formatted(contentLength, maxBytes)); + } + delegate.streamStart(entityDetails, resultCallback); + } + } + @RequiredArgsConstructor private static class LimitedBytesEntityConsumer extends AbstractBinAsyncEntityConsumer { diff --git a/commafeed-server/src/test/java/com/commafeed/backend/HttpGetterTest.java b/commafeed-server/src/test/java/com/commafeed/backend/HttpGetterTest.java index d8534d82..1d24ce55 100644 --- a/commafeed-server/src/test/java/com/commafeed/backend/HttpGetterTest.java +++ b/commafeed-server/src/test/java/com/commafeed/backend/HttpGetterTest.java @@ -360,7 +360,8 @@ class HttpGetterTest { IOException e = Assertions.assertThrows(IOException.class, () -> getter.get(this.feedUrl)); Assertions.assertEquals( - "Response size exceeds the maximum allowed size (10000 bytes)", e.getMessage()); + "Response size (100000 bytes) exceeds the maximum allowed size (10000 bytes)", + e.getMessage()); } @Test