ninio-http/src/main/java/com/davfx/ninio/http/ChunkedReader.java
@Override
	public void received(ByteBuffer buffer) {
		if (ended) {
			throw new IllegalStateException();
		}
		while (true) {
			
			while (!chunkHeaderRead) {
				String line = lineReader.handle(buffer);
				if (line == null) {
					return;
				}
				try {
					chunkLength = Integer.parseInt(line, 16);
				} catch (NumberFormatException e) {
					ended = true;
					failing.failed(new IOException("Invalid chunk size: " + line));
					return;
				}
				chunkHeaderRead = true;
				chunkCountRead = 0;
			}

			if (chunkHeaderRead) {
				if (chunkCountRead < chunkLength) {
					if (!buffer.hasRemaining()) {
						return;
					}

					long toRead = chunkLength - chunkCountRead;
					
			    	ByteBuffer d = buffer.duplicate();
			    	if (toRead >= 0) {
						if (d.remaining() > toRead) {
							d.limit((int) (buffer.position() + toRead));
						}
			    	}
			    	
			    	chunkCountRead += d.remaining();
					buffer.position((int) (buffer.position() + d.remaining()));

					wrappee.received(d);
				}
					
				if (chunkCountRead == chunkLength) {
					while (chunkHeaderRead) {
						String line = lineReader.handle(buffer);
						if (line == null) {
							return;
						}
						if (!line.isEmpty()) {
							ended = true;
							failing.failed(new IOException("Invalid chunk footer"));
							return;
						}
						chunkHeaderRead = false;
					}

					if (chunkLength == 0) {
						ended = true;
						wrappee.ended();
						return;
					}
				}
			}
		
		}
	}
@Override
	public void received(ByteBuffer buffer) {
		if (ended) {
			throw new IllegalStateException();
		}
		while (true) {
			
			while (!chunkHeaderRead) {
				String line = lineReader.handle(buffer);
				if (line == null) {
					return;
				}
				try {
					chunkLength = Integer.parseInt(line, 16);
				} catch (NumberFormatException e) {
					ended = true;
					failing.failed(new IOException("Invalid chunk size: " + line));
					return;
				}
				chunkHeaderRead = true;
				chunkCountRead = 0;
			}

			if (chunkHeaderRead) {
				if (chunkCountRead < chunkLength) {
					if (!buffer.hasRemaining()) {
						return;
					}

					long toRead = chunkLength - chunkCountRead;
					
			    	ByteBuffer d = buffer.duplicate();
			    	if (toRead >= 0) {
						if (d.remaining() > toRead) {
							d.limit((int) (buffer.position() + toRead));
						}
			    	}
			    	
			    	chunkCountRead += d.remaining();
					buffer.position((int) (buffer.position() + d.remaining()));

					wrappee.received(d);
				}
					
				if (chunkCountRead == chunkLength) {
					while (chunkHeaderRead) {
						String line = lineReader.handle(buffer);
						if (line == null) {
							return;
						}
						if (!line.isEmpty()) {
							ended = true;
							failing.failed(new IOException("Invalid chunk footer"));
							return;
						}
						chunkHeaderRead = false;
					}

					if (chunkLength == 0) {
						ended = true;
						wrappee.ended();
						return;
					}
				}
			}
		
		}
	}
MUST sync-ly consume buffer