From cc85f0520caf5ab5759cca94f40de9f763231c81 Mon Sep 17 00:00:00 2001 From: Alex Osborne Date: Tue, 20 May 2025 15:52:02 +0900 Subject: [PATCH] Add RecordingInputStream.asOutputStream() Using RecordingInputStream requires an awkward workaround when the API being recorded is not in the form of an InputStream, for example, if it's asynchronous. This adds a method to access the underlying RecordingOutputStream so you can write to it directly when that would be easier. --- CHANGES.md | 4 ++++ .../java/org/archive/io/RecordingInputStream.java | 13 +++++++++++-- .../org/archive/io/RecordingInputStreamTest.java | 13 ++++++++++++- 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/CHANGES.md b/CHANGES.md index 19c26b2f..6d9c5880 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,10 @@ 2.0.0 ----- +### New features + +- Added `RecordingInputStream.asOutputStream()` for direct writing of recorded data without an input stream. [#108](https://github.com/iipc/webarchive-commons/pull/108) + ### Removals #### Removed Apache HttpClient 3.1 diff --git a/src/main/java/org/archive/io/RecordingInputStream.java b/src/main/java/org/archive/io/RecordingInputStream.java index 95419280..3c9db61f 100644 --- a/src/main/java/org/archive/io/RecordingInputStream.java +++ b/src/main/java/org/archive/io/RecordingInputStream.java @@ -383,12 +383,12 @@ public synchronized void mark(int readlimit) { @Override public boolean markSupported() { - return this.in.markSupported(); + return in != null && this.in.markSupported(); } @Override public synchronized void reset() throws IOException { - this.in.reset(); + if (in != null) this.in.reset(); this.recordingOutputStream.reset(); } @@ -418,4 +418,13 @@ public void chopAtMessageBodyBegin() { public void clearForReuse() throws IOException { recordingOutputStream.clearForReuse(); } + + /** + * Returns an OutputStream that can be used for recording input data. This is useful if the input comes in some + * form other than an InputStream. For example, if the input is provided by a callback periodically called with + * a chunk of data. + */ + public RecordingOutputStream asOutputStream() { + return this.recordingOutputStream; + } } diff --git a/src/test/java/org/archive/io/RecordingInputStreamTest.java b/src/test/java/org/archive/io/RecordingInputStreamTest.java index 9ddc7457..49160aa3 100644 --- a/src/test/java/org/archive/io/RecordingInputStreamTest.java +++ b/src/test/java/org/archive/io/RecordingInputStreamTest.java @@ -41,7 +41,6 @@ public class RecordingInputStreamTest { @TempDir File tempDir; - /** * Test readFullyOrUntil soft (no exception) and hard (exception) * length cutoffs, timeout, and rate-throttling. @@ -128,4 +127,16 @@ public void run() { }.start(); } + + @Test + public void testAsOutputStream() throws IOException { + RecordingInputStream ris = new RecordingInputStream(16384, (new File( + tempDir, "testAsOutputStream").getAbsolutePath())); + ris.open(null); + ris.asOutputStream().write("hello".getBytes()); + ris.close(); + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ris.getReplayInputStream().readFullyTo(baos); + assertEquals("hello", baos.toString()); + } }