diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpOutputInterceptor.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpOutputInterceptor.java index fcf2ae6078b5..cc5a698d0f1e 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpOutputInterceptor.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/gzip/GzipHttpOutputInterceptor.java @@ -263,6 +263,7 @@ public boolean mightCompress() private class GzipBufferCB extends IteratingNestedCallback { + private ByteBuffer _copy; private final ByteBuffer _content; private final boolean _last; @@ -271,10 +272,6 @@ public GzipBufferCB(ByteBuffer content, boolean complete, Callback callback) super(callback); _content = content; _last = complete; - _crc.update(_content.slice()); - _deflater.setInput(_content); - if (_last) - _deflater.finish(); } @Override @@ -299,6 +296,11 @@ protected Action process() throws Exception _channel.getByteBufferPool().release(_buffer); _buffer = null; } + if (_copy != null) + { + _channel.getByteBufferPool().release(_copy); + _copy = null; + } return Action.SUCCEEDED; } @@ -318,13 +320,52 @@ protected Action process() throws Exception // If the deflator is not finished, then compress more data if (!_deflater.finished()) { - if (_deflater.needsInput() && !_last) - return Action.SUCCEEDED; + if (_deflater.needsInput()) + { + // if there is no more content available to compress + // then we are either finished all content or just the current write. + if (BufferUtil.isEmpty(_content)) + { + if (_last) + _deflater.finish(); + else + return Action.SUCCEEDED; + } + else + { + // If there is more content available to compress, we have to make sure + // it is available in an array for the current deflator API, maybe slicing + // of content. + ByteBuffer slice; + if (_content.hasArray()) + slice = _content; + else + { + if (_copy == null) + _copy = _channel.getByteBufferPool().acquire(_bufferSize, false); + else + BufferUtil.clear(_copy); + slice = _copy; + BufferUtil.append(_copy, _content); + } + + // transfer the data from the slice to the the deflator + byte[] array = slice.array(); + int off = slice.arrayOffset() + slice.position(); + int len = slice.remaining(); + _crc.update(array, off, len); + _deflater.setInput(array, off, len); + slice.position(slice.position() + len); + if (_last && BufferUtil.isEmpty(_content)) + _deflater.finish(); + } + } // deflate the content into the available space in the buffer - int pos = BufferUtil.flipToFill(_buffer); - _deflater.deflate(_buffer, _syncFlush ? Deflater.SYNC_FLUSH : Deflater.NO_FLUSH); - BufferUtil.flipToFlush(_buffer, pos); + int off = _buffer.arrayOffset() + _buffer.limit(); + int len = BufferUtil.space(_buffer); + int produced = _deflater.deflate(_buffer.array(), off, len, _syncFlush ? Deflater.SYNC_FLUSH : Deflater.NO_FLUSH); + _buffer.limit(_buffer.limit() + produced); } // If we have finished deflation and there is room for the trailer. @@ -345,10 +386,11 @@ protected Action process() throws Exception @Override public String toString() { - return String.format("%s[content=%s last=%b buffer=%s deflate=%s %s]", + return String.format("%s[content=%s last=%b copy=%s buffer=%s deflate=%s %s]", super.toString(), BufferUtil.toDetailString(_content), _last, + BufferUtil.toDetailString(_copy), BufferUtil.toDetailString(_buffer), _deflater, _deflater != null && _deflater.finished() ? "(finished)" : "");