This is an automated email from the ASF dual-hosted git repository.

desruisseaux pushed a commit to branch geoapi-4.0
in repository https://gitbox.apache.org/repos/asf/sis.git

commit 906fcdf516d4ba3c0ff22549bbebd0a1f6eb7cfe
Author: Martin Desruisseaux <[email protected]>
AuthorDate: Thu May 22 05:05:25 2025 +0200

    Missing EOF detection when using HTTP ranges or S3.
---
 .../apache/sis/io/stream/FileCacheByteChannel.java | 24 +++++++++++++++++-----
 1 file changed, 19 insertions(+), 5 deletions(-)

diff --git 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/FileCacheByteChannel.java
 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/FileCacheByteChannel.java
index cb9e13b396..da27553604 100644
--- 
a/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/FileCacheByteChannel.java
+++ 
b/endorsed/src/org.apache.sis.storage/main/org/apache/sis/io/stream/FileCacheByteChannel.java
@@ -406,6 +406,7 @@ public abstract class FileCacheByteChannel extends 
ByteRangeChannel implements S
      * @param  end    position of the last byte to read with the returned 
stream (inclusive),
      *                or {@link Long#MAX_VALUE} for end of stream.
      * @return information about the input stream providing the bytes to read 
starting at the given start position.
+     *         May be {@code null} if this method detects that the {@code 
start} position is after the end of stream.
      * @throws IOException if the connection cannot be established.
      */
     protected abstract Connection openConnection(long start, long end) throws 
IOException;
@@ -415,7 +416,7 @@ public abstract class FileCacheByteChannel extends 
ByteRangeChannel implements S
      * This method is invoked for example when this channel needs to skip an 
arbitrarily large number
      * of bytes because the {@linkplain #position(long) position changed}. The 
{@code connection}
      * argument is the value returned by a previous call to {@link 
#openConnection(long, long)}.
-     * The boolean return value tells what this method has done:
+     * The Boolean return value tells what this method has done:
      *
      * <ul class="verbose">
      *   <li>If this method returns {@code true}, then the input stream has 
been closed by this method and this
@@ -505,7 +506,7 @@ public abstract class FileCacheByteChannel extends 
ByteRangeChannel implements S
      * the current position. If the gab between ranges is less than {@link 
#SKIP_THRESHOLD},
      * the ranges will be merged in a single request.
      *
-     * @return the opened connection (never {@code null}).
+     * @return the opened connection, or {@code null} if end of stream.
      * @throws IOException if the connection cannot be established.
      */
     private Connection openConnection() throws IOException {
@@ -514,7 +515,14 @@ public abstract class FileCacheByteChannel extends 
ByteRangeChannel implements S
         long end;
         do {                    // Should be executed exactly 1 or 2 times.
             if (i >= size) {
-                end = (length > 0) ? length-1 : Long.MAX_VALUE;
+                if (length <= 0) {
+                    end = Long.MAX_VALUE;
+                } else {
+                    end = length - 1;
+                    if (position > end) {
+                        return null;
+                    }
+                }
                 break;
             }
             end = rangesOfInterest.getMaxLong(i) - 1;       // Inclusive
@@ -522,7 +530,7 @@ public abstract class FileCacheByteChannel extends 
ByteRangeChannel implements S
         } while (end < position);
         /*
          * At this point we found the smallest "end of range" position.
-         * If the gab with next range is small enough, merge the ranges
+         * If the gap with next range is small enough, merge the ranges
          * in order to make a single connection request.
          */
         while (i < size) {
@@ -538,6 +546,9 @@ public abstract class FileCacheByteChannel extends 
ByteRangeChannel implements S
          * Save the stream length if it is known.
          */
         final Connection c = openConnection(position, end);
+        if (c == null) {
+            return null;
+        }
         file.position(c.start);
         if (c.length >= 0) {
             length = c.length;
@@ -647,6 +658,9 @@ public abstract class FileCacheByteChannel extends 
ByteRangeChannel implements S
          */
         if (c == null) {
             c = openConnection();
+            if (c == null) {
+                return -1;
+            }
             offset = position - c.start;
         }
         offset = skipInInput(offset);
@@ -877,7 +891,7 @@ public abstract class FileCacheByteChannel extends 
ByteRangeChannel implements S
         }
 
         /**
-         * Invoked in a background thread after a delay for closing a possibly 
inactive connection.
+         * Invoked in a background thread after a delay for closing a possibly 
inactive connections.
          * If this method confirms that the connection has been inactive for a 
time longer than the timeout,
          * then the connection is closed. Otherwise a new task is scheduled 
for checking again later.
          */

Reply via email to