code: private void closeStream(String reason, long length, boolean forceAbort) {
      if (wrappedStream != null) {
  
        // if the amount of data remaining in the current request is greater
        // than the readahead value: abort.
        long remaining = remainingInCurrentRequest();
        LOG.debug("Closing stream {}: {}", reason,
            forceAbort ? "abort" : "soft");
        boolean shouldAbort = forceAbort || remaining > readahead;
        if (!shouldAbort) {
          try {
            // clean close. This will read to the end of the stream,
            // so, while cleaner, can be pathological on a multi-GB object
  
            // explicitly drain the stream
            long drained = 0;
            while (wrappedStream.read() >= 0) {
              drained++;
            }
            LOG.debug("Drained stream of {} bytes", drained);
  
            // now close it
            wrappedStream.close();
            // this MUST come after the close, so that if the IO operations fail
            // and an abort is triggered, the initial attempt's statistics
            // aren't collected.
          } catch (IOException e) {
            // exception escalates to an abort
            LOG.debug("When closing {} stream for {}", uri, reason, e);
            shouldAbort = true;
          }
        }
        if (shouldAbort) {
          // Abort, rather than just close, the underlying stream.  Otherwise, the
          // remaining object payload is read from S3 while closing the stream.
          LOG.debug("Aborting stream");
          wrappedStream.abort();
        }
        LOG.debug("Stream {} {}: {}; remaining={} streamPos={},"
                + " nextReadPos={},"
                + " request range {}-{} length={}",
            uri, (shouldAbort ? "aborted" : "closed"), reason,
            remaining, pos, nextReadPos,
            contentRangeStart, contentRangeFinish,
            length);
        wrappedStream = null;
      }
    }
docs: Close a stream: decide whether to abort or close, based on
  the length of the stream and the current position.
  If a close() is attempted and fails, the operation escalates to
  an abort.
  
  This does not set the {@link #closed} flag.
  @param reason reason for stream being closed; used in messages
  @param length length of the stream
  @param forceAbort force an abort; used if explicitly requested