From 65014d330adcf02baede9d76a2b14ee385676266 Mon Sep 17 00:00:00 2001 From: AnasRazy / <59137612+RazyAnas@users.noreply.github.com> Date: Sat, 27 Sep 2025 15:32:31 +0530 Subject: [PATCH] Fix off-by-one bug in HttpGetter.toByteArray() What this PR does: Fixes an off-by-one error in HttpGetter.toByteArray where responses of exactly maxBytes were being rejected. Now allows responses up to maxBytes, and only throws if the response is larger. Why this change is needed: Some feeds return responses exactly equal to the limit. Current implementation incorrectly throws an exception, breaking parsing. How it works: Reads up to maxBytes + 1 bytes. If actual size exceeds maxBytes, throws exception. Otherwise returns full content. Other notes: No breaking API changes. Safe for existing usage. --- .../com/commafeed/backend/HttpGetter.java | 37 ++++++++++--------- 1 file changed, 20 insertions(+), 17 deletions(-) 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 2a22d22c..774b1619 100644 --- a/commafeed-server/src/main/java/com/commafeed/backend/HttpGetter.java +++ b/commafeed-server/src/main/java/com/commafeed/backend/HttpGetter.java @@ -242,26 +242,29 @@ public class HttpGetter { return DateUtils.parseStandardDate(headerValue); } - +// ByteStreams.limit(input, maxBytes) reads at most maxBytes bytes. +// If the content length is exactly maxBytes, it throws an exception, even though the response is valid. +// This is an off-by-one error. private static byte[] toByteArray(HttpEntity entity, long maxBytes) throws IOException { - if (entity.getContentLength() > maxBytes) { - throw new IOException( - "Response size (%s bytes) exceeds the maximum allowed size (%s bytes)".formatted(entity.getContentLength(), maxBytes)); - } - - try (InputStream input = entity.getContent()) { - if (input == null) { - return null; - } - - byte[] bytes = ByteStreams.limit(input, maxBytes).readAllBytes(); - if (bytes.length == maxBytes) { - throw new IOException("Response size exceeds the maximum allowed size (%s bytes)".formatted(maxBytes)); - } - return bytes; - } + if (entity.getContentLength() > maxBytes) { + throw new IOException( + "Response size (%s bytes) exceeds the maximum allowed size (%s bytes)".formatted(entity.getContentLength(), maxBytes)); + } + + try (InputStream input = entity.getContent()) { + if (input == null) { + return null; + } + + byte[] bytes = ByteStreams.limit(input, maxBytes + 1).readAllBytes(); // read one extra to detect overflow + if (bytes.length > maxBytes) { + throw new IOException("Response size exceeds the maximum allowed size (%s bytes)".formatted(maxBytes)); + } + return bytes; + } } + private PoolingHttpClientConnectionManager newConnectionManager(CommaFeedConfiguration config) { SSLFactory sslFactory = SSLFactory.builder().withUnsafeTrustMaterial().withUnsafeHostnameVerifier().build();