LengthDelimitedDecoder extends AbstractContentDecoder implements FileContentDecoder { @Override public int read(final ByteBuffer dst) throws IOException { Args.notNull(dst, "Byte buffer"); if (isCompleted()) { return -1; } final int chunk = (int) Math.min((this.contentLength - this.len), Integer.MAX_VALUE); final int bytesRead; if (this.buffer.hasData()) { final int maxLen = Math.min(chunk, this.buffer.length()); bytesRead = this.buffer.read(dst, maxLen); } else { bytesRead = readFromChannel(dst, chunk); } if (bytesRead == -1) { setCompleted(); if (this.len < this.contentLength) { throw new ConnectionClosedException( "Premature end of Content-Length delimited message body (expected: %d; received: %d)", this.contentLength, this.len); } } this.len += bytesRead; if (this.len >= this.contentLength) { this.completed = true; } if (this.completed && bytesRead == 0) { return -1; } return bytesRead; } LengthDelimitedDecoder(
            final ReadableByteChannel channel,
            final SessionInputBuffer buffer,
            final BasicHttpTransportMetrics metrics,
            final long contentLength); @Override int read(final ByteBuffer dst); @Override long transfer(
            final FileChannel dst,
            final long position,
            final long count); @Override String toString();  }
@Test public void testCodingBeyondContentLimit() throws Exception { final ReadableByteChannel channel = new ReadableByteChannelMock( new String[] { "stuff;", "more stuff; and a lot more stuff"}, StandardCharsets.US_ASCII); final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII); final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics(); final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder( channel, inbuf, metrics, 16); final ByteBuffer dst = ByteBuffer.allocate(1024); int bytesRead = decoder.read(dst); Assert.assertEquals(6, bytesRead); Assert.assertEquals("stuff;", CodecTestUtils.convert(dst)); Assert.assertFalse(decoder.isCompleted()); Assert.assertEquals(6, metrics.getBytesTransferred()); dst.clear(); bytesRead = decoder.read(dst); Assert.assertEquals(10, bytesRead); Assert.assertEquals("more stuff", CodecTestUtils.convert(dst)); Assert.assertTrue(decoder.isCompleted()); Assert.assertEquals(16, metrics.getBytesTransferred()); dst.clear(); bytesRead = decoder.read(dst); Assert.assertEquals(-1, bytesRead); Assert.assertTrue(decoder.isCompleted()); Assert.assertEquals(16, metrics.getBytesTransferred()); }
@Test public void testBasicDecodingSmallBuffer() throws Exception { final ReadableByteChannel channel = new ReadableByteChannelMock( new String[] {"stuff;", "more stuff"}, StandardCharsets.US_ASCII); final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII); final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics(); final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder( channel, inbuf, metrics, 16); final ByteBuffer dst = ByteBuffer.allocate(4); int bytesRead = decoder.read(dst); Assert.assertEquals(4, bytesRead); Assert.assertEquals("stuf", CodecTestUtils.convert(dst)); Assert.assertFalse(decoder.isCompleted()); Assert.assertEquals(4, metrics.getBytesTransferred()); dst.clear(); bytesRead = decoder.read(dst); Assert.assertEquals(2, bytesRead); Assert.assertEquals("f;", CodecTestUtils.convert(dst)); Assert.assertFalse(decoder.isCompleted()); Assert.assertEquals(6, metrics.getBytesTransferred()); dst.clear(); bytesRead = decoder.read(dst); Assert.assertEquals(4, bytesRead); Assert.assertEquals("more", CodecTestUtils.convert(dst)); Assert.assertFalse(decoder.isCompleted()); Assert.assertEquals(10, metrics.getBytesTransferred()); dst.clear(); bytesRead = decoder.read(dst); Assert.assertEquals(4, bytesRead); Assert.assertEquals(" stu", CodecTestUtils.convert(dst)); Assert.assertFalse(decoder.isCompleted()); Assert.assertEquals(14, metrics.getBytesTransferred()); dst.clear(); bytesRead = decoder.read(dst); Assert.assertEquals(2, bytesRead); Assert.assertEquals("ff", CodecTestUtils.convert(dst)); Assert.assertTrue(decoder.isCompleted()); Assert.assertEquals(16, metrics.getBytesTransferred()); dst.clear(); bytesRead = decoder.read(dst); Assert.assertEquals(-1, bytesRead); Assert.assertTrue(decoder.isCompleted()); Assert.assertEquals(16, metrics.getBytesTransferred()); }
@Test public void testDecodingFromSessionBuffer1() throws Exception { final ReadableByteChannel channel = new ReadableByteChannelMock( new String[] {"stuff;", "more stuff"}, StandardCharsets.US_ASCII); final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII); final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics(); inbuf.fill(channel); Assert.assertEquals(6, inbuf.length()); final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder( channel, inbuf, metrics, 16); final ByteBuffer dst = ByteBuffer.allocate(1024); int bytesRead = decoder.read(dst); Assert.assertEquals(6, bytesRead); Assert.assertEquals("stuff;", CodecTestUtils.convert(dst)); Assert.assertFalse(decoder.isCompleted()); Assert.assertEquals(0, metrics.getBytesTransferred()); dst.clear(); bytesRead = decoder.read(dst); Assert.assertEquals(10, bytesRead); Assert.assertEquals("more stuff", CodecTestUtils.convert(dst)); Assert.assertTrue(decoder.isCompleted()); Assert.assertEquals(10, metrics.getBytesTransferred()); dst.clear(); bytesRead = decoder.read(dst); Assert.assertEquals(-1, bytesRead); Assert.assertTrue(decoder.isCompleted()); Assert.assertEquals(10, metrics.getBytesTransferred()); }
@Test public void testDecodingFromSessionBuffer2() throws Exception { final ReadableByteChannel channel = new ReadableByteChannelMock( new String[] { "stuff;", "more stuff; and a lot more stuff"}, StandardCharsets.US_ASCII); final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII); final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics(); inbuf.fill(channel); inbuf.fill(channel); Assert.assertEquals(38, inbuf.length()); final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder( channel, inbuf, metrics, 16); final ByteBuffer dst = ByteBuffer.allocate(1024); int bytesRead = decoder.read(dst); Assert.assertEquals(16, bytesRead); Assert.assertEquals("stuff;more stuff", CodecTestUtils.convert(dst)); Assert.assertTrue(decoder.isCompleted()); Assert.assertEquals(0, metrics.getBytesTransferred()); dst.clear(); bytesRead = decoder.read(dst); Assert.assertEquals(-1, bytesRead); Assert.assertTrue(decoder.isCompleted()); Assert.assertEquals(0, metrics.getBytesTransferred()); }
@Test public void testInvalidInput() throws Exception { final String s = "stuff"; final ReadableByteChannel channel = new ReadableByteChannelMock( new String[] {s}, StandardCharsets.US_ASCII); final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII); final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics(); final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder( channel, inbuf, metrics, 3); try { decoder.read(null); Assert.fail("NullPointerException should have been thrown"); } catch (final NullPointerException ex) { } }
@Test public void testZeroLengthDecoding() throws Exception { final ReadableByteChannel channel = new ReadableByteChannelMock( new String[] {"stuff"}, StandardCharsets.US_ASCII); final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII); final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics(); final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder( channel, inbuf, metrics, 0); final ByteBuffer dst = ByteBuffer.allocate(1024); final int bytesRead = decoder.read(dst); Assert.assertEquals(-1, bytesRead); Assert.assertTrue(decoder.isCompleted()); Assert.assertEquals(0, metrics.getBytesTransferred()); }
@Test(expected=ConnectionClosedException.class) public void testTruncatedContent() throws Exception { final ReadableByteChannel channel = new ReadableByteChannelMock( new String[] {"1234567890"}, StandardCharsets.US_ASCII); final SessionInputBuffer inbuf = new SessionInputBufferImpl(1024, 256, 0, StandardCharsets.US_ASCII); final BasicHttpTransportMetrics metrics = new BasicHttpTransportMetrics(); final LengthDelimitedDecoder decoder = new LengthDelimitedDecoder( channel, inbuf, metrics, 20); final ByteBuffer dst = ByteBuffer.allocate(1024); final int bytesRead = decoder.read(dst); Assert.assertEquals(10, bytesRead); decoder.read(dst); }