Input streams returned by DecompressingEntity.getContent() should

support mark(int) and reset() if the underlying stream does

- Pass calls to the underlying InputStream for mark(int)
- Pass calls to the underlying InputStream for reset()
- LazyDecompressingInputStream extends FilterInputStream
- Reimplement internals fluently
- Reuse Closer.close(Closeable)
- Tested locally with git master 5.3-beta2-SNAPSHOT
This commit is contained in:
Gary Gregory 2024-08-16 14:01:08 -04:00 committed by Gary Gregory
parent d7ed56894a
commit 2dafdca160
2 changed files with 47 additions and 20 deletions

View File

@ -26,15 +26,18 @@
*/ */
package org.apache.hc.client5.http.entity; package org.apache.hc.client5.http.entity;
import java.io.FilterInputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.UncheckedIOException;
import org.apache.hc.core5.io.Closer;
/** /**
* Lazy init InputStream wrapper. * Lazy initializes from an {@link InputStream} wrapper.
*/ */
class LazyDecompressingInputStream extends InputStream { class LazyDecompressingInputStream extends FilterInputStream {
private final InputStream wrappedStream;
private final InputStreamFactory inputStreamFactory; private final InputStreamFactory inputStreamFactory;
private InputStream wrapperStream; private InputStream wrapperStream;
@ -42,38 +45,35 @@ class LazyDecompressingInputStream extends InputStream {
public LazyDecompressingInputStream( public LazyDecompressingInputStream(
final InputStream wrappedStream, final InputStream wrappedStream,
final InputStreamFactory inputStreamFactory) { final InputStreamFactory inputStreamFactory) {
this.wrappedStream = wrappedStream; super(wrappedStream);
this.inputStreamFactory = inputStreamFactory; this.inputStreamFactory = inputStreamFactory;
} }
private void initWrapper() throws IOException { private InputStream initWrapper() throws IOException {
if (wrapperStream == null) { if (wrapperStream == null) {
wrapperStream = inputStreamFactory.create(wrappedStream); wrapperStream = inputStreamFactory.create(in);
} }
return wrapperStream;
} }
@Override @Override
public int read() throws IOException { public int read() throws IOException {
initWrapper(); return initWrapper().read();
return wrapperStream.read();
} }
@Override @Override
public int read(final byte[] b) throws IOException { public int read(final byte[] b) throws IOException {
initWrapper(); return initWrapper().read(b);
return wrapperStream.read(b);
} }
@Override @Override
public int read(final byte[] b, final int off, final int len) throws IOException { public int read(final byte[] b, final int off, final int len) throws IOException {
initWrapper(); return initWrapper().read(b, off, len);
return wrapperStream.read(b, off, len);
} }
@Override @Override
public long skip(final long n) throws IOException { public long skip(final long n) throws IOException {
initWrapper(); return initWrapper().skip(n);
return wrapperStream.skip(n);
} }
@Override @Override
@ -83,19 +83,29 @@ class LazyDecompressingInputStream extends InputStream {
@Override @Override
public int available() throws IOException { public int available() throws IOException {
initWrapper(); return initWrapper().available();
return wrapperStream.available();
} }
@Override @Override
public void close() throws IOException { public void close() throws IOException {
try { try {
if (wrapperStream != null) { Closer.close(wrapperStream);
wrapperStream.close();
}
} finally { } finally {
wrappedStream.close(); super.close();
} }
} }
@Override
public void mark(final int readlimit) {
try {
initWrapper().mark(readlimit);
} catch (final IOException e) {
throw new UncheckedIOException(e);
}
}
@Override
public void reset() throws IOException {
initWrapper().reset();
}
} }

View File

@ -76,6 +76,22 @@ class TestDecompressingEntity {
EntityUtils.consume(entity); EntityUtils.consume(entity);
} }
@Test
void testStreamingMarking() throws Exception {
final CRC32 crc32 = new CRC32();
final ByteArrayInputStream in = new ByteArrayInputStream("1234567890".getBytes(StandardCharsets.US_ASCII));
final InputStreamEntity wrapped = new InputStreamEntity(in, -1, ContentType.DEFAULT_TEXT);
final ChecksumEntity entity = new ChecksumEntity(wrapped, crc32);
final InputStream in1 = entity.getContent();
Assertions.assertEquals('1', in1.read());
Assertions.assertEquals('2', in1.read());
in1.mark(1);
Assertions.assertEquals('3', in1.read());
in1.reset();
Assertions.assertEquals('3', in1.read());
EntityUtils.consume(entity);
}
@Test @Test
void testWriteToStream() throws Exception { void testWriteToStream() throws Exception {
final CRC32 crc32 = new CRC32(); final CRC32 crc32 = new CRC32();
@ -101,3 +117,4 @@ class TestDecompressingEntity {
} }
} }