ninio-http/src/main/java/com/davfx/ninio/http/GzipReader.java
@Override
	public void received(ByteBuffer deflated) {
		if (ended) {
			throw new IllegalStateException();
		}

		if (deflated.remaining() >= FOOTER_LENGTH) {
			for (ByteBuffer b : previewFooter) {
				if (!read(b)) {
					return;
				}
			}
			previewFooter.clear();
			currentPreviewFooterLength = 0;
			
			ByteBuffer deflatedKeepingFooter = deflated.duplicate();
			deflatedKeepingFooter.limit(deflatedKeepingFooter.limit() - FOOTER_LENGTH);
			deflated.position(deflated.position() + deflatedKeepingFooter.remaining());
			if (!read(deflatedKeepingFooter)) {
				return;
			}

			currentPreviewFooterLength += deflated.remaining();
			previewFooter.addLast(deflated.duplicate());
			deflated.position(deflated.position() + deflated.remaining());
			return;
		} else {
			currentPreviewFooterLength += deflated.remaining();
			previewFooter.addLast(deflated.duplicate());
			deflated.position(deflated.position() + deflated.remaining());

			int toFlush = FOOTER_LENGTH - currentPreviewFooterLength;
			while (toFlush > 0) {
				ByteBuffer b = previewFooter.getFirst();

				ByteBuffer d = b.duplicate();
				d.limit(Math.min(d.limit(), toFlush));
				b.position(b.position() + d.remaining());
				toFlush -= d.remaining();
				if (!read(d)) {
					return;
				}
				if (!b.hasRemaining()) {
					previewFooter.removeFirst();
				}
			}
		}
	}
@Override
	public void received(ByteBuffer deflated) {
		if (ended) {
			throw new IllegalStateException();
		}

		if (deflated.remaining() >= FOOTER_LENGTH) {
			for (ByteBuffer b : previewFooter) {
				if (!read(b)) {
					return;
				}
			}
			previewFooter.clear();
			currentPreviewFooterLength = 0;
			
			ByteBuffer deflatedKeepingFooter = deflated.duplicate();
			deflatedKeepingFooter.limit(deflatedKeepingFooter.limit() - FOOTER_LENGTH);
			deflated.position(deflated.position() + deflatedKeepingFooter.remaining());
			if (!read(deflatedKeepingFooter)) {
				return;
			}

			currentPreviewFooterLength += deflated.remaining();
			previewFooter.addLast(deflated.duplicate());
			deflated.position(deflated.position() + deflated.remaining());
			return;
		} else {
			currentPreviewFooterLength += deflated.remaining();
			previewFooter.addLast(deflated.duplicate());
			deflated.position(deflated.position() + deflated.remaining());

			int toFlush = FOOTER_LENGTH - currentPreviewFooterLength;
			while (toFlush > 0) {
				ByteBuffer b = previewFooter.getFirst();

				ByteBuffer d = b.duplicate();
				d.limit(Math.min(d.limit(), toFlush));
				b.position(b.position() + d.remaining());
				toFlush -= d.remaining();
				if (!read(d)) {
					return;
				}
				if (!b.hasRemaining()) {
					previewFooter.removeFirst();
				}
			}
		}
	}
MUST sync-ly consume buffer