/** * Finishes writing to the underlying stream, but does NOT close the underlying stream. */ @Override public void close() throws IOException { if (!this.closed) { this.closed = true; finish(); this.buffer.flush(this.outputStream); } } }
/** * Writes the array. If the array does not fit within the buffer, it is * not split, but rather written out as one large chunk. */ @Override public void write(final byte[] b) throws IOException { write(b, 0, b.length); }
/** * Must be called to ensure the internal cache is flushed and the closing * chunk is written. * @throws IOException in case of an I/O error */ public void finish() throws IOException { if (!this.wroteLastChunk) { flushCache(); writeClosingChunk(); this.wroteLastChunk = true; } }
@Test public void testChunkedOutputStream() throws IOException { final SessionOutputBuffer outbuffer = new SessionOutputBufferImpl(16); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); final ChunkedOutputStream out = new ChunkedOutputStream(outbuffer, outputStream, 2); out.write('1'); out.write('2'); out.write('3'); out.write('4'); out.finish(); out.close(); final String content = new String(outputStream.toByteArray(), StandardCharsets.US_ASCII); Assert.assertEquals("2\r\n12\r\n2\r\n34\r\n0\r\n\r\n", content); }
@Test public void testChunkedConsistence() throws IOException { final String input = "76126;27823abcd;:q38a-\nkjc\rk%1ad\tkh/asdui\r\njkh+?\\suweb"; final SessionOutputBuffer outbuffer = new SessionOutputBufferImpl(16); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); final ChunkedOutputStream out = new ChunkedOutputStream(outbuffer, outputStream, 2048); out.write(input.getBytes(StandardCharsets.ISO_8859_1)); out.flush(); out.close(); out.close(); final SessionInputBuffer inBuffer = new SessionInputBufferImpl(16); final ByteArrayInputStream inputStream = new ByteArrayInputStream(outputStream.toByteArray()); final ChunkedInputStream in = new ChunkedInputStream(inBuffer, inputStream); final byte[] d = new byte[10]; final ByteArrayOutputStream result = new ByteArrayOutputStream(); int len = 0; while ((len = in.read(d)) > 0) { result.write(d, 0, len); } final String output = new String(result.toByteArray(), StandardCharsets.ISO_8859_1); Assert.assertEquals(input, output); in.close(); }
@Test public void testChunkedOutputStreamClose() throws IOException { final SessionOutputBuffer outbuffer = new SessionOutputBufferImpl(16); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); final ChunkedOutputStream out = new ChunkedOutputStream(outbuffer, outputStream, 2048); out.close(); out.close(); try { out.write(new byte[] {1,2,3}); Assert.fail("IOException should have been thrown"); } catch (final IOException ex) { // expected } try { out.write(1); Assert.fail("IOException should have been thrown"); } catch (final IOException ex) { // expected } }
protected OutputStream createContentOutputStream( final long len, final SessionOutputBuffer buffer, final OutputStream outputStream, final Supplier<List<? extends Header>> trailers) { if (len >= 0) { return new ContentLengthOutputStream(buffer, outputStream, len); } else if (len == ContentLengthStrategy.CHUNKED) { final int chunkSizeHint = h1Config.getChunkSizeHint() >= 0 ? h1Config.getChunkSizeHint() : 2048; return new ChunkedOutputStream(buffer, outputStream, chunkSizeHint, trailers); } else { return new IdentityOutputStream(buffer, outputStream); } }
@Override public void write(final int b) throws IOException { if (this.closed) { throw new StreamClosedException(); } this.cache[this.cachePosition] = (byte) b; this.cachePosition++; if (this.cachePosition == this.cache.length) { flushCache(); } }
private void writeClosingChunk() throws IOException { // Write the final chunk. this.lineBuffer.clear(); this.lineBuffer.append('0'); this.buffer.writeLine(this.lineBuffer, this.outputStream); writeTrailers(); this.lineBuffer.clear(); this.buffer.writeLine(this.lineBuffer, this.outputStream); }
/** * Writes the array. If the array does not fit within the buffer, it is * not split, but rather written out as one large chunk. */ @Override public void write(final byte[] src, final int off, final int len) throws IOException { if (this.closed) { throw new StreamClosedException(); } if (len >= this.cache.length - this.cachePosition) { flushCacheWithAppend(src, off, len); } else { System.arraycopy(src, off, cache, this.cachePosition, len); this.cachePosition += len; } }
@Test public void testChunkedOutputStreamSmallChunk() throws IOException { final SessionOutputBuffer outbuffer = new SessionOutputBufferImpl(16); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); final ChunkedOutputStream out = new ChunkedOutputStream(outbuffer, outputStream, 2); out.write('1'); out.finish(); out.close(); final String content = new String(outputStream.toByteArray(), StandardCharsets.US_ASCII); Assert.assertEquals("1\r\n1\r\n0\r\n\r\n", content); }
protected OutputStream createContentOutputStream( final long len, final SessionOutputBuffer buffer, final OutputStream outputStream, final Supplier<List<? extends Header>> trailers) { if (len >= 0) { return new ContentLengthOutputStream(buffer, outputStream, len); } else if (len == ContentLengthStrategy.CHUNKED) { final int chunkSizeHint = h1Config.getChunkSizeHint() >= 0 ? h1Config.getChunkSizeHint() : 2048; return new ChunkedOutputStream(buffer, outputStream, chunkSizeHint, trailers); } else { return new IdentityOutputStream(buffer, outputStream); } }
/** * Flushes the content buffer and the underlying stream. */ @Override public void flush() throws IOException { flushCache(); this.buffer.flush(this.outputStream); }
private void writeClosingChunk() throws IOException { // Write the final chunk. this.lineBuffer.clear(); this.lineBuffer.append('0'); this.buffer.writeLine(this.lineBuffer, this.outputStream); writeTrailers(); this.lineBuffer.clear(); this.buffer.writeLine(this.lineBuffer, this.outputStream); }
/** * Writes the array. If the array does not fit within the buffer, it is * not split, but rather written out as one large chunk. */ @Override public void write(final byte[] src, final int off, final int len) throws IOException { if (this.closed) { throw new StreamClosedException(); } if (len >= this.cache.length - this.cachePosition) { flushCacheWithAppend(src, off, len); } else { System.arraycopy(src, off, cache, this.cachePosition, len); this.cachePosition += len; } }
@Test public void testChunkedOutputStreamLargeChunk() throws IOException { final SessionOutputBuffer outbuffer = new SessionOutputBufferImpl(16); final ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); final ChunkedOutputStream out = new ChunkedOutputStream(outbuffer, outputStream, 2); out.write(new byte[] {'1', '2', '3', '4'}); out.finish(); out.close(); final String content = new String(outputStream.toByteArray(), StandardCharsets.US_ASCII); Assert.assertEquals("4\r\n1234\r\n0\r\n\r\n", content); }
/** * Writes the array. If the array does not fit within the buffer, it is * not split, but rather written out as one large chunk. */ @Override public void write(final byte[] b) throws IOException { write(b, 0, b.length); }
/** * Finishes writing to the underlying stream, but does NOT close the underlying stream. */ @Override public void close() throws IOException { if (!this.closed) { this.closed = true; finish(); this.buffer.flush(this.outputStream); } } }
/** * Must be called to ensure the internal cache is flushed and the closing * chunk is written. * @throws IOException in case of an I/O error */ public void finish() throws IOException { if (!this.wroteLastChunk) { flushCache(); writeClosingChunk(); this.wroteLastChunk = true; } }
@Override public void write(final int b) throws IOException { if (this.closed) { throw new StreamClosedException(); } this.cache[this.cachePosition] = (byte) b; this.cachePosition++; if (this.cachePosition == this.cache.length) { flushCache(); } }