@Override
    public InputStream read(final Path file, final TransferStatus status, final ConnectionCallback callback) throws BackgroundException {
        try {
            if(file.getType().contains(Path.Type.upload)) {
                return new NullInputStream(0L);
            }
            final HttpRange range = HttpRange.withStatus(status);
            final RequestEntityRestStorageService client = session.getClient();
            final Map<String, Object> requestHeaders = new HashMap<>();
            final Map<String, String> requestParameters = new HashMap<>();
            if(file.attributes().getVersionId() != null) {
                requestParameters.put("versionId", file.attributes().getVersionId());
            }
            if(status.isAppend()) {
                final String header;
                if(TransferStatus.UNKNOWN_LENGTH == range.getEnd()) {
                    header = String.format("bytes=%d-", range.getStart());
                }
                else {
                    header = String.format("bytes=%d-%d", range.getStart(), range.getEnd());
                }
                if(log.isDebugEnabled()) {
                    log.debug(String.format("Add range header %s for file %s", header, file));
                }
                requestHeaders.put(HttpHeaders.RANGE, header);
            }
            final Path bucket = containerService.getContainer(file);
            final HttpResponse response = client.performRestGet(bucket.isRoot() ? StringUtils.EMPTY : bucket.getName(),
                    containerService.getKey(file), requestParameters, requestHeaders, new int[]{HttpStatus.SC_PARTIAL_CONTENT, HttpStatus.SC_OK});
            return new HttpMethodReleaseInputStream(response, status);
        }
        catch(ServiceException e) {
            throw new S3ExceptionMappingService().map("Download {0} failed", e, file);
        }
        catch(IOException e) {
            throw new DefaultIOExceptionMappingService().map("Download {0} failed", e, file);
        }
    }
@Test
    public void testReadGzipContentEncoding() throws Exception {
        final ByteArrayOutputStream compressedStream = new ByteArrayOutputStream();
        final byte[] rawContent = RandomUtils.nextBytes(1457);
        final GZIPOutputStream gzipOutputStream = new GZIPOutputStream(compressedStream);
        gzipOutputStream.write(rawContent);
        // Make sure to write
        gzipOutputStream.close();
        final byte[] compressedContent = compressedStream.toByteArray();
        final Path container = new Path("test-eu-central-1-cyberduck", EnumSet.of(Path.Type.directory, Path.Type.volume));
        final Path file = new Path(container, new AlphanumericRandomStringService().random(), EnumSet.of(Path.Type.file));
        final TransferStatus status = new TransferStatus().withLength(compressedContent.length);
        status.setMetadata(Collections.singletonMap(HttpHeaders.CONTENT_ENCODING, "gzip"));
        assertNotEquals(TransferStatus.UNKNOWN_LENGTH, status.getLength());
        status.setChecksum(new SHA256ChecksumCompute().compute(new ByteArrayInputStream(compressedContent), status));
        final OutputStream out = new S3WriteFeature(session, new S3AccessControlListFeature(session)).write(file, status, new DisabledConnectionCallback());
        new StreamCopier(new TransferStatus(), new TransferStatus()).transfer(new ByteArrayInputStream(compressedContent), out);
        final InputStream in = new S3ReadFeature(session).read(file, status, new DisabledConnectionCallback());
        assertNotNull(in);
        assertEquals(TransferStatus.UNKNOWN_LENGTH, status.getLength());
        final BytecountStreamListener count = new BytecountStreamListener();
        final ByteArrayOutputStream received = new ByteArrayOutputStream();
        new StreamCopier(status, status).withListener(count).transfer(in, received);
        assertEquals(rawContent.length, count.getRecv());
        assertArrayEquals(rawContent, received.toByteArray());
        in.close();
        new S3DefaultDeleteFeature(session).delete(Collections.singletonList(file), new DisabledLoginCallback(), new Delete.DisabledCallback());
    }