@Test(expected=MalformedChunkCodingException.class) public void testMalformedChunkSizeDecoding() throws Exception { final String s = "5\r\n01234\r\n5zz\r\n56789\r\n6\r\nabcdef\r\n0\r\n\r\n"; 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 ChunkDecoder decoder = new ChunkDecoder(channel, inbuf, metrics); final ByteBuffer dst = ByteBuffer.allocate(1024); decoder.read(dst); }
@Override public int read(final ByteBuffer dst) throws IOException { Args.notNull(dst, "Byte buffer"); if (this.state == State.COMPLETED) { return -1; } int totalRead = 0; while (this.state != State.COMPLETED) { if (!this.buffer.hasData() || this.chunkSize == -1L) { final int bytesRead = fillBufferFromChannel(); if (bytesRead == -1) { this.endOfStream = true; } } switch (this.state) { case READ_CONTENT: if (this.chunkSize == -1L) { readChunkHead(); if (this.chunkSize == -1L) { return totalRead; } if (this.chunkSize == 0L) { this.chunkSize = -1L; this.state = State.READ_FOOTERS; break; } } final long maxLen = this.chunkSize - this.pos; final int len = this.buffer.read(dst, (int) Math.min(maxLen, Integer.MAX_VALUE)); if (len > 0) { this.pos += len; totalRead += len; } else { if (!this.buffer.hasData() && this.endOfStream) { this.state = State.COMPLETED; setCompleted(); throw new TruncatedChunkException( "Truncated chunk (expected size: %d; actual size: %d)", chunkSize, pos); } } if (this.pos == this.chunkSize) { this.chunkSize = -1L; this.pos = 0L; this.endOfChunk = true; break; } return totalRead; case READ_FOOTERS: if (this.lineBuf == null) { this.lineBuf = new CharArrayBuffer(32); } else { this.lineBuf.clear(); } if (!this.buffer.readLine(this.lineBuf, this.endOfStream)) { if (this.endOfStream) { this.state = State.COMPLETED; setCompleted(); } return totalRead; } if (this.lineBuf.length() > 0) { final int maxHeaderCount = this.http1Config.getMaxHeaderCount(); if (maxHeaderCount > 0 && trailerBufs.size() >= maxHeaderCount) { throw new MessageConstraintException("Maximum header count exceeded"); } parseHeader(); } else { this.state = State.COMPLETED; setCompleted(); processFooters(); } break; } } return totalRead; }
ChunkDecoder extends AbstractContentDecoder { @Override public int read(final ByteBuffer dst) throws IOException { Args.notNull(dst, "Byte buffer"); if (this.state == State.COMPLETED) { return -1; } int totalRead = 0; while (this.state != State.COMPLETED) { if (!this.buffer.hasData() || this.chunkSize == -1L) { final int bytesRead = fillBufferFromChannel(); if (bytesRead == -1) { this.endOfStream = true; } } switch (this.state) { case READ_CONTENT: if (this.chunkSize == -1L) { readChunkHead(); if (this.chunkSize == -1L) { return totalRead; } if (this.chunkSize == 0L) { this.chunkSize = -1L; this.state = State.READ_FOOTERS; break; } } final long maxLen = this.chunkSize - this.pos; final int len = this.buffer.read(dst, (int) Math.min(maxLen, Integer.MAX_VALUE)); if (len > 0) { this.pos += len; totalRead += len; } else { if (!this.buffer.hasData() && this.endOfStream) { this.state = State.COMPLETED; setCompleted(); throw new TruncatedChunkException( "Truncated chunk (expected size: %d; actual size: %d)", chunkSize, pos); } } if (this.pos == this.chunkSize) { this.chunkSize = -1L; this.pos = 0L; this.endOfChunk = true; break; } return totalRead; case READ_FOOTERS: if (this.lineBuf == null) { this.lineBuf = new CharArrayBuffer(32); } else { this.lineBuf.clear(); } if (!this.buffer.readLine(this.lineBuf, this.endOfStream)) { if (this.endOfStream) { this.state = State.COMPLETED; setCompleted(); } return totalRead; } if (this.lineBuf.length() > 0) { final int maxHeaderCount = this.http1Config.getMaxHeaderCount(); if (maxHeaderCount > 0 && trailerBufs.size() >= maxHeaderCount) { throw new MessageConstraintException("Maximum header count exceeded"); } parseHeader(); } else { this.state = State.COMPLETED; setCompleted(); processFooters(); } break; } } return totalRead; } }
ChunkDecoder extends AbstractContentDecoder { @Override public int read(final ByteBuffer dst) throws IOException { Args.notNull(dst, "Byte buffer"); if (this.state == State.COMPLETED) { return -1; } int totalRead = 0; while (this.state != State.COMPLETED) { if (!this.buffer.hasData() || this.chunkSize == -1L) { final int bytesRead = fillBufferFromChannel(); if (bytesRead == -1) { this.endOfStream = true; } } switch (this.state) { case READ_CONTENT: if (this.chunkSize == -1L) { readChunkHead(); if (this.chunkSize == -1L) { return totalRead; } if (this.chunkSize == 0L) { this.chunkSize = -1L; this.state = State.READ_FOOTERS; break; } } final long maxLen = this.chunkSize - this.pos; final int len = this.buffer.read(dst, (int) Math.min(maxLen, Integer.MAX_VALUE)); if (len > 0) { this.pos += len; totalRead += len; } else { if (!this.buffer.hasData() && this.endOfStream) { this.state = State.COMPLETED; setCompleted(); throw new TruncatedChunkException( "Truncated chunk (expected size: %d; actual size: %d)", chunkSize, pos); } } if (this.pos == this.chunkSize) { this.chunkSize = -1L; this.pos = 0L; this.endOfChunk = true; break; } return totalRead; case READ_FOOTERS: if (this.lineBuf == null) { this.lineBuf = new CharArrayBuffer(32); } else { this.lineBuf.clear(); } if (!this.buffer.readLine(this.lineBuf, this.endOfStream)) { if (this.endOfStream) { this.state = State.COMPLETED; setCompleted(); } return totalRead; } if (this.lineBuf.length() > 0) { final int maxHeaderCount = this.http1Config.getMaxHeaderCount(); if (maxHeaderCount > 0 && trailerBufs.size() >= maxHeaderCount) { throw new MessageConstraintException("Maximum header count exceeded"); } parseHeader(); } else { this.state = State.COMPLETED; setCompleted(); processFooters(); } break; } } return totalRead; } ChunkDecoder(
            final ReadableByteChannel channel,
            final SessionInputBuffer buffer,
            final Http1Config http1Config,
            final BasicHttpTransportMetrics metrics);  ChunkDecoder(
            final ReadableByteChannel channel,
            final SessionInputBuffer buffer,
            final BasicHttpTransportMetrics metrics); }
ChunkDecoder extends AbstractContentDecoder { @Override public int read(final ByteBuffer dst) throws IOException { Args.notNull(dst, "Byte buffer"); if (this.state == State.COMPLETED) { return -1; } int totalRead = 0; while (this.state != State.COMPLETED) { if (!this.buffer.hasData() || this.chunkSize == -1L) { final int bytesRead = fillBufferFromChannel(); if (bytesRead == -1) { this.endOfStream = true; } } switch (this.state) { case READ_CONTENT: if (this.chunkSize == -1L) { readChunkHead(); if (this.chunkSize == -1L) { return totalRead; } if (this.chunkSize == 0L) { this.chunkSize = -1L; this.state = State.READ_FOOTERS; break; } } final long maxLen = this.chunkSize - this.pos; final int len = this.buffer.read(dst, (int) Math.min(maxLen, Integer.MAX_VALUE)); if (len > 0) { this.pos += len; totalRead += len; } else { if (!this.buffer.hasData() && this.endOfStream) { this.state = State.COMPLETED; setCompleted(); throw new TruncatedChunkException( "Truncated chunk (expected size: %d; actual size: %d)", chunkSize, pos); } } if (this.pos == this.chunkSize) { this.chunkSize = -1L; this.pos = 0L; this.endOfChunk = true; break; } return totalRead; case READ_FOOTERS: if (this.lineBuf == null) { this.lineBuf = new CharArrayBuffer(32); } else { this.lineBuf.clear(); } if (!this.buffer.readLine(this.lineBuf, this.endOfStream)) { if (this.endOfStream) { this.state = State.COMPLETED; setCompleted(); } return totalRead; } if (this.lineBuf.length() > 0) { final int maxHeaderCount = this.http1Config.getMaxHeaderCount(); if (maxHeaderCount > 0 && trailerBufs.size() >= maxHeaderCount) { throw new MessageConstraintException("Maximum header count exceeded"); } parseHeader(); } else { this.state = State.COMPLETED; setCompleted(); processFooters(); } break; } } return totalRead; } ChunkDecoder(
            final ReadableByteChannel channel,
            final SessionInputBuffer buffer,
            final Http1Config http1Config,
            final BasicHttpTransportMetrics metrics);  ChunkDecoder(
            final ReadableByteChannel channel,
            final SessionInputBuffer buffer,
            final BasicHttpTransportMetrics metrics); @Override int read(final ByteBuffer dst); @Override List<? extends Header> getTrailers(); @Override String toString(); }
ChunkDecoder extends AbstractContentDecoder { @Override public int read(final ByteBuffer dst) throws IOException { Args.notNull(dst, "Byte buffer"); if (this.state == State.COMPLETED) { return -1; } int totalRead = 0; while (this.state != State.COMPLETED) { if (!this.buffer.hasData() || this.chunkSize == -1L) { final int bytesRead = fillBufferFromChannel(); if (bytesRead == -1) { this.endOfStream = true; } } switch (this.state) { case READ_CONTENT: if (this.chunkSize == -1L) { readChunkHead(); if (this.chunkSize == -1L) { return totalRead; } if (this.chunkSize == 0L) { this.chunkSize = -1L; this.state = State.READ_FOOTERS; break; } } final long maxLen = this.chunkSize - this.pos; final int len = this.buffer.read(dst, (int) Math.min(maxLen, Integer.MAX_VALUE)); if (len > 0) { this.pos += len; totalRead += len; } else { if (!this.buffer.hasData() && this.endOfStream) { this.state = State.COMPLETED; setCompleted(); throw new TruncatedChunkException( "Truncated chunk (expected size: %d; actual size: %d)", chunkSize, pos); } } if (this.pos == this.chunkSize) { this.chunkSize = -1L; this.pos = 0L; this.endOfChunk = true; break; } return totalRead; case READ_FOOTERS: if (this.lineBuf == null) { this.lineBuf = new CharArrayBuffer(32); } else { this.lineBuf.clear(); } if (!this.buffer.readLine(this.lineBuf, this.endOfStream)) { if (this.endOfStream) { this.state = State.COMPLETED; setCompleted(); } return totalRead; } if (this.lineBuf.length() > 0) { final int maxHeaderCount = this.http1Config.getMaxHeaderCount(); if (maxHeaderCount > 0 && trailerBufs.size() >= maxHeaderCount) { throw new MessageConstraintException("Maximum header count exceeded"); } parseHeader(); } else { this.state = State.COMPLETED; setCompleted(); processFooters(); } break; } } return totalRead; } ChunkDecoder(
            final ReadableByteChannel channel,
            final SessionInputBuffer buffer,
            final Http1Config http1Config,
            final BasicHttpTransportMetrics metrics);  ChunkDecoder(
            final ReadableByteChannel channel,
            final SessionInputBuffer buffer,
            final BasicHttpTransportMetrics metrics); @Override int read(final ByteBuffer dst); @Override List<? extends Header> getTrailers(); @Override String toString();  }