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;
import java.io.FilterInputStream;
import java.io.IOException;
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 InputStream wrapperStream;
@ -42,38 +45,35 @@ class LazyDecompressingInputStream extends InputStream {
public LazyDecompressingInputStream(
final InputStream wrappedStream,
final InputStreamFactory inputStreamFactory) {
this.wrappedStream = wrappedStream;
super(wrappedStream);
this.inputStreamFactory = inputStreamFactory;
}
private void initWrapper() throws IOException {
private InputStream initWrapper() throws IOException {
if (wrapperStream == null) {
wrapperStream = inputStreamFactory.create(wrappedStream);
wrapperStream = inputStreamFactory.create(in);
}
return wrapperStream;
}
@Override
public int read() throws IOException {
initWrapper();
return wrapperStream.read();
return initWrapper().read();
}
@Override
public int read(final byte[] b) throws IOException {
initWrapper();
return wrapperStream.read(b);
return initWrapper().read(b);
}
@Override
public int read(final byte[] b, final int off, final int len) throws IOException {
initWrapper();
return wrapperStream.read(b, off, len);
return initWrapper().read(b, off, len);
}
@Override
public long skip(final long n) throws IOException {
initWrapper();
return wrapperStream.skip(n);
return initWrapper().skip(n);
}
@Override
@ -83,19 +83,29 @@ class LazyDecompressingInputStream extends InputStream {
@Override
public int available() throws IOException {
initWrapper();
return wrapperStream.available();
return initWrapper().available();
}
@Override
public void close() throws IOException {
try {
if (wrapperStream != null) {
wrapperStream.close();
}
Closer.close(wrapperStream);
} 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);
}
@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
void testWriteToStream() throws Exception {
final CRC32 crc32 = new CRC32();
@ -101,3 +117,4 @@ class TestDecompressingEntity {
}
}