Class GzipSupport.OptimisticAvailabilityInputStream

java.lang.Object
java.io.InputStream
java.io.FilterInputStream
com.google.api.client.http.GzipSupport.OptimisticAvailabilityInputStream
All Implemented Interfaces:
Closeable, AutoCloseable
Enclosing class:
GzipSupport

private static final class GzipSupport.OptimisticAvailabilityInputStream extends FilterInputStream
When GZIPInputStream completes processing an individual member it will call InputStream.available() to determine if there is more stream to try and process. If the call to available() returns 0 GZIPInputStream will determine it has processed the entirety of the underlying stream. This is spurious, as InputStream.available() is allowed to return 0 if it would require blocking in order for more bytes to be available. When GZIPInputStream is reading from a Transfer-Encoding: chunked response, if the chunk boundary happens to align closely enough to the member boundary GZIPInputStream won't consume the whole response.

This class, provides an optimistic "estimate" (in actuality, a lie) of the number of available() bytes in the underlying stream. It does this by tracking the last number of bytes read. If the last number of bytes read is grater than -1, we return Integer.MAX_VALUE to any call of available().

We're breaking the contract of available() in that we're lying about how much data we have accessible without blocking, however in the case where we're weaving GZIPInputStream into response processing we already know there are going to be blocking calls to read before the stream is exhausted.

This scenario isn't unique to processing of chunked responses, and can be replicated reliably using a SequenceInputStream with two underlying ByteArrayInputStream. See the corresponding test class for a reproduction.

The need for this class has been verified for the following JVMs:

  1.  openjdk version "1.8.0_292"
     OpenJDK Runtime Environment (AdoptOpenJDK)(build 1.8.0_292-b10)
     OpenJDK 64-Bit Server VM (AdoptOpenJDK)(build 25.292-b10, mixed mode)
       
  2.  openjdk version "11.0.14.1" 2022-02-08
     OpenJDK Runtime Environment Temurin-11.0.14.1+1 (build 11.0.14.1+1)
     OpenJDK 64-Bit Server VM Temurin-11.0.14.1+1 (build 11.0.14.1+1, mixed mode)
       
  3.  openjdk version "17" 2021-09-14
     OpenJDK Runtime Environment Temurin-17+35 (build 17+35)
     OpenJDK 64-Bit Server VM Temurin-17+35 (build 17+35, mixed mode, sharing)