From 2278d272353d6c18a40ee5439418d053342fe4a7 Mon Sep 17 00:00:00 2001 From: Thomas Becker Date: Fri, 30 Mar 2012 11:02:44 +0200 Subject: [PATCH 1/5] 375692: GzipFilter support for deflate Change-Id: I4a42d750cfbbb61078adafa1e2bcbc1973198dca --- ...=> AbstractCompressedResponseWrapper.java} | 381 +++++++++--------- .../http/gzip/AbstractCompressedStream.java | 343 ++++++++++++++++ .../http/gzip/CompressedResponseWrapper.java | 58 +++ .../jetty/http/gzip/CompressedStream.java | 77 ++++ .../jetty/http/gzip/CompressionType.java | 48 +++ .../http/gzip/DeflateResponseWrapperImpl.java | 54 +++ .../jetty/http/gzip/DeflateStreamImpl.java | 55 +++ .../http/gzip/GzipResponseWrapperImpl.java | 53 +++ .../eclipse/jetty/http/gzip/GzipStream.java | 305 -------------- .../jetty/http/gzip/GzipStreamImpl.java | 56 +++ .../jetty/server/handler/GzipHandler.java | 12 +- .../eclipse/jetty/servlets/GzipFilter.java | 134 +++--- .../jetty/servlets/IncludableGzipFilter.java | 87 ++-- .../servlets/GzipFilterContentLengthTest.java | 47 ++- .../GzipFilterDefaultNoRecompressTest.java | 54 ++- .../jetty/servlets/GzipFilterDefaultTest.java | 47 ++- .../servlets/GzipWithPipeliningTest.java | 71 +++- .../IncludableGzipFilterMinSizeTest.java | 30 +- .../servlets/IncludableGzipFilterTest.java | 49 ++- .../jetty/servlets/PipelineHelper.java | 10 +- .../jetty/servlets/gzip/GzipTester.java | 42 +- 21 files changed, 1332 insertions(+), 681 deletions(-) rename jetty-http/src/main/java/org/eclipse/jetty/http/gzip/{GzipResponseWrapper.java => AbstractCompressedResponseWrapper.java} (62%) create mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/gzip/AbstractCompressedStream.java create mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/gzip/CompressedResponseWrapper.java create mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/gzip/CompressedStream.java create mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/gzip/CompressionType.java create mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/gzip/DeflateResponseWrapperImpl.java create mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/gzip/DeflateStreamImpl.java create mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipResponseWrapperImpl.java delete mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipStream.java create mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipStreamImpl.java diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipResponseWrapper.java b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/AbstractCompressedResponseWrapper.java similarity index 62% rename from jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipResponseWrapper.java rename to jetty-http/src/main/java/org/eclipse/jetty/http/gzip/AbstractCompressedResponseWrapper.java index 093e127d902..95c69109e99 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipResponseWrapper.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/AbstractCompressedResponseWrapper.java @@ -1,5 +1,5 @@ // ======================================================================== -// Copyright (c) Webtide LLC +// Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd. // ------------------------------------------------------------------------ // All rights reserved. This program and the accompanying materials // are made available under the terms of the Eclipse Public License v1.0 @@ -11,7 +11,6 @@ // You may elect to redistribute this code under either of these licenses. // ======================================================================== - package org.eclipse.jetty.http.gzip; import java.io.IOException; @@ -28,42 +27,36 @@ import javax.servlet.http.HttpServletResponseWrapper; import org.eclipse.jetty.util.StringUtil; - -/* ------------------------------------------------------------ */ +/*------------------------------------------------------------ */ /** + * Skeletal implementation of the CompressedResponseWrapper interface. + * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper */ -public class GzipResponseWrapper extends HttpServletResponseWrapper +public abstract class AbstractCompressedResponseWrapper extends HttpServletResponseWrapper implements CompressedResponseWrapper { - public static final int DEFAULT_BUFFER_SIZE = 8192; - public static final int DEFAULT_MIN_GZIP_SIZE = 256; - private HttpServletRequest _request; + public static final int DEFAULT_BUFFER_SIZE = 8192; + public static final int DEFAULT_MIN_COMPRESS_SIZE = 256; + private Set _mimeTypes; private int _bufferSize=DEFAULT_BUFFER_SIZE; - private int _minGzipSize=DEFAULT_MIN_GZIP_SIZE; + private int _minCompressSize=DEFAULT_MIN_COMPRESS_SIZE; + private HttpServletRequest _request; private PrintWriter _writer; - private GzipStream _gzStream; + private CompressedStream _compressedStream; private long _contentLength=-1; - private boolean _noGzip; + private boolean _noCompression; - /** - * Instantiates a new gzip response wrapper. - * - * @param request the request - * @param response the response - */ - public GzipResponseWrapper(HttpServletRequest request, HttpServletResponse response) + public AbstractCompressedResponseWrapper(HttpServletRequest request, HttpServletResponse response) { super(response); - _request=request; + _request = request; } /* ------------------------------------------------------------ */ /** - * Sets the mime types. - * - * @param mimeTypes the new mime types + * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setMimeTypes(java.util.Set) */ public void setMimeTypes(Set mimeTypes) { @@ -72,8 +65,9 @@ public class GzipResponseWrapper extends HttpServletResponseWrapper /* ------------------------------------------------------------ */ /** - * @see javax.servlet.ServletResponseWrapper#setBufferSize(int) + * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setBufferSize(int) */ + @Override public void setBufferSize(int bufferSize) { _bufferSize = bufferSize; @@ -81,76 +75,77 @@ public class GzipResponseWrapper extends HttpServletResponseWrapper /* ------------------------------------------------------------ */ /** - * Sets the min gzip size. - * - * @param minGzipSize the new min gzip size + * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setMinCompressSize(int) */ - public void setMinGzipSize(int minGzipSize) + public void setMinCompressSize(int minCompressSize) { - _minGzipSize = minGzipSize; + _minCompressSize = minCompressSize; } /* ------------------------------------------------------------ */ /** - * @see javax.servlet.ServletResponseWrapper#setContentType(java.lang.String) + * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setContentType(java.lang.String) */ + @Override public void setContentType(String ct) { super.setContentType(ct); - + if (ct!=null) { int colon=ct.indexOf(";"); if (colon>0) ct=ct.substring(0,colon); } - - if ((_gzStream==null || _gzStream._out==null) && + + if ((_compressedStream==null || _compressedStream.getOutputStream()==null) && (_mimeTypes==null && ct!=null && ct.contains("gzip") || _mimeTypes!=null && (ct==null||!_mimeTypes.contains(StringUtil.asciiToLowerCase(ct))))) { - noGzip(); + noCompression(); } } /* ------------------------------------------------------------ */ /** - * @see javax.servlet.http.HttpServletResponseWrapper#setStatus(int, java.lang.String) + * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setStatus(int, java.lang.String) */ + @Override public void setStatus(int sc, String sm) { super.setStatus(sc,sm); if (sc<200 || sc==204 || sc==205 || sc>=300) - noGzip(); + noCompression(); } /* ------------------------------------------------------------ */ /** - * @see javax.servlet.http.HttpServletResponseWrapper#setStatus(int) + * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setStatus(int) */ + @Override public void setStatus(int sc) { super.setStatus(sc); if (sc<200 || sc==204 || sc==205 ||sc>=300) - noGzip(); + noCompression(); } /* ------------------------------------------------------------ */ /** - * @see javax.servlet.ServletResponseWrapper#setContentLength(int) + * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setContentLength(int) */ + @Override public void setContentLength(int length) { setContentLength((long)length); } - - /* ------------------------------------------------------------ */ + protected void setContentLength(long length) { _contentLength=length; - if (_gzStream!=null) - _gzStream.setContentLength(length); - else if (_noGzip && _contentLength>=0) + if (_compressedStream!=null) + _compressedStream.setContentLength(length); + else if (_noCompression && _contentLength>=0) { HttpServletResponse response = (HttpServletResponse)getResponse(); if(_contentLength= 0) + { + if (_contentLength < Integer.MAX_VALUE) + _response.setContentLength((int)_contentLength); + else + _response.setHeader("Content-Length",Long.toString(_contentLength)); + } + } + + /* ------------------------------------------------------------ */ + /** + * @see java.io.OutputStream#flush() + */ + @Override + public void flush() throws IOException + { + if (_out == null || _bOut != null) + { + if (_contentLength > 0 && _contentLength < _minCompressSize) + doNotCompress(); + else + doCompress(); + } + + _out.flush(); + } + + /* ------------------------------------------------------------ */ + /** + * @see java.io.OutputStream#close() + */ + @Override + public void close() throws IOException + { + if (_closed) + return; + + if (_request.getAttribute("javax.servlet.include.request_uri") != null) + flush(); + else + { + if (_bOut != null) + { + if (_contentLength < 0) + _contentLength = _bOut.getCount(); + if (_contentLength < _minCompressSize) + doNotCompress(); + else + doCompress(); + } + else if (_out == null) + { + doNotCompress(); + } + + if (_compressedOutputStream != null) + _compressedOutputStream.close(); + else + _out.close(); + _closed = true; + } + } + + /** + * Finish. + * + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public void finish() throws IOException + { + if (!_closed) + { + if (_out == null || _bOut != null) + { + if (_contentLength > 0 && _contentLength < _minCompressSize) + doNotCompress(); + else + doCompress(); + } + + if (_compressedOutputStream != null && !_closed) + { + _closed = true; + _compressedOutputStream.close(); + } + } + } + + /* ------------------------------------------------------------ */ + /** + * @see java.io.OutputStream#write(int) + */ + @Override + public void write(int b) throws IOException + { + checkOut(1); + _out.write(b); + } + + /* ------------------------------------------------------------ */ + /** + * @see java.io.OutputStream#write(byte[]) + */ + @Override + public void write(byte b[]) throws IOException + { + checkOut(b.length); + _out.write(b); + } + + /* ------------------------------------------------------------ */ + /** + * @see java.io.OutputStream#write(byte[], int, int) + */ + @Override + public void write(byte b[], int off, int len) throws IOException + { + checkOut(len); + _out.write(b,off,len); + } + + /** + * Do compress. + * + * @throws IOException Signals that an I/O exception has occurred. + */ + public void doCompress() throws IOException + { + if (_compressedOutputStream==null) + { + if (_response.isCommitted()) + throw new IllegalStateException(); + + if (setContentEncoding()) + { + _out=_compressedOutputStream=createStream(); + + if (_bOut!=null) + { + _out.write(_bOut.getBuf(),0,_bOut.getCount()); + _bOut=null; + } + } + else + doNotCompress(); + } + } + + /** + * Do not compress. + * + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public void doNotCompress() throws IOException + { + if (_compressedOutputStream != null) + throw new IllegalStateException(); + if (_out == null || _bOut != null) + { + _doNotCompress = true; + + _out = _response.getOutputStream(); + setContentLength(_contentLength); + + if (_bOut != null) + _out.write(_bOut.getBuf(),0,_bOut.getCount()); + _bOut = null; + } + } + + /** + * Check out. + * + * @param length + * the length + * @throws IOException + * Signals that an I/O exception has occurred. + */ + private void checkOut(int length) throws IOException + { + if (_closed) + throw new IOException("CLOSED"); + + if (_out == null) + { + if (_response.isCommitted() || (_contentLength >= 0 && _contentLength < _minCompressSize)) + doNotCompress(); + else if (length > _minCompressSize) + doCompress(); + else + _out = _bOut = new ByteArrayOutputStream2(_bufferSize); + } + else if (_bOut != null) + { + if (_response.isCommitted() || (_contentLength >= 0 && _contentLength < _minCompressSize)) + doNotCompress(); + else if (length >= (_bOut.getBuf().length - _bOut.getCount())) + doCompress(); + } + } + + /** + * @see org.eclipse.jetty.http.gzip.CompressedStream#getOutputStream() + */ + public OutputStream getOutputStream() + { + return _out; + } + + /** + * @see org.eclipse.jetty.http.gzip.CompressedStream#isClosed() + */ + public boolean isClosed() + { + return _closed; + } + + /** + * Allows derived implementations to replace PrintWriter implementation. + */ + protected PrintWriter newWriter(OutputStream out, String encoding) throws UnsupportedEncodingException + { + return encoding == null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding)); + } + + /** + * Sets the content encoding. + * + * @return true, if successful + */ + protected abstract boolean setContentEncoding(); + + /** + * Create the stream fitting to the underlying compression type. + * + * @throws IOException + * Signals that an I/O exception has occurred. + */ + protected abstract DeflaterOutputStream createStream() throws IOException; + +} diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/CompressedResponseWrapper.java b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/CompressedResponseWrapper.java new file mode 100644 index 00000000000..14bdc6bb612 --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/CompressedResponseWrapper.java @@ -0,0 +1,58 @@ +// ======================================================================== +// Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.http.gzip; + +import java.io.IOException; +import java.util.Set; + +import javax.servlet.http.HttpServletResponse; + +/* ------------------------------------------------------------ */ +/** + * A ResponseWrapper interface that adds compress functionality to a ResponseWrapper + */ +public interface CompressedResponseWrapper extends HttpServletResponse +{ + + /** + * Sets the mime types. + * + * @param mimeTypes + * the new mime types + */ + public void setMimeTypes(Set mimeTypes); + + /** + * Sets the min compress size. + * + * @param minCompressSize + * the new min compress size + */ + public void setMinCompressSize(int minCompressSize); + + /* ------------------------------------------------------------ */ + /** + * No compression. + */ + public void noCompression(); + + /** + * Finish. + * + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public void finish() throws IOException; + +} \ No newline at end of file diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/CompressedStream.java b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/CompressedStream.java new file mode 100644 index 00000000000..751b2f05d1e --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/CompressedStream.java @@ -0,0 +1,77 @@ +// ======================================================================== +// Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.http.gzip; + +import java.io.Closeable; +import java.io.Flushable; +import java.io.IOException; +import java.io.OutputStream; + +/* ------------------------------------------------------------ */ +/** +* Interface for compressed streams +*/ +public interface CompressedStream extends Closeable, Flushable +{ + + /** + * Reset buffer. + */ + public void resetBuffer(); + + /** + * Sets the content length. + * + * @param length + * the new content length + */ + public void setContentLength(long length); + + /* ------------------------------------------------------------ */ + /** + * @return true if stream is closed + */ + public boolean isClosed(); + + /** + * Do compress. + * + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public void doCompress() throws IOException; + + /** + * Do not compress. + * + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public void doNotCompress() throws IOException; + + /** + * Finish. + * + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public void finish() throws IOException; + + /* ------------------------------------------------------------ */ + /** + * @return the {@link OutputStream} + */ + public OutputStream getOutputStream(); + +} \ No newline at end of file diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/CompressionType.java b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/CompressionType.java new file mode 100644 index 00000000000..4b75c2631d3 --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/CompressionType.java @@ -0,0 +1,48 @@ +// ======================================================================== +// Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd. +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.http.gzip; + +public enum CompressionType +{ + GZIP("gzip"), DEFLATE("deflate"), UNSUPPORTED("unsupported"); + + private final String encodingHeader; + + private CompressionType(String encodingHeader) + { + this.encodingHeader = encodingHeader; + } + + public String getEncodingHeader() + { + return encodingHeader; + } + + public static CompressionType getByEncodingHeader(String encodingHeader) + { + // prefer gzip over deflate + if (encodingHeader.toLowerCase().contains(CompressionType.GZIP.encodingHeader)) + { + return CompressionType.GZIP; + } + else if (encodingHeader.toLowerCase().contains(CompressionType.DEFLATE.encodingHeader)) + { + return CompressionType.DEFLATE; + } + else + { + return CompressionType.UNSUPPORTED; + } + } +} \ No newline at end of file diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/DeflateResponseWrapperImpl.java b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/DeflateResponseWrapperImpl.java new file mode 100644 index 00000000000..9cf5fe02673 --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/DeflateResponseWrapperImpl.java @@ -0,0 +1,54 @@ +// ======================================================================== +// Copyright (c) Webtide LLC +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + + +package org.eclipse.jetty.http.gzip; + +import java.io.IOException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/* ------------------------------------------------------------ */ +/** + */ +public class DeflateResponseWrapperImpl extends AbstractCompressedResponseWrapper +{ + /** + * Instantiates a new deflate response wrapper. + * + * @param request the request + * @param response the response + */ + public DeflateResponseWrapperImpl(HttpServletRequest request, HttpServletResponse response) + { + super(request,response); + } + + + /* ------------------------------------------------------------ */ + /** + * @param request the request + * @param response the response + * @param contentLength the content length + * @param bufferSize the buffer size + * @param minCompressSize the min compress size + * @return the deflate stream + * @throws IOException Signals that an I/O exception has occurred. + */ + @Override + protected CompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minCompressSize) throws IOException + { + return new DeflateStreamImpl(request,response,contentLength,bufferSize,minCompressSize); + } +} + diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/DeflateStreamImpl.java b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/DeflateStreamImpl.java new file mode 100644 index 00000000000..16e3d82750d --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/DeflateStreamImpl.java @@ -0,0 +1,55 @@ +// ======================================================================== +// Copyright (c) Webtide LLC +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.http.gzip; + +import java.io.IOException; +import java.util.zip.DeflaterOutputStream; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + + +/* ------------------------------------------------------------ */ +/** + * Compressed Stream implementation using deflate to compress + */ +public class DeflateStreamImpl extends AbstractCompressedStream implements CompressedStream +{ + public DeflateStreamImpl(HttpServletRequest request, HttpServletResponse response, long contentLength, int bufferSize, int minGzipSize) throws IOException + { + super(request,response,contentLength,bufferSize,minGzipSize); + } + + /** + * Sets the Content-Encoding header to deflate. + * + * @return true, if successful + */ + @Override + protected boolean setContentEncoding() + { + _response.setHeader("Content-Encoding", CompressionType.DEFLATE.getEncodingHeader()); + return _response.containsHeader("Content-Encoding"); + } + + /** + * @return a new DeflaterOutputStream backed by _response.getOutputStream() + */ + @Override + protected DeflaterOutputStream createStream() throws IOException + { + return new DeflaterOutputStream(_response.getOutputStream()); + } +} + diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipResponseWrapperImpl.java b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipResponseWrapperImpl.java new file mode 100644 index 00000000000..f434ad27c3f --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipResponseWrapperImpl.java @@ -0,0 +1,53 @@ +// ======================================================================== +// Copyright (c) Webtide LLC +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.http.gzip; + +import java.io.IOException; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +/* ------------------------------------------------------------ */ +/** + */ +public class GzipResponseWrapperImpl extends AbstractCompressedResponseWrapper +{ + /** + * Instantiates a new gzip response wrapper. + * + * @param request the request + * @param response the response + */ + public GzipResponseWrapperImpl(HttpServletRequest request, HttpServletResponse response) + { + super(request,response); + } + + + /* ------------------------------------------------------------ */ + /** + * @param request the request + * @param response the response + * @param contentLength the content length + * @param bufferSize the buffer size + * @param minCompressSize the min gzip size + * @return the gzip stream + * @throws IOException Signals that an I/O exception has occurred. + */ + @Override + protected CompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minCompressSize) throws IOException + { + return new GzipStreamImpl(request,response,contentLength,bufferSize,minCompressSize); + } +} + diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipStream.java b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipStream.java deleted file mode 100644 index aa05a1920e7..00000000000 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipStream.java +++ /dev/null @@ -1,305 +0,0 @@ -// ======================================================================== -// Copyright (c) Webtide LLC -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== - - -package org.eclipse.jetty.http.gzip; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.UnsupportedEncodingException; -import java.util.zip.GZIPOutputStream; - -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; - -import org.eclipse.jetty.util.ByteArrayOutputStream2; - - -/* ------------------------------------------------------------ */ -/** - */ -public class GzipStream extends ServletOutputStream -{ - protected HttpServletRequest _request; - protected HttpServletResponse _response; - protected OutputStream _out; - protected ByteArrayOutputStream2 _bOut; - protected GZIPOutputStream _gzOut; - protected boolean _closed; - protected int _bufferSize; - protected int _minGzipSize; - protected long _contentLength; - protected boolean _doNotGzip; - - /** - * Instantiates a new gzip stream. - * - * @param request the request - * @param response the response - * @param contentLength the content length - * @param bufferSize the buffer size - * @param minGzipSize the min gzip size - * @throws IOException Signals that an I/O exception has occurred. - */ - public GzipStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minGzipSize) throws IOException - { - _request=request; - _response=response; - _contentLength=contentLength; - _bufferSize=bufferSize; - _minGzipSize=minGzipSize; - if (minGzipSize==0) - doGzip(); - } - - /** - * Reset buffer. - */ - public void resetBuffer() - { - if (_response.isCommitted()) - throw new IllegalStateException("Committed"); - _closed=false; - _out=null; - _bOut=null; - if (_gzOut!=null) - _response.setHeader("Content-Encoding",null); - _gzOut=null; - _doNotGzip=false; - } - - /** - * Sets the content length. - * - * @param length the new content length - */ - public void setContentLength(long length) - { - _contentLength=length; - if (_doNotGzip && length>=0) - { - if(_contentLength0 && _contentLength<_minGzipSize) - doNotGzip(); - else - doGzip(); - } - - _out.flush(); - } - - /* ------------------------------------------------------------ */ - /** - * @see java.io.OutputStream#close() - */ - public void close() throws IOException - { - if (_closed) - return; - - if (_request.getAttribute("javax.servlet.include.request_uri")!=null) - flush(); - else - { - if (_bOut!=null) - { - if (_contentLength<0) - _contentLength=_bOut.getCount(); - if (_contentLength<_minGzipSize) - doNotGzip(); - else - doGzip(); - } - else if (_out==null) - { - doNotGzip(); - } - - if (_gzOut!=null) - _gzOut.close(); - else - _out.close(); - _closed=true; - } - } - - /** - * Finish. - * - * @throws IOException Signals that an I/O exception has occurred. - */ - public void finish() throws IOException - { - if (!_closed) - { - if (_out==null || _bOut!=null) - { - if (_contentLength>0 && _contentLength<_minGzipSize) - doNotGzip(); - else - doGzip(); - } - - if (_gzOut!=null && !_closed) - { - _closed=true; - _gzOut.close(); - } - } - } - - /* ------------------------------------------------------------ */ - /** - * @see java.io.OutputStream#write(int) - */ - public void write(int b) throws IOException - { - checkOut(1); - _out.write(b); - } - - /* ------------------------------------------------------------ */ - /** - * @see java.io.OutputStream#write(byte[]) - */ - public void write(byte b[]) throws IOException - { - checkOut(b.length); - _out.write(b); - } - - /* ------------------------------------------------------------ */ - /** - * @see java.io.OutputStream#write(byte[], int, int) - */ - public void write(byte b[], int off, int len) throws IOException - { - checkOut(len); - _out.write(b,off,len); - } - - /** - * Sets the content encoding gzip. - * - * @return true, if successful - */ - protected boolean setContentEncodingGzip() - { - _response.setHeader("Content-Encoding", "gzip"); - return _response.containsHeader("Content-Encoding"); - } - - /** - * Do gzip. - * - * @throws IOException Signals that an I/O exception has occurred. - */ - public void doGzip() throws IOException - { - if (_gzOut==null) - { - if (_response.isCommitted()) - throw new IllegalStateException(); - - if (setContentEncodingGzip()) - { - _out=_gzOut=new GZIPOutputStream(_response.getOutputStream(),_bufferSize); - - if (_bOut!=null) - { - _out.write(_bOut.getBuf(),0,_bOut.getCount()); - _bOut=null; - } - } - else - doNotGzip(); - } - } - - /** - * Do not gzip. - * - * @throws IOException Signals that an I/O exception has occurred. - */ - public void doNotGzip() throws IOException - { - if (_gzOut!=null) - throw new IllegalStateException(); - if (_out==null || _bOut!=null ) - { - _doNotGzip = true; - - _out=_response.getOutputStream(); - setContentLength(_contentLength); - - if (_bOut!=null) - _out.write(_bOut.getBuf(),0,_bOut.getCount()); - _bOut=null; - } - } - - /** - * Check out. - * - * @param length the length - * @throws IOException Signals that an I/O exception has occurred. - */ - private void checkOut(int length) throws IOException - { - if (_closed) - throw new IOException("CLOSED"); - - if (_out==null) - { - if (_response.isCommitted() || (_contentLength>=0 && _contentLength<_minGzipSize)) - doNotGzip(); - else if (length>_minGzipSize) - doGzip(); - else - _out=_bOut=new ByteArrayOutputStream2(_bufferSize); - } - else if (_bOut!=null) - { - if (_response.isCommitted() || (_contentLength>=0 && _contentLength<_minGzipSize)) - doNotGzip(); - else if (length>=(_bOut.getBuf().length -_bOut.getCount())) - doGzip(); - } - } - - /** - * Allows derived implementations to replace PrintWriter implementation. - */ - protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException - { - return encoding==null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding)); - } -} - diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipStreamImpl.java b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipStreamImpl.java new file mode 100644 index 00000000000..218aebca38d --- /dev/null +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipStreamImpl.java @@ -0,0 +1,56 @@ +// ======================================================================== +// Copyright (c) Webtide LLC +// ------------------------------------------------------------------------ +// All rights reserved. This program and the accompanying materials +// are made available under the terms of the Eclipse Public License v1.0 +// and Apache License v2.0 which accompanies this distribution. +// The Eclipse Public License is available at +// http://www.eclipse.org/legal/epl-v10.html +// The Apache License v2.0 is available at +// http://www.opensource.org/licenses/apache2.0.php +// You may elect to redistribute this code under either of these licenses. +// ======================================================================== + +package org.eclipse.jetty.http.gzip; + +import java.io.IOException; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.GZIPOutputStream; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + + +/* ------------------------------------------------------------ */ +/** + * Compressed Stream implementation using gzip to compress + */ +public class GzipStreamImpl extends AbstractCompressedStream implements CompressedStream +{ + public GzipStreamImpl(HttpServletRequest request, HttpServletResponse response, long contentLength, int bufferSize, int minGzipSize) throws IOException + { + super(request,response,contentLength,bufferSize,minGzipSize); + } + + /** + * Sets the Content-Encoding header to gzip. + * + * @return true, if successful + */ + @Override + protected boolean setContentEncoding() + { + _response.setHeader("Content-Encoding", CompressionType.GZIP.getEncodingHeader()); + return _response.containsHeader("Content-Encoding"); + } + + /** + * @return a new GZIPOutputStream backed by _response.getOutputStream() + */ + @Override + protected DeflaterOutputStream createStream() throws IOException + { + return new GZIPOutputStream(_response.getOutputStream(),_bufferSize); + } +} + diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/GzipHandler.java b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/GzipHandler.java index 81198f5299d..83bd42e152b 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/handler/GzipHandler.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/handler/GzipHandler.java @@ -30,7 +30,7 @@ import org.eclipse.jetty.continuation.Continuation; import org.eclipse.jetty.continuation.ContinuationListener; import org.eclipse.jetty.continuation.ContinuationSupport; import org.eclipse.jetty.http.HttpMethods; -import org.eclipse.jetty.http.gzip.GzipResponseWrapper; +import org.eclipse.jetty.http.gzip.GzipResponseWrapperImpl; import org.eclipse.jetty.server.Request; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; @@ -222,7 +222,7 @@ public class GzipHandler extends HandlerWrapper } } - final GzipResponseWrapper wrappedResponse = newGzipResponseWrapper(request,response); + final GzipResponseWrapperImpl wrappedResponse = newGzipResponseWrapper(request,response); boolean exceptional=true; try @@ -256,7 +256,7 @@ public class GzipHandler extends HandlerWrapper else if (exceptional && !response.isCommitted()) { wrappedResponse.resetBuffer(); - wrappedResponse.noGzip(); + wrappedResponse.noCompression(); } else wrappedResponse.finish(); @@ -276,14 +276,14 @@ public class GzipHandler extends HandlerWrapper * @param response the response * @return the gzip response wrapper */ - protected GzipResponseWrapper newGzipResponseWrapper(HttpServletRequest request, HttpServletResponse response) + protected GzipResponseWrapperImpl newGzipResponseWrapper(HttpServletRequest request, HttpServletResponse response) { - return new GzipResponseWrapper(request, response) + return new GzipResponseWrapperImpl(request, response) { { super.setMimeTypes(GzipHandler.this._mimeTypes); super.setBufferSize(GzipHandler.this._bufferSize); - super.setMinGzipSize(GzipHandler.this._minGzipSize); + super.setMinCompressSize(GzipHandler.this._minGzipSize); } @Override diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java index 1b993e6eedf..266b71887bc 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java @@ -13,10 +13,6 @@ package org.eclipse.jetty.servlets; import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.UnsupportedEncodingException; import java.util.HashSet; import java.util.Set; import java.util.StringTokenizer; @@ -34,14 +30,18 @@ import org.eclipse.jetty.continuation.Continuation; import org.eclipse.jetty.continuation.ContinuationListener; import org.eclipse.jetty.continuation.ContinuationSupport; import org.eclipse.jetty.http.HttpMethods; -import org.eclipse.jetty.http.gzip.GzipResponseWrapper; +import org.eclipse.jetty.http.gzip.CompressedResponseWrapper; +import org.eclipse.jetty.http.gzip.CompressionType; +import org.eclipse.jetty.http.gzip.DeflateResponseWrapperImpl; +import org.eclipse.jetty.http.gzip.GzipResponseWrapperImpl; import org.eclipse.jetty.util.log.Log; import org.eclipse.jetty.util.log.Logger; /* ------------------------------------------------------------ */ /** GZIP Filter - * This filter will gzip the content of a response iff:
    + * This filter will gzip or deflate the content of a response if:
      *
    • The filter is mapped to a matching path
    • + *
    • accept-encoding header is set to either gzip, deflate or a combination of those
    • *
    • The response status code is >=200 and <300 *
    • The content length is unknown or more than the minGzipSize initParameter or the minGzipSize is 0(default)
    • *
    • The content-type is in the comma separated list of mimeTypes set in the mimeTypes initParameter or @@ -50,8 +50,11 @@ import org.eclipse.jetty.util.log.Logger; *
    * *

    + * If both gzip and deflate are specified in the accept-encoding header, then gzip will be used. + *

    + *

    * Compressing the content can greatly improve the network bandwidth usage, but at a cost of memory and - * CPU cycles. If this filter is mapped for static content, then use of efficient direct NIO may be + * CPU cycles. If this filter is mapped for static content, then use of efficient direct NIO may be * prevented, thus use of the gzip mechanism of the {@link org.eclipse.jetty.servlet.DefaultServlet} is * advised instead. *

    @@ -157,7 +160,8 @@ public class GzipFilter extends UserAgentFilter HttpServletResponse response=(HttpServletResponse)res; String ae = request.getHeader("accept-encoding"); - if (ae != null && ae.indexOf("gzip")>=0 && !response.containsHeader("Content-Encoding") + CompressionType compressionType = CompressionType.getByEncodingHeader(ae); + if (ae != null && !compressionType.equals(CompressionType.UNSUPPORTED) && !response.containsHeader("Content-Encoding") && !HttpMethods.HEAD.equalsIgnoreCase(request.getMethod())) { String ua = getUserAgent(request); @@ -172,8 +176,8 @@ public class GzipFilter extends UserAgentFilter super.doFilter(request,response,chain); return; } - - final GzipResponseWrapper wrappedResponse=newGzipResponseWrapper(request,response); + + CompressedResponseWrapper wrappedResponse = createWrappedResponse(request,response,compressionType); boolean exceptional=true; try @@ -186,28 +190,12 @@ public class GzipFilter extends UserAgentFilter Continuation continuation = ContinuationSupport.getContinuation(request); if (continuation.isSuspended() && continuation.isResponseWrapped()) { - continuation.addContinuationListener(new ContinuationListener() - { - public void onComplete(Continuation continuation) - { - try - { - wrappedResponse.finish(); - } - catch(IOException e) - { - LOG.warn(e); - } - } - - public void onTimeout(Continuation continuation) - {} - }); + continuation.addContinuationListener(new ContinuationListenerWaitingForWrappedResponseToFinish(wrappedResponse)); } else if (exceptional && !response.isCommitted()) { wrappedResponse.resetBuffer(); - wrappedResponse.noGzip(); + wrappedResponse.noCompression(); } else wrappedResponse.finish(); @@ -218,7 +206,59 @@ public class GzipFilter extends UserAgentFilter super.doFilter(request,response,chain); } } + + protected CompressedResponseWrapper createWrappedResponse(HttpServletRequest request, HttpServletResponse response, CompressionType compressionType) + { + CompressedResponseWrapper wrappedResponse = null; + if (compressionType.equals(CompressionType.GZIP)) + { + wrappedResponse = new GzipResponseWrapperImpl(request,response); + } + else if (compressionType.equals(CompressionType.DEFLATE)) + { + wrappedResponse = new DeflateResponseWrapperImpl(request,response); + } + else + { + throw new IllegalStateException(compressionType + " not supported"); + } + configureWrappedResponse(wrappedResponse); + return wrappedResponse; + } + + private void configureWrappedResponse(CompressedResponseWrapper wrappedResponse) + { + wrappedResponse.setMimeTypes(_mimeTypes); + wrappedResponse.setBufferSize(_bufferSize); + wrappedResponse.setMinCompressSize(_minGzipSize); + } + private class ContinuationListenerWaitingForWrappedResponseToFinish implements ContinuationListener{ + + private CompressedResponseWrapper wrappedResponse; + + public ContinuationListenerWaitingForWrappedResponseToFinish(CompressedResponseWrapper wrappedResponse) + { + this.wrappedResponse = wrappedResponse; + } + + public void onComplete(Continuation continuation) + { + try + { + wrappedResponse.finish(); + } + catch (IOException e) + { + LOG.warn(e); + } + } + + public void onTimeout(Continuation continuation) + { + } + } + /** * Checks to see if the UserAgent is excluded * @@ -275,42 +315,4 @@ public class GzipFilter extends UserAgentFilter } return false; } - - /** - * Allows derived implementations to replace ResponseWrapper implementation. - * - * @param request the request - * @param response the response - * @return the gzip response wrapper - */ - protected GzipResponseWrapper newGzipResponseWrapper(HttpServletRequest request, HttpServletResponse response) - { - return new GzipResponseWrapper(request, response) - { - { - setMimeTypes(GzipFilter.this._mimeTypes); - setBufferSize(GzipFilter.this._bufferSize); - setMinGzipSize(GzipFilter.this._minGzipSize); - } - - @Override - protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException - { - return GzipFilter.this.newWriter(out,encoding); - } - }; - } - - /** - * Allows derived implementations to replace PrintWriter implementation. - * - * @param out the out - * @param encoding the encoding - * @return the prints the writer - * @throws UnsupportedEncodingException - */ - protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException - { - return encoding==null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding)); - } } diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/IncludableGzipFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/IncludableGzipFilter.java index 7d9a24ac58a..a325dee3a99 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/IncludableGzipFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/IncludableGzipFilter.java @@ -24,12 +24,14 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.http.gzip.GzipResponseWrapper; -import org.eclipse.jetty.http.gzip.GzipStream; +import org.eclipse.jetty.http.gzip.CompressedResponseWrapper; +import org.eclipse.jetty.http.gzip.CompressedStream; +import org.eclipse.jetty.http.gzip.CompressionType; +import org.eclipse.jetty.http.gzip.DeflateStreamImpl; +import org.eclipse.jetty.http.gzip.GzipResponseWrapperImpl; +import org.eclipse.jetty.http.gzip.GzipStreamImpl; import org.eclipse.jetty.io.UncheckedPrintWriter; - - /* ------------------------------------------------------------ */ /** Includable GZip Filter. * This extension to the {@link GzipFilter} that uses Jetty features to allow @@ -57,36 +59,52 @@ public class IncludableGzipFilter extends GzipFilter } @Override - protected GzipResponseWrapper newGzipResponseWrapper(HttpServletRequest request, HttpServletResponse response) + protected CompressedResponseWrapper createWrappedResponse(HttpServletRequest request, HttpServletResponse response, CompressionType compressionType) { return new IncludableResponseWrapper(request,response); } - public class IncludableResponseWrapper extends GzipResponseWrapper + public class IncludableResponseWrapper extends GzipResponseWrapperImpl { public IncludableResponseWrapper(HttpServletRequest request, HttpServletResponse response) { super(request,response); - + super.setMimeTypes(IncludableGzipFilter.this._mimeTypes); super.setBufferSize(IncludableGzipFilter.this._bufferSize); - super.setMinGzipSize(IncludableGzipFilter.this._minGzipSize); + super.setMinCompressSize(IncludableGzipFilter.this._minGzipSize); } @Override - protected GzipStream newGzipStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minGzipSize) throws IOException + protected CompressedStream newCompressedStream(HttpServletRequest request, HttpServletResponse response, long contentLength, int bufferSize, + int minGzipSize) throws IOException { - return new IncludableGzipStream(request,response,contentLength,bufferSize,minGzipSize); + String encodingHeader = request.getHeader("accept-encoding"); + CompressionType compressionType = CompressionType.getByEncodingHeader(encodingHeader); + if (compressionType.equals(CompressionType.GZIP)) + { + return new IncludableGzipStream(request,response,contentLength,bufferSize,minGzipSize); + } + else if (compressionType.equals(CompressionType.DEFLATE)) + { + return new IncludableDeflateStream(request,response,contentLength,bufferSize,minGzipSize); + } + else + { + throw new IllegalStateException(compressionType.name() + " not supported."); + } } @Override - protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException + protected PrintWriter newWriter(OutputStream out, String encoding) throws UnsupportedEncodingException { - return IncludableGzipFilter.this.newWriter(out,encoding); + if (_uncheckedPrintWriter) + return encoding == null?new UncheckedPrintWriter(out):new UncheckedPrintWriter(new OutputStreamWriter(out,encoding)); + return super.newWriter(out,encoding); } } - - public class IncludableGzipStream extends GzipStream + + public class IncludableGzipStream extends GzipStreamImpl { public IncludableGzipStream(HttpServletRequest request, HttpServletResponse response, long contentLength, int bufferSize, int minGzipSize) throws IOException @@ -95,22 +113,43 @@ public class IncludableGzipFilter extends GzipFilter } @Override - protected boolean setContentEncodingGzip() + protected boolean setContentEncoding() { - if (_request.getAttribute("javax.servlet.include.request_uri")!=null) - _response.setHeader("org.eclipse.jetty.server.include.Content-Encoding", "gzip"); + if (_request.getAttribute("javax.servlet.include.request_uri") != null) + { + _response.setHeader("org.eclipse.jetty.server.include.Content-Encoding","gzip"); + } else - _response.setHeader("Content-Encoding", "gzip"); - + { + _response.setHeader("Content-Encoding","gzip"); + } + return _response.containsHeader("Content-Encoding"); } } - @Override - protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException + public class IncludableDeflateStream extends DeflateStreamImpl { - if (_uncheckedPrintWriter) - return encoding==null?new UncheckedPrintWriter(out):new UncheckedPrintWriter(new OutputStreamWriter(out,encoding)); - return super.newWriter(out,encoding); + public IncludableDeflateStream(HttpServletRequest request, HttpServletResponse response, long contentLength, int bufferSize, int minGzipSize) + throws IOException + { + super(request,response,contentLength,bufferSize,minGzipSize); + } + + @Override + protected boolean setContentEncoding() + { + if (_request.getAttribute("javax.servlet.include.request_uri") != null) + { + _response.setHeader("org.eclipse.jetty.server.include.Content-Encoding","deflate"); + } + else + { + _response.setHeader("Content-Encoding","deflate"); + } + + return _response.containsHeader("Content-Encoding"); + } } + } diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterContentLengthTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterContentLengthTest.java index 109fe2675f2..b636583c716 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterContentLengthTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterContentLengthTest.java @@ -6,7 +6,8 @@ import java.util.List; import javax.servlet.Servlet; import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.http.gzip.GzipResponseWrapper; +import org.eclipse.jetty.http.gzip.CompressionType; +import org.eclipse.jetty.http.gzip.GzipResponseWrapperImpl; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlets.gzip.GzipTester; import org.eclipse.jetty.servlets.gzip.TestServletLengthStreamTypeWrite; @@ -48,32 +49,42 @@ public class GzipFilterContentLengthTest { return Arrays.asList(new Object[][] { - { TestServletLengthStreamTypeWrite.class }, - { TestServletLengthTypeStreamWrite.class }, - { TestServletStreamLengthTypeWrite.class }, - { TestServletStreamTypeLengthWrite.class }, - { TestServletTypeLengthStreamWrite.class }, - { TestServletTypeStreamLengthWrite.class } }); + { TestServletLengthStreamTypeWrite.class, CompressionType.GZIP }, + { TestServletLengthTypeStreamWrite.class, CompressionType.GZIP }, + { TestServletStreamLengthTypeWrite.class, CompressionType.GZIP }, + { TestServletStreamTypeLengthWrite.class, CompressionType.GZIP }, + { TestServletTypeLengthStreamWrite.class, CompressionType.GZIP }, + { TestServletTypeStreamLengthWrite.class, CompressionType.GZIP }, + { TestServletLengthStreamTypeWrite.class, CompressionType.DEFLATE }, + { TestServletLengthTypeStreamWrite.class, CompressionType.DEFLATE }, + { TestServletStreamLengthTypeWrite.class, CompressionType.DEFLATE }, + { TestServletStreamTypeLengthWrite.class, CompressionType.DEFLATE }, + { TestServletTypeLengthStreamWrite.class, CompressionType.DEFLATE }, + { TestServletTypeStreamLengthWrite.class, CompressionType.DEFLATE } + }); } - private static final int LARGE = GzipResponseWrapper.DEFAULT_BUFFER_SIZE * 8; - private static final int MEDIUM = GzipResponseWrapper.DEFAULT_BUFFER_SIZE; - private static final int SMALL = GzipResponseWrapper.DEFAULT_BUFFER_SIZE / 4; - private static final int TINY = GzipResponseWrapper.DEFAULT_MIN_GZIP_SIZE / 2; + private static final int LARGE = GzipResponseWrapperImpl.DEFAULT_BUFFER_SIZE * 8; + private static final int MEDIUM = GzipResponseWrapperImpl.DEFAULT_BUFFER_SIZE; + private static final int SMALL = GzipResponseWrapperImpl.DEFAULT_BUFFER_SIZE / 4; + private static final int TINY = GzipResponseWrapperImpl.DEFAULT_MIN_COMPRESS_SIZE/ 2; + + private CompressionType compressionType; + public GzipFilterContentLengthTest(Class testServlet, CompressionType compressionType) + { + this.testServlet = testServlet; + this.compressionType = compressionType; + } + @Rule public TestingDir testingdir = new TestingDir(); private Class testServlet; - public GzipFilterContentLengthTest(Class testServlet) - { - this.testServlet = testServlet; - } - private void assertIsGzipCompressed(String filename, int filesize) throws Exception { - GzipTester tester = new GzipTester(testingdir); + GzipTester tester = new GzipTester(testingdir, compressionType); File testfile = tester.prepareServerFile(testServlet.getSimpleName() + "-" + filename,filesize); @@ -93,7 +104,7 @@ public class GzipFilterContentLengthTest private void assertIsNotGzipCompressed(String filename, int filesize) throws Exception { - GzipTester tester = new GzipTester(testingdir); + GzipTester tester = new GzipTester(testingdir, compressionType); File testfile = tester.prepareServerFile(testServlet.getSimpleName() + "-" + filename,filesize); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java index ec5aab410be..996e26a0547 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java @@ -5,6 +5,7 @@ import java.io.IOException; import java.util.Arrays; import java.util.List; +import org.eclipse.jetty.http.gzip.CompressionType; import org.eclipse.jetty.servlet.DefaultServlet; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlets.gzip.GzipTester; @@ -31,22 +32,41 @@ public class GzipFilterDefaultNoRecompressTest return Arrays.asList(new Object[][] { // Some already compressed files - { "test_quotes.gz", "application/gzip" }, - { "test_quotes.bz2", "application/bzip2" }, - { "test_quotes.zip", "application/zip" }, - { "test_quotes.rar", "application/octet-stream" }, + { "test_quotes.gz", "application/gzip", CompressionType.GZIP }, + { "test_quotes.bz2", "application/bzip2", CompressionType.GZIP }, + { "test_quotes.zip", "application/zip", CompressionType.GZIP }, + { "test_quotes.rar", "application/octet-stream", CompressionType.GZIP }, // Some images (common first) - { "jetty_logo.png", "image/png" }, - { "jetty_logo.gif", "image/gif" }, - { "jetty_logo.jpeg", "image/jpeg" }, - { "jetty_logo.jpg", "image/jpeg" }, + { "jetty_logo.png", "image/png", CompressionType.GZIP }, + { "jetty_logo.gif", "image/gif", CompressionType.GZIP }, + { "jetty_logo.jpeg", "image/jpeg", CompressionType.GZIP }, + { "jetty_logo.jpg", "image/jpeg", CompressionType.GZIP }, // Lesser encountered images (usually found being requested from non-browser clients) - { "jetty_logo.bmp", "image/bmp" }, - { "jetty_logo.tga", "application/tga" }, - { "jetty_logo.tif", "image/tiff" }, - { "jetty_logo.tiff", "image/tiff" }, - { "jetty_logo.xcf", "image/xcf" }, - { "jetty_logo.jp2", "image/jpeg2000" } }); + { "jetty_logo.bmp", "image/bmp", CompressionType.GZIP }, + { "jetty_logo.tga", "application/tga", CompressionType.GZIP }, + { "jetty_logo.tif", "image/tiff", CompressionType.GZIP }, + { "jetty_logo.tiff", "image/tiff", CompressionType.GZIP }, + { "jetty_logo.xcf", "image/xcf", CompressionType.GZIP }, + { "jetty_logo.jp2", "image/jpeg2000", CompressionType.GZIP }, + + // Same tests again for deflate + // Some already compressed files + { "test_quotes.gz", "application/gzip", CompressionType.DEFLATE }, + { "test_quotes.bz2", "application/bzip2", CompressionType.DEFLATE }, + { "test_quotes.zip", "application/zip", CompressionType.DEFLATE }, + { "test_quotes.rar", "application/octet-stream", CompressionType.DEFLATE }, + // Some images (common first) + { "jetty_logo.png", "image/png", CompressionType.DEFLATE }, + { "jetty_logo.gif", "image/gif", CompressionType.DEFLATE }, + { "jetty_logo.jpeg", "image/jpeg", CompressionType.DEFLATE }, + { "jetty_logo.jpg", "image/jpeg", CompressionType.DEFLATE }, + // Lesser encountered images (usually found being requested from non-browser clients) + { "jetty_logo.bmp", "image/bmp", CompressionType.DEFLATE }, + { "jetty_logo.tga", "application/tga", CompressionType.DEFLATE }, + { "jetty_logo.tif", "image/tiff", CompressionType.DEFLATE }, + { "jetty_logo.tiff", "image/tiff", CompressionType.DEFLATE }, + { "jetty_logo.xcf", "image/xcf", CompressionType.DEFLATE }, + { "jetty_logo.jp2", "image/jpeg2000", CompressionType.DEFLATE } }); } @Rule @@ -54,17 +74,19 @@ public class GzipFilterDefaultNoRecompressTest private String alreadyCompressedFilename; private String expectedContentType; + private CompressionType compressionType; - public GzipFilterDefaultNoRecompressTest(String testFilename, String expectedContentType) + public GzipFilterDefaultNoRecompressTest(String testFilename, String expectedContentType, CompressionType compressionType) { this.alreadyCompressedFilename = testFilename; this.expectedContentType = expectedContentType; + this.compressionType = compressionType; } @Test public void testNotGzipFiltered_Default_AlreadyCompressed() throws Exception { - GzipTester tester = new GzipTester(testingdir); + GzipTester tester = new GzipTester(testingdir, compressionType); copyTestFileToServer(alreadyCompressedFilename); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java index 82fd54dc11f..47f637150cd 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java @@ -1,6 +1,8 @@ package org.eclipse.jetty.servlets; import java.io.IOException; +import java.util.Arrays; +import java.util.Collection; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; @@ -8,23 +10,48 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.http.gzip.GzipResponseWrapper; +import org.eclipse.jetty.http.gzip.CompressionType; +import org.eclipse.jetty.http.gzip.GzipResponseWrapperImpl; import org.eclipse.jetty.servlet.DefaultServlet; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlets.gzip.GzipTester; import org.eclipse.jetty.toolchain.test.TestingDir; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; /** * Test the GzipFilter support built into the {@link DefaultServlet} */ +@RunWith(Parameterized.class) public class GzipFilterDefaultTest { + @Parameters + public static Collection data() + { + CompressionType[][] data = new CompressionType[][] + { + { CompressionType.GZIP }, + { CompressionType.DEFLATE } + }; + + return Arrays.asList(data); + } + + private CompressionType compressionType; + + public GzipFilterDefaultTest(CompressionType compressionType) + { + this.compressionType = compressionType; + } public static class HttpStatusServlet extends HttpServlet { + private static final long serialVersionUID = 1L; + private int _status = 204; public HttpStatusServlet() @@ -50,10 +77,10 @@ public class GzipFilterDefaultTest @Test public void testIsGzipCompressedTiny() throws Exception { - GzipTester tester = new GzipTester(testingdir); + GzipTester tester = new GzipTester(testingdir, compressionType); // Test content that is smaller than the buffer. - int filesize = GzipResponseWrapper.DEFAULT_BUFFER_SIZE / 4; + int filesize = GzipResponseWrapperImpl.DEFAULT_BUFFER_SIZE / 4; tester.prepareServerFile("file.txt",filesize); FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class); @@ -73,10 +100,10 @@ public class GzipFilterDefaultTest @Test public void testIsGzipCompressedLarge() throws Exception { - GzipTester tester = new GzipTester(testingdir); + GzipTester tester = new GzipTester(testingdir, compressionType); // Test content that is smaller than the buffer. - int filesize = GzipResponseWrapper.DEFAULT_BUFFER_SIZE * 4; + int filesize = GzipResponseWrapperImpl.DEFAULT_BUFFER_SIZE * 4; tester.prepareServerFile("file.txt",filesize); FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class); @@ -96,10 +123,10 @@ public class GzipFilterDefaultTest @Test public void testIsNotGzipCompressed() throws Exception { - GzipTester tester = new GzipTester(testingdir); + GzipTester tester = new GzipTester(testingdir, compressionType); // Test content that is smaller than the buffer. - int filesize = GzipResponseWrapper.DEFAULT_BUFFER_SIZE * 4; + int filesize = GzipResponseWrapperImpl.DEFAULT_BUFFER_SIZE * 4; tester.prepareServerFile("file.mp3",filesize); FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class); @@ -119,7 +146,7 @@ public class GzipFilterDefaultTest @Test public void testIsNotGzipCompressedHttpStatus() throws Exception { - GzipTester tester = new GzipTester(testingdir); + GzipTester tester = new GzipTester(testingdir, compressionType); // Test error code 204 FilterHolder holder = tester.setContentServlet(HttpStatusServlet.class); @@ -140,13 +167,13 @@ public class GzipFilterDefaultTest @Test public void testUserAgentExclusion() throws Exception { - GzipTester tester = new GzipTester(testingdir); + GzipTester tester = new GzipTester(testingdir, compressionType); FilterHolder holder = tester.setContentServlet(DefaultServlet.class); holder.setInitParameter("excludedAgents", "foo"); tester.setUserAgent("foo"); - int filesize = GzipResponseWrapper.DEFAULT_BUFFER_SIZE * 4; + int filesize = GzipResponseWrapperImpl.DEFAULT_BUFFER_SIZE * 4; tester.prepareServerFile("file.txt",filesize); try diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipWithPipeliningTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipWithPipeliningTest.java index b6a030ab894..65a66898fc4 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipWithPipeliningTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipWithPipeliningTest.java @@ -1,18 +1,24 @@ package org.eclipse.jetty.servlets; import static org.hamcrest.Matchers.*; +import static org.junit.Assert.*; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; +import java.io.InputStream; import java.net.URI; import java.security.DigestOutputStream; import java.security.MessageDigest; +import java.util.Arrays; +import java.util.Collection; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; +import java.util.zip.InflaterInputStream; +import org.eclipse.jetty.http.gzip.CompressionType; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.DefaultServlet; @@ -25,21 +31,46 @@ import org.eclipse.jetty.toolchain.test.IO; import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.TestingDir; import org.junit.After; -import org.junit.Assert; import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; /** * Test the effects of Gzip filtering when in the context of HTTP/1.1 Pipelining. */ +@RunWith(Parameterized.class) public class GzipWithPipeliningTest { + @Parameters + public static Collection data() + { + // Test different Content-Encoding header combinations. So implicitly testing that gzip is preferred oder deflate + String[][] data = new String[][] + { + { CompressionType.GZIP.getEncodingHeader() }, + { CompressionType.DEFLATE.getEncodingHeader() + ", " + CompressionType.GZIP.getEncodingHeader() }, + { CompressionType.GZIP.getEncodingHeader() + ", " + CompressionType.DEFLATE.getEncodingHeader() }, + { CompressionType.DEFLATE.getEncodingHeader() } + }; + + return Arrays.asList(data); + } + @Rule public TestingDir testingdir = new TestingDir(); private Server server; private URI serverUri; + private String encodingHeader; + + + public GzipWithPipeliningTest(String encodingHeader) + { + this.encodingHeader = encodingHeader; + } @Before public void startServer() throws Exception @@ -86,7 +117,7 @@ public class GzipWithPipeliningTest testingdir.ensureEmpty(); File outputDir = testingdir.getDir(); - PipelineHelper client = new PipelineHelper(serverUri); + PipelineHelper client = new PipelineHelper(serverUri, encodingHeader); try { @@ -95,7 +126,7 @@ public class GzipWithPipeliningTest // Size of content, as it exists on disk, without gzip compression. long rawsize = txtFile.length() + pngFile.length(); - Assert.assertThat("Ensure that we have sufficient file size to trigger chunking",rawsize,greaterThan(300000L)); + assertThat("Ensure that we have sufficient file size to trigger chunking",rawsize,greaterThan(300000L)); String respHeader; @@ -106,8 +137,9 @@ public class GzipWithPipeliningTest respHeader = client.readResponseHeader(); System.out.println("Response Header #1 --\n" + respHeader); - Assert.assertThat("Content-Encoding should be gzipped",respHeader,containsString("Content-Encoding: gzip\r\n")); - Assert.assertThat("Transfer-Encoding should be chunked",respHeader,containsString("Transfer-Encoding: chunked\r\n")); + String expectedEncodingHeader = encodingHeader.equals(CompressionType.DEFLATE.getEncodingHeader()) ? CompressionType.DEFLATE.getEncodingHeader() : CompressionType.GZIP.getEncodingHeader(); + assertThat("Content-Encoding should be gzipped",respHeader,containsString("Content-Encoding: " + expectedEncodingHeader + "\r\n")); + assertThat("Transfer-Encoding should be chunked",respHeader,containsString("Transfer-Encoding: chunked\r\n")); // Raw output / gzipped, writted to disk (checked for sha1sum later) File rawOutputFile = new File(outputDir, "response-1.gz"); @@ -118,7 +150,7 @@ public class GzipWithPipeliningTest // Read only 20% - intentionally a partial read. System.out.println("Attempting to read partial content ..."); - int readBytes = client.readBody(rawOutputStream,(int)((float)chunkSize * 0.20f)); + int readBytes = client.readBody(rawOutputStream,(int)(chunkSize * 0.20f)); System.out.printf("Read %,d bytes%n",readBytes); // Issue another request @@ -133,14 +165,14 @@ public class GzipWithPipeliningTest readBytes = client.readBody(rawOutputStream,(int)chunkSize); System.out.printf("Read %,d bytes%n",readBytes); line = client.readLine(); - Assert.assertThat("Chunk delim should be an empty line with CR+LF",line,is("")); + assertThat("Chunk delim should be an empty line with CR+LF",line,is("")); chunkSize = client.readChunkSize(); System.out.printf("Next Chunk: (0x%X) %,d bytes%n",chunkSize,chunkSize); } // Inter-pipeline delim line = client.readLine(); - Assert.assertThat("Inter-pipeline delim should be an empty line with CR+LF",line,is("")); + assertThat("Inter-pipeline delim should be an empty line with CR+LF",line,is("")); // Sha1tracking for 1st Request MessageDigest digestTxt = MessageDigest.getInstance("SHA1"); @@ -149,14 +181,23 @@ public class GzipWithPipeliningTest // Decompress 1st request and calculate sha1sum IO.close(rawOutputStream); FileInputStream rawInputStream = new FileInputStream(rawOutputFile); - GZIPInputStream ungzipStream = new GZIPInputStream(rawInputStream); - IO.copy(ungzipStream, digesterTxt); + InputStream uncompressedStream = null; + if (CompressionType.DEFLATE.getEncodingHeader().equals(encodingHeader)) + { + uncompressedStream = new InflaterInputStream(rawInputStream); + } + else + { + uncompressedStream = new GZIPInputStream(rawInputStream); + } + + IO.copy(uncompressedStream, digesterTxt); // Read 2nd request http response header respHeader = client.readResponseHeader(); System.out.println("Response Header #2 --\n" + respHeader); - Assert.assertThat("Content-Encoding should NOT be gzipped",respHeader,not(containsString("Content-Encoding: gzip\r\n"))); - Assert.assertThat("Transfer-Encoding should NOT be chunked",respHeader,not(containsString("Transfer-Encoding: chunked\r\n"))); + assertThat("Content-Encoding should NOT be gzipped",respHeader,not(containsString("Content-Encoding: gzip\r\n"))); + assertThat("Transfer-Encoding should NOT be chunked",respHeader,not(containsString("Transfer-Encoding: chunked\r\n"))); // Sha1tracking for 2nd Request MessageDigest digestImg = MessageDigest.getInstance("SHA1"); @@ -164,7 +205,7 @@ public class GzipWithPipeliningTest // Read 2nd request body int contentLength = client.getContentLength(respHeader); - Assert.assertThat("Image Content Length",(long)contentLength,is(pngFile.length())); + assertThat("Image Content Length",(long)contentLength,is(pngFile.length())); client.readBody(digesterImg,contentLength); // Validate checksums @@ -183,7 +224,7 @@ public class GzipWithPipeliningTest { String expectedSha1 = loadSha1sum(testResourceFile + ".sha1"); String actualSha1 = Hex.asHex(digest.digest()); - Assert.assertEquals(testResourceFile + " / SHA1Sum of content",expectedSha1,actualSha1); + assertEquals(testResourceFile + " / SHA1Sum of content",expectedSha1,actualSha1); } private String loadSha1sum(String testResourceSha1Sum) throws IOException @@ -192,7 +233,7 @@ public class GzipWithPipeliningTest String contents = IO.readToString(sha1File); Pattern pat = Pattern.compile("^[0-9A-Fa-f]*"); Matcher mat = pat.matcher(contents); - Assert.assertTrue("Should have found HEX code in SHA1 file: " + sha1File,mat.find()); + assertTrue("Should have found HEX code in SHA1 file: " + sha1File,mat.find()); return mat.group(); } diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterMinSizeTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterMinSizeTest.java index 6e37eb311fb..e12abff667a 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterMinSizeTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterMinSizeTest.java @@ -13,14 +13,21 @@ package org.eclipse.jetty.servlets; +import java.util.Arrays; +import java.util.Collection; + import javax.servlet.Servlet; +import org.eclipse.jetty.http.gzip.CompressionType; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlets.gzip.GzipTester; import org.eclipse.jetty.servlets.gzip.TestMinGzipSizeServlet; import org.eclipse.jetty.toolchain.test.TestingDir; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; /** * Perform specific tests on the IncludableGzipFilter's ability to manage @@ -28,17 +35,36 @@ import org.junit.Test; * * @see http://bugs.eclipse.org/366106 */ +@RunWith(Parameterized.class) public class IncludableGzipFilterMinSizeTest { + @Parameters + public static Collection data() + { + CompressionType[][] data = new CompressionType[][] + { + { CompressionType.GZIP }, + { CompressionType.DEFLATE } + }; + + return Arrays.asList(data); + } + + public IncludableGzipFilterMinSizeTest(CompressionType compressionType) + { + this.compressionType = compressionType; + } + @Rule public TestingDir testdir = new TestingDir(); + private CompressionType compressionType; private Class testServlet = TestMinGzipSizeServlet.class; @Test public void testUnderMinSize() throws Exception { - GzipTester tester = new GzipTester(testdir); + GzipTester tester = new GzipTester(testdir, compressionType); // Use IncludableGzipFilter tester.setGzipFilterClass(IncludableGzipFilter.class); @@ -64,7 +90,7 @@ public class IncludableGzipFilterMinSizeTest @Test public void testOverMinSize() throws Exception { - GzipTester tester = new GzipTester(testdir); + GzipTester tester = new GzipTester(testdir, compressionType); // Use IncludableGzipFilter tester.setGzipFilterClass(IncludableGzipFilter.class); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterTest.java index 63b0dd9d262..49459e4e2ef 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterTest.java @@ -22,10 +22,14 @@ import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; +import java.util.Arrays; +import java.util.Collection; import java.util.zip.GZIPInputStream; +import java.util.zip.InflaterInputStream; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.http.gzip.CompressionType; import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.testing.HttpTester; @@ -36,9 +40,28 @@ import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; +@RunWith(Parameterized.class) public class IncludableGzipFilterTest { + @Parameters + public static Collection data() + { + CompressionType[][] data = new CompressionType[][] + { + { CompressionType.GZIP }, + { CompressionType.DEFLATE } + }; + + return Arrays.asList(data); + } + + @Rule + public TestingDir testdir = new TestingDir(); + private static String __content = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. In quis felis nunc. "+ "Quisque suscipit mauris et ante auctor ornare rhoncus lacus aliquet. Pellentesque "+ @@ -53,11 +76,14 @@ public class IncludableGzipFilterTest "Aliquam purus mauris, consectetur nec convallis lacinia, porta sed ante. Suspendisse "+ "et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque."; - @Rule - public TestingDir testdir = new TestingDir(); - private ServletTester tester; - + private CompressionType compressionType; + + public IncludableGzipFilterTest(CompressionType compressionType) + { + this.compressionType = compressionType; + } + @Before public void setUp() throws Exception { @@ -95,7 +121,7 @@ public class IncludableGzipFilterTest request.setMethod("GET"); request.setVersion("HTTP/1.0"); request.setHeader("Host","tester"); - request.setHeader("accept-encoding","gzip"); + request.setHeader("accept-encoding", compressionType.getEncodingHeader()); request.setURI("/context/file.txt"); ByteArrayBuffer reqsBuff = new ByteArrayBuffer(request.generate().getBytes()); @@ -103,10 +129,19 @@ public class IncludableGzipFilterTest response.parse(respBuff.asArray()); assertTrue(response.getMethod()==null); - assertTrue(response.getHeader("Content-Encoding").equalsIgnoreCase("gzip")); + assertTrue(response.getHeader("Content-Encoding").equalsIgnoreCase(compressionType.getEncodingHeader())); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); - InputStream testIn = new GZIPInputStream(new ByteArrayInputStream(response.getContentBytes())); + InputStream testIn = null; + ByteArrayInputStream compressedResponseStream = new ByteArrayInputStream(response.getContentBytes()); + if (compressionType.equals(CompressionType.GZIP)) + { + testIn = new GZIPInputStream(compressedResponseStream); + } + else if (compressionType.equals(CompressionType.DEFLATE)) + { + testIn = new InflaterInputStream(compressedResponseStream); + } ByteArrayOutputStream testOut = new ByteArrayOutputStream(); IO.copy(testIn,testOut); diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PipelineHelper.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PipelineHelper.java index 3f0e039b3e8..ad58c1bad6e 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PipelineHelper.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/PipelineHelper.java @@ -25,8 +25,9 @@ public class PipelineHelper private Socket socket; private OutputStream outputStream; private InputStream inputStream; + private String encodingHeader; - public PipelineHelper(URI uri) + public PipelineHelper(URI uri, String encodingHeader) { if (LOG instanceof StdErrLog) { @@ -34,6 +35,7 @@ public class PipelineHelper } this.uri = uri; this.endpoint = new InetSocketAddress(uri.getHost(),uri.getPort()); + this.encodingHeader = encodingHeader; } /** @@ -76,7 +78,7 @@ public class PipelineHelper req.append("Accept-Language: en-us\r\n"); if (acceptGzipped) { - req.append("Accept-Encoding: gzip, deflate\r\n"); + req.append("Accept-Encoding: " + encodingHeader + "\r\n"); } req.append("Cookie: JSESSIONID=spqx8v8szylt1336t96vc6mw0\r\n"); if ( close ) @@ -134,7 +136,7 @@ public class PipelineHelper while (!(foundCR && foundLF)) { b = inputStream.read(); - Assert.assertThat("Should not have hit EOL (yet) during chunk size read",(int)b,not(-1)); + Assert.assertThat("Should not have hit EOL (yet) during chunk size read",b,not(-1)); if (b == 0x0D) { foundCR = true; @@ -163,7 +165,7 @@ public class PipelineHelper while (!(foundCR && foundLF)) { b = inputStream.read(); - Assert.assertThat("Should not have hit EOL (yet) during chunk size read",(int)b,not(-1)); + Assert.assertThat("Should not have hit EOL (yet) during chunk size read",b,not(-1)); if (b == 0x0D) { foundCR = true; diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java index d4e101775ff..91cc374c893 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java @@ -1,5 +1,13 @@ package org.eclipse.jetty.servlets.gzip; +import static org.hamcrest.Matchers.containsString; +import static org.hamcrest.Matchers.equalTo; +import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; +import static org.hamcrest.Matchers.notNullValue; +import static org.hamcrest.Matchers.nullValue; +import static org.junit.Assert.assertThat; + import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; @@ -12,9 +20,12 @@ import java.util.Enumeration; import java.util.regex.Matcher; import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; +import java.util.zip.InflaterInputStream; + import javax.servlet.Servlet; import javax.servlet.http.HttpServletResponse; +import org.eclipse.jetty.http.gzip.CompressionType; import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletHolder; @@ -26,12 +37,6 @@ import org.eclipse.jetty.toolchain.test.MavenTestingUtils; import org.eclipse.jetty.toolchain.test.TestingDir; import org.junit.Assert; -import static org.hamcrest.Matchers.containsString; -import static org.hamcrest.Matchers.is; -import static org.hamcrest.Matchers.not; -import static org.hamcrest.Matchers.notNullValue; -import static org.hamcrest.Matchers.nullValue; - public class GzipTester { private Class gzipFilterClass = GzipFilter.class; @@ -39,10 +44,12 @@ public class GzipTester private String userAgent = null; private ServletTester servletTester; private TestingDir testdir; + private CompressionType compressionType; - public GzipTester(TestingDir testingdir) + public GzipTester(TestingDir testingdir, CompressionType compressionType) { this.testdir = testingdir; + this.compressionType = compressionType; // Make sure we start with a clean testing directory. // DOES NOT WORK IN WINDOWS - this.testdir.ensureEmpty(); } @@ -61,7 +68,7 @@ public class GzipTester request.setMethod("GET"); request.setVersion("HTTP/1.0"); request.setHeader("Host","tester"); - request.setHeader("Accept-Encoding","gzip"); + request.setHeader("Accept-Encoding",compressionType.getEncodingHeader()); if (this.userAgent != null) request.setHeader("User-Agent", this.userAgent); request.setURI("/context/" + requestedFilename); @@ -76,7 +83,7 @@ public class GzipTester Assert.assertThat("Response.method",response.getMethod(),nullValue()); Assert.assertThat("Response.status",response.getStatus(),is(HttpServletResponse.SC_OK)); Assert.assertThat("Response.header[Content-Length]",response.getHeader("Content-Length"),notNullValue()); - Assert.assertThat("Response.header[Content-Encoding]",response.getHeader("Content-Encoding"),containsString("gzip")); + Assert.assertThat("Response.header[Content-Encoding]",response.getHeader("Content-Encoding"),containsString(compressionType.getEncodingHeader())); // Assert that the decompressed contents are what we expect. File serverFile = testdir.getFile(serverFilename); @@ -89,12 +96,19 @@ public class GzipTester try { bais = new ByteArrayInputStream(response.getContentBytes()); - in = new GZIPInputStream(bais); + if (compressionType.equals(CompressionType.GZIP)) + { + in = new GZIPInputStream(bais); + } + else if (compressionType.equals(CompressionType.DEFLATE)) + { + in = new InflaterInputStream(bais); + } out = new ByteArrayOutputStream(); IO.copy(in,out); actual = out.toString(encoding); - Assert.assertEquals("Uncompressed contents",expected,actual); + assertThat("Uncompressed contents",actual,equalTo(expected)); } finally { @@ -128,7 +142,7 @@ public class GzipTester request.setMethod("GET"); request.setVersion("HTTP/1.0"); request.setHeader("Host","tester"); - request.setHeader("Accept-Encoding","gzip"); + request.setHeader("Accept-Encoding",compressionType.getEncodingHeader()); if (this.userAgent != null) request.setHeader("User-Agent", this.userAgent); request.setURI("/context/" + requestedFilename); @@ -215,7 +229,7 @@ public class GzipTester request.setMethod("GET"); request.setVersion("HTTP/1.0"); request.setHeader("Host","tester"); - request.setHeader("Accept-Encoding","gzip"); + request.setHeader("Accept-Encoding",compressionType.getEncodingHeader()); if (this.userAgent != null) request.setHeader("User-Agent", this.userAgent); if (filename == null) @@ -238,7 +252,7 @@ public class GzipTester int serverLength = Integer.parseInt(response.getHeader("Content-Length")); Assert.assertThat("Response.header[Content-Length]",serverLength,is(expectedFilesize)); } - Assert.assertThat("Response.header[Content-Encoding]",response.getHeader("Content-Encoding"),not(containsString("gzip"))); + Assert.assertThat("Response.header[Content-Encoding]",response.getHeader("Content-Encoding"),not(containsString(compressionType.getEncodingHeader()))); // Assert that the contents are what we expect. if (filename != null) From 9244292fcaeb0b688802f6e8d4c52527b5bad45f Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 2 Apr 2012 12:09:03 +1000 Subject: [PATCH 2/5] 375692: simplified gzipfilter --- .../AbstractCompressedResponseWrapper.java | 412 ------------------ .../http/gzip/AbstractCompressedStream.java | 22 +- .../http/gzip/CompressedResponseWrapper.java | 401 ++++++++++++++++- .../jetty/http/gzip/CompressedStream.java | 77 ---- .../jetty/http/gzip/CompressionType.java | 48 -- .../http/gzip/DeflateResponseWrapperImpl.java | 54 --- .../jetty/http/gzip/DeflateStreamImpl.java | 55 --- .../http/gzip/GzipResponseWrapperImpl.java | 53 --- .../jetty/http/gzip/GzipStreamImpl.java | 56 --- .../jetty/server/handler/GzipHandler.java | 24 +- .../eclipse/jetty/servlets/GzipFilter.java | 70 ++- .../jetty/servlets/IncludableGzipFilter.java | 138 +++--- .../servlets/GzipFilterContentLengthTest.java | 39 +- .../GzipFilterDefaultNoRecompressTest.java | 61 ++- .../jetty/servlets/GzipFilterDefaultTest.java | 23 +- .../servlets/GzipWithPipeliningTest.java | 13 +- .../IncludableGzipFilterMinSizeTest.java | 13 +- .../servlets/IncludableGzipFilterTest.java | 21 +- .../jetty/servlets/gzip/GzipTester.java | 19 +- 19 files changed, 618 insertions(+), 981 deletions(-) delete mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/gzip/AbstractCompressedResponseWrapper.java delete mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/gzip/CompressedStream.java delete mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/gzip/CompressionType.java delete mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/gzip/DeflateResponseWrapperImpl.java delete mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/gzip/DeflateStreamImpl.java delete mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipResponseWrapperImpl.java delete mode 100644 jetty-http/src/main/java/org/eclipse/jetty/http/gzip/GzipStreamImpl.java diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/AbstractCompressedResponseWrapper.java b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/AbstractCompressedResponseWrapper.java deleted file mode 100644 index 95c69109e99..00000000000 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/AbstractCompressedResponseWrapper.java +++ /dev/null @@ -1,412 +0,0 @@ -// ======================================================================== -// Copyright (c) 2009-2009 Mort Bay Consulting Pty. Ltd. -// ------------------------------------------------------------------------ -// All rights reserved. This program and the accompanying materials -// are made available under the terms of the Eclipse Public License v1.0 -// and Apache License v2.0 which accompanies this distribution. -// The Eclipse Public License is available at -// http://www.eclipse.org/legal/epl-v10.html -// The Apache License v2.0 is available at -// http://www.opensource.org/licenses/apache2.0.php -// You may elect to redistribute this code under either of these licenses. -// ======================================================================== - -package org.eclipse.jetty.http.gzip; - -import java.io.IOException; -import java.io.OutputStream; -import java.io.OutputStreamWriter; -import java.io.PrintWriter; -import java.io.UnsupportedEncodingException; -import java.util.Set; - -import javax.servlet.ServletOutputStream; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpServletResponseWrapper; - -import org.eclipse.jetty.util.StringUtil; - -/*------------------------------------------------------------ */ -/** - * Skeletal implementation of the CompressedResponseWrapper interface. - * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper - */ -public abstract class AbstractCompressedResponseWrapper extends HttpServletResponseWrapper implements CompressedResponseWrapper -{ - - public static final int DEFAULT_BUFFER_SIZE = 8192; - public static final int DEFAULT_MIN_COMPRESS_SIZE = 256; - - private Set _mimeTypes; - private int _bufferSize=DEFAULT_BUFFER_SIZE; - private int _minCompressSize=DEFAULT_MIN_COMPRESS_SIZE; - private HttpServletRequest _request; - - private PrintWriter _writer; - private CompressedStream _compressedStream; - private long _contentLength=-1; - private boolean _noCompression; - - public AbstractCompressedResponseWrapper(HttpServletRequest request, HttpServletResponse response) - { - super(response); - _request = request; - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setMimeTypes(java.util.Set) - */ - public void setMimeTypes(Set mimeTypes) - { - _mimeTypes = mimeTypes; - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setBufferSize(int) - */ - @Override - public void setBufferSize(int bufferSize) - { - _bufferSize = bufferSize; - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setMinCompressSize(int) - */ - public void setMinCompressSize(int minCompressSize) - { - _minCompressSize = minCompressSize; - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setContentType(java.lang.String) - */ - @Override - public void setContentType(String ct) - { - super.setContentType(ct); - - if (ct!=null) - { - int colon=ct.indexOf(";"); - if (colon>0) - ct=ct.substring(0,colon); - } - - if ((_compressedStream==null || _compressedStream.getOutputStream()==null) && - (_mimeTypes==null && ct!=null && ct.contains("gzip") || - _mimeTypes!=null && (ct==null||!_mimeTypes.contains(StringUtil.asciiToLowerCase(ct))))) - { - noCompression(); - } - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setStatus(int, java.lang.String) - */ - @Override - public void setStatus(int sc, String sm) - { - super.setStatus(sc,sm); - if (sc<200 || sc==204 || sc==205 || sc>=300) - noCompression(); - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setStatus(int) - */ - @Override - public void setStatus(int sc) - { - super.setStatus(sc); - if (sc<200 || sc==204 || sc==205 ||sc>=300) - noCompression(); - } - - /* ------------------------------------------------------------ */ - /** - * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setContentLength(int) - */ - @Override - public void setContentLength(int length) - { - setContentLength((long)length); - } - - protected void setContentLength(long length) - { - _contentLength=length; - if (_compressedStream!=null) - _compressedStream.setContentLength(length); - else if (_noCompression && _contentLength>=0) - { - HttpServletResponse response = (HttpServletResponse)getResponse(); - if(_contentLength _mimeTypes; + private int _bufferSize=DEFAULT_BUFFER_SIZE; + private int _minCompressSize=DEFAULT_MIN_COMPRESS_SIZE; + protected HttpServletRequest _request; - /** - * Sets the mime types. - * - * @param mimeTypes - * the new mime types - */ - public void setMimeTypes(Set mimeTypes); + private PrintWriter _writer; + private AbstractCompressedStream _compressedStream; + private long _contentLength=-1; + private boolean _noCompression; - /** - * Sets the min compress size. - * - * @param minCompressSize - * the new min compress size - */ - public void setMinCompressSize(int minCompressSize); + public CompressedResponseWrapper(HttpServletRequest request, HttpServletResponse response) + { + super(response); + _request = request; + } /* ------------------------------------------------------------ */ /** - * No compression. + * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setMimeTypes(java.util.Set) */ - public void noCompression(); + public void setMimeTypes(Set mimeTypes) + { + _mimeTypes = mimeTypes; + } + /* ------------------------------------------------------------ */ /** - * Finish. - * - * @throws IOException - * Signals that an I/O exception has occurred. + * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setBufferSize(int) */ - public void finish() throws IOException; + @Override + public void setBufferSize(int bufferSize) + { + _bufferSize = bufferSize; + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setMinCompressSize(int) + */ + public void setMinCompressSize(int minCompressSize) + { + _minCompressSize = minCompressSize; + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setContentType(java.lang.String) + */ + @Override + public void setContentType(String ct) + { + super.setContentType(ct); + + if (ct!=null) + { + int colon=ct.indexOf(";"); + if (colon>0) + ct=ct.substring(0,colon); + } + + if ((_compressedStream==null || _compressedStream.getOutputStream()==null) && + (_mimeTypes==null && ct!=null && ct.contains("gzip") || + _mimeTypes!=null && (ct==null||!_mimeTypes.contains(StringUtil.asciiToLowerCase(ct))))) + { + noCompression(); + } + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setStatus(int, java.lang.String) + */ + @Override + public void setStatus(int sc, String sm) + { + super.setStatus(sc,sm); + if (sc<200 || sc==204 || sc==205 || sc>=300) + noCompression(); + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setStatus(int) + */ + @Override + public void setStatus(int sc) + { + super.setStatus(sc); + if (sc<200 || sc==204 || sc==205 ||sc>=300) + noCompression(); + } + + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setContentLength(int) + */ + @Override + public void setContentLength(int length) + { + setContentLength((long)length); + } + + /* ------------------------------------------------------------ */ + protected void setContentLength(long length) + { + _contentLength=length; + if (_compressedStream!=null) + _compressedStream.setContentLength(length); + else if (_noCompression && _contentLength>=0) + { + HttpServletResponse response = (HttpServletResponse)getResponse(); + if(_contentLength _mimeTypes; protected int _bufferSize=8192; @@ -147,7 +149,22 @@ public class GzipFilter extends UserAgentFilter public void destroy() { } - + + /* ------------------------------------------------------------ */ + public String selectCompression(String encodingHeader) + { + // TODO, this could be a little more robust. + // prefer gzip over deflate + if (encodingHeader!=null) + { + if (encodingHeader.toLowerCase().contains(GZIP)) + return GZIP; + if (encodingHeader.toLowerCase().contains(DEFLATE)) + return DEFLATE; + } + return null; + } + /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.servlets.UserAgentFilter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) @@ -160,9 +177,8 @@ public class GzipFilter extends UserAgentFilter HttpServletResponse response=(HttpServletResponse)res; String ae = request.getHeader("accept-encoding"); - CompressionType compressionType = CompressionType.getByEncodingHeader(ae); - if (ae != null && !compressionType.equals(CompressionType.UNSUPPORTED) && !response.containsHeader("Content-Encoding") - && !HttpMethods.HEAD.equalsIgnoreCase(request.getMethod())) + String compressionType = selectCompression(request.getHeader("accept-encoding")); + if (compressionType!=null && !response.containsHeader("Content-Encoding") && !HttpMethods.HEAD.equalsIgnoreCase(request.getMethod())) { String ua = getUserAgent(request); if (isExcludedAgent(ua)) @@ -207,16 +223,44 @@ public class GzipFilter extends UserAgentFilter } } - protected CompressedResponseWrapper createWrappedResponse(HttpServletRequest request, HttpServletResponse response, CompressionType compressionType) + protected CompressedResponseWrapper createWrappedResponse(HttpServletRequest request, HttpServletResponse response, final String compressionType) { CompressedResponseWrapper wrappedResponse = null; - if (compressionType.equals(CompressionType.GZIP)) + if (compressionType.equals(GZIP)) { - wrappedResponse = new GzipResponseWrapperImpl(request,response); + wrappedResponse = new CompressedResponseWrapper(request,response) + { + @Override + protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minCompressSize) throws IOException + { + return new AbstractCompressedStream(compressionType,request,response,contentLength,bufferSize,minCompressSize) + { + @Override + protected DeflaterOutputStream createStream() throws IOException + { + return new GZIPOutputStream(_response.getOutputStream(),_bufferSize); + } + }; + } + }; } - else if (compressionType.equals(CompressionType.DEFLATE)) + else if (compressionType.equals(DEFLATE)) { - wrappedResponse = new DeflateResponseWrapperImpl(request,response); + wrappedResponse = new CompressedResponseWrapper(request,response) + { + @Override + protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minCompressSize) throws IOException + { + return new AbstractCompressedStream(compressionType,request,response,contentLength,bufferSize,minCompressSize) + { + @Override + protected DeflaterOutputStream createStream() throws IOException + { + return new DeflaterOutputStream(_response.getOutputStream()); + } + }; + } + }; } else { @@ -226,7 +270,7 @@ public class GzipFilter extends UserAgentFilter return wrappedResponse; } - private void configureWrappedResponse(CompressedResponseWrapper wrappedResponse) + protected void configureWrappedResponse(CompressedResponseWrapper wrappedResponse) { wrappedResponse.setMimeTypes(_mimeTypes); wrappedResponse.setBufferSize(_bufferSize); diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/IncludableGzipFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/IncludableGzipFilter.java index a325dee3a99..972393e1644 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/IncludableGzipFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/IncludableGzipFilter.java @@ -18,6 +18,8 @@ import java.io.OutputStream; import java.io.OutputStreamWriter; import java.io.PrintWriter; import java.io.UnsupportedEncodingException; +import java.util.zip.DeflaterOutputStream; +import java.util.zip.GZIPOutputStream; import javax.servlet.FilterConfig; import javax.servlet.ServletException; @@ -25,11 +27,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.gzip.CompressedResponseWrapper; -import org.eclipse.jetty.http.gzip.CompressedStream; -import org.eclipse.jetty.http.gzip.CompressionType; -import org.eclipse.jetty.http.gzip.DeflateStreamImpl; -import org.eclipse.jetty.http.gzip.GzipResponseWrapperImpl; -import org.eclipse.jetty.http.gzip.GzipStreamImpl; +import org.eclipse.jetty.http.gzip.AbstractCompressedStream; import org.eclipse.jetty.io.UncheckedPrintWriter; /* ------------------------------------------------------------ */ @@ -58,43 +56,75 @@ public class IncludableGzipFilter extends GzipFilter _uncheckedPrintWriter=Boolean.valueOf(tmp).booleanValue(); } + /* ------------------------------------------------------------ */ + /** + * @see org.eclipse.jetty.servlets.GzipFilter#createWrappedResponse(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.String) + */ @Override - protected CompressedResponseWrapper createWrappedResponse(HttpServletRequest request, HttpServletResponse response, CompressionType compressionType) + protected CompressedResponseWrapper createWrappedResponse(HttpServletRequest request, HttpServletResponse response, final String compressionType) { - return new IncludableResponseWrapper(request,response); + CompressedResponseWrapper wrappedResponse = null; + if (compressionType.equals(GZIP)) + { + wrappedResponse = new IncludableResponseWrapper(request,response) + { + @Override + protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minCompressSize) throws IOException + { + return new AbstractCompressedStream(compressionType,request,response,contentLength,bufferSize,minCompressSize) + { + @Override + protected DeflaterOutputStream createStream() throws IOException + { + return new GZIPOutputStream(_response.getOutputStream(),_bufferSize); + } + }; + } + }; + } + else if (compressionType.equals(DEFLATE)) + { + wrappedResponse = new IncludableResponseWrapper(request,response) + { + @Override + protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minCompressSize) throws IOException + { + return new AbstractCompressedStream(compressionType,request,response,contentLength,bufferSize,minCompressSize) + { + @Override + protected DeflaterOutputStream createStream() throws IOException + { + return new DeflaterOutputStream(_response.getOutputStream()); + } + }; + } + }; + } + else + { + throw new IllegalStateException(compressionType + " not supported"); + } + configureWrappedResponse(wrappedResponse); + return wrappedResponse; } - - public class IncludableResponseWrapper extends GzipResponseWrapperImpl + + + // Extend CompressedResponseWrapper to be able to set headers during include and to create unchecked printwriters + private abstract class IncludableResponseWrapper extends CompressedResponseWrapper { public IncludableResponseWrapper(HttpServletRequest request, HttpServletResponse response) { super(request,response); - - super.setMimeTypes(IncludableGzipFilter.this._mimeTypes); - super.setBufferSize(IncludableGzipFilter.this._bufferSize); - super.setMinCompressSize(IncludableGzipFilter.this._minGzipSize); } @Override - protected CompressedStream newCompressedStream(HttpServletRequest request, HttpServletResponse response, long contentLength, int bufferSize, - int minGzipSize) throws IOException + public void setHeader(String name,String value) { - String encodingHeader = request.getHeader("accept-encoding"); - CompressionType compressionType = CompressionType.getByEncodingHeader(encodingHeader); - if (compressionType.equals(CompressionType.GZIP)) - { - return new IncludableGzipStream(request,response,contentLength,bufferSize,minGzipSize); - } - else if (compressionType.equals(CompressionType.DEFLATE)) - { - return new IncludableDeflateStream(request,response,contentLength,bufferSize,minGzipSize); - } - else - { - throw new IllegalStateException(compressionType.name() + " not supported."); - } + super.setHeader(name,value); + HttpServletResponse response = (HttpServletResponse)getResponse(); + if (!response.containsHeader(name)) + response.setHeader("org.eclipse.jetty.server.include."+name,value);; } - @Override protected PrintWriter newWriter(OutputStream out, String encoding) throws UnsupportedEncodingException { @@ -104,52 +134,4 @@ public class IncludableGzipFilter extends GzipFilter } } - public class IncludableGzipStream extends GzipStreamImpl - { - public IncludableGzipStream(HttpServletRequest request, HttpServletResponse response, long contentLength, int bufferSize, int minGzipSize) - throws IOException - { - super(request,response,contentLength,bufferSize,minGzipSize); - } - - @Override - protected boolean setContentEncoding() - { - if (_request.getAttribute("javax.servlet.include.request_uri") != null) - { - _response.setHeader("org.eclipse.jetty.server.include.Content-Encoding","gzip"); - } - else - { - _response.setHeader("Content-Encoding","gzip"); - } - - return _response.containsHeader("Content-Encoding"); - } - } - - public class IncludableDeflateStream extends DeflateStreamImpl - { - public IncludableDeflateStream(HttpServletRequest request, HttpServletResponse response, long contentLength, int bufferSize, int minGzipSize) - throws IOException - { - super(request,response,contentLength,bufferSize,minGzipSize); - } - - @Override - protected boolean setContentEncoding() - { - if (_request.getAttribute("javax.servlet.include.request_uri") != null) - { - _response.setHeader("org.eclipse.jetty.server.include.Content-Encoding","deflate"); - } - else - { - _response.setHeader("Content-Encoding","deflate"); - } - - return _response.containsHeader("Content-Encoding"); - } - } - } diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterContentLengthTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterContentLengthTest.java index b636583c716..c752591bc25 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterContentLengthTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterContentLengthTest.java @@ -6,8 +6,7 @@ import java.util.List; import javax.servlet.Servlet; import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.http.gzip.CompressionType; -import org.eclipse.jetty.http.gzip.GzipResponseWrapperImpl; +import org.eclipse.jetty.http.gzip.CompressedResponseWrapper; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlets.gzip.GzipTester; import org.eclipse.jetty.servlets.gzip.TestServletLengthStreamTypeWrite; @@ -49,29 +48,29 @@ public class GzipFilterContentLengthTest { return Arrays.asList(new Object[][] { - { TestServletLengthStreamTypeWrite.class, CompressionType.GZIP }, - { TestServletLengthTypeStreamWrite.class, CompressionType.GZIP }, - { TestServletStreamLengthTypeWrite.class, CompressionType.GZIP }, - { TestServletStreamTypeLengthWrite.class, CompressionType.GZIP }, - { TestServletTypeLengthStreamWrite.class, CompressionType.GZIP }, - { TestServletTypeStreamLengthWrite.class, CompressionType.GZIP }, - { TestServletLengthStreamTypeWrite.class, CompressionType.DEFLATE }, - { TestServletLengthTypeStreamWrite.class, CompressionType.DEFLATE }, - { TestServletStreamLengthTypeWrite.class, CompressionType.DEFLATE }, - { TestServletStreamTypeLengthWrite.class, CompressionType.DEFLATE }, - { TestServletTypeLengthStreamWrite.class, CompressionType.DEFLATE }, - { TestServletTypeStreamLengthWrite.class, CompressionType.DEFLATE } + { TestServletLengthStreamTypeWrite.class, GzipFilter.GZIP }, + { TestServletLengthTypeStreamWrite.class, GzipFilter.GZIP }, + { TestServletStreamLengthTypeWrite.class, GzipFilter.GZIP }, + { TestServletStreamTypeLengthWrite.class, GzipFilter.GZIP }, + { TestServletTypeLengthStreamWrite.class, GzipFilter.GZIP }, + { TestServletTypeStreamLengthWrite.class, GzipFilter.GZIP }, + { TestServletLengthStreamTypeWrite.class, GzipFilter.DEFLATE }, + { TestServletLengthTypeStreamWrite.class, GzipFilter.DEFLATE }, + { TestServletStreamLengthTypeWrite.class, GzipFilter.DEFLATE }, + { TestServletStreamTypeLengthWrite.class, GzipFilter.DEFLATE }, + { TestServletTypeLengthStreamWrite.class, GzipFilter.DEFLATE }, + { TestServletTypeStreamLengthWrite.class, GzipFilter.DEFLATE } }); } - private static final int LARGE = GzipResponseWrapperImpl.DEFAULT_BUFFER_SIZE * 8; - private static final int MEDIUM = GzipResponseWrapperImpl.DEFAULT_BUFFER_SIZE; - private static final int SMALL = GzipResponseWrapperImpl.DEFAULT_BUFFER_SIZE / 4; - private static final int TINY = GzipResponseWrapperImpl.DEFAULT_MIN_COMPRESS_SIZE/ 2; + private static final int LARGE = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE * 8; + private static final int MEDIUM = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE; + private static final int SMALL = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE / 4; + private static final int TINY = CompressedResponseWrapper.DEFAULT_MIN_COMPRESS_SIZE/ 2; - private CompressionType compressionType; + private String compressionType; - public GzipFilterContentLengthTest(Class testServlet, CompressionType compressionType) + public GzipFilterContentLengthTest(Class testServlet, String compressionType) { this.testServlet = testServlet; this.compressionType = compressionType; diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java index 996e26a0547..a890b96b628 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultNoRecompressTest.java @@ -5,7 +5,6 @@ import java.io.IOException; import java.util.Arrays; import java.util.List; -import org.eclipse.jetty.http.gzip.CompressionType; import org.eclipse.jetty.servlet.DefaultServlet; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlets.gzip.GzipTester; @@ -32,41 +31,41 @@ public class GzipFilterDefaultNoRecompressTest return Arrays.asList(new Object[][] { // Some already compressed files - { "test_quotes.gz", "application/gzip", CompressionType.GZIP }, - { "test_quotes.bz2", "application/bzip2", CompressionType.GZIP }, - { "test_quotes.zip", "application/zip", CompressionType.GZIP }, - { "test_quotes.rar", "application/octet-stream", CompressionType.GZIP }, + { "test_quotes.gz", "application/gzip", GzipFilter.GZIP }, + { "test_quotes.bz2", "application/bzip2", GzipFilter.GZIP }, + { "test_quotes.zip", "application/zip", GzipFilter.GZIP }, + { "test_quotes.rar", "application/octet-stream", GzipFilter.GZIP }, // Some images (common first) - { "jetty_logo.png", "image/png", CompressionType.GZIP }, - { "jetty_logo.gif", "image/gif", CompressionType.GZIP }, - { "jetty_logo.jpeg", "image/jpeg", CompressionType.GZIP }, - { "jetty_logo.jpg", "image/jpeg", CompressionType.GZIP }, + { "jetty_logo.png", "image/png", GzipFilter.GZIP }, + { "jetty_logo.gif", "image/gif", GzipFilter.GZIP }, + { "jetty_logo.jpeg", "image/jpeg", GzipFilter.GZIP }, + { "jetty_logo.jpg", "image/jpeg", GzipFilter.GZIP }, // Lesser encountered images (usually found being requested from non-browser clients) - { "jetty_logo.bmp", "image/bmp", CompressionType.GZIP }, - { "jetty_logo.tga", "application/tga", CompressionType.GZIP }, - { "jetty_logo.tif", "image/tiff", CompressionType.GZIP }, - { "jetty_logo.tiff", "image/tiff", CompressionType.GZIP }, - { "jetty_logo.xcf", "image/xcf", CompressionType.GZIP }, - { "jetty_logo.jp2", "image/jpeg2000", CompressionType.GZIP }, + { "jetty_logo.bmp", "image/bmp", GzipFilter.GZIP }, + { "jetty_logo.tga", "application/tga", GzipFilter.GZIP }, + { "jetty_logo.tif", "image/tiff", GzipFilter.GZIP }, + { "jetty_logo.tiff", "image/tiff", GzipFilter.GZIP }, + { "jetty_logo.xcf", "image/xcf", GzipFilter.GZIP }, + { "jetty_logo.jp2", "image/jpeg2000", GzipFilter.GZIP }, // Same tests again for deflate // Some already compressed files - { "test_quotes.gz", "application/gzip", CompressionType.DEFLATE }, - { "test_quotes.bz2", "application/bzip2", CompressionType.DEFLATE }, - { "test_quotes.zip", "application/zip", CompressionType.DEFLATE }, - { "test_quotes.rar", "application/octet-stream", CompressionType.DEFLATE }, + { "test_quotes.gz", "application/gzip", GzipFilter.DEFLATE }, + { "test_quotes.bz2", "application/bzip2", GzipFilter.DEFLATE }, + { "test_quotes.zip", "application/zip", GzipFilter.DEFLATE }, + { "test_quotes.rar", "application/octet-stream", GzipFilter.DEFLATE }, // Some images (common first) - { "jetty_logo.png", "image/png", CompressionType.DEFLATE }, - { "jetty_logo.gif", "image/gif", CompressionType.DEFLATE }, - { "jetty_logo.jpeg", "image/jpeg", CompressionType.DEFLATE }, - { "jetty_logo.jpg", "image/jpeg", CompressionType.DEFLATE }, + { "jetty_logo.png", "image/png", GzipFilter.DEFLATE }, + { "jetty_logo.gif", "image/gif", GzipFilter.DEFLATE }, + { "jetty_logo.jpeg", "image/jpeg", GzipFilter.DEFLATE }, + { "jetty_logo.jpg", "image/jpeg", GzipFilter.DEFLATE }, // Lesser encountered images (usually found being requested from non-browser clients) - { "jetty_logo.bmp", "image/bmp", CompressionType.DEFLATE }, - { "jetty_logo.tga", "application/tga", CompressionType.DEFLATE }, - { "jetty_logo.tif", "image/tiff", CompressionType.DEFLATE }, - { "jetty_logo.tiff", "image/tiff", CompressionType.DEFLATE }, - { "jetty_logo.xcf", "image/xcf", CompressionType.DEFLATE }, - { "jetty_logo.jp2", "image/jpeg2000", CompressionType.DEFLATE } }); + { "jetty_logo.bmp", "image/bmp", GzipFilter.DEFLATE }, + { "jetty_logo.tga", "application/tga", GzipFilter.DEFLATE }, + { "jetty_logo.tif", "image/tiff", GzipFilter.DEFLATE }, + { "jetty_logo.tiff", "image/tiff", GzipFilter.DEFLATE }, + { "jetty_logo.xcf", "image/xcf", GzipFilter.DEFLATE }, + { "jetty_logo.jp2", "image/jpeg2000", GzipFilter.DEFLATE } }); } @Rule @@ -74,9 +73,9 @@ public class GzipFilterDefaultNoRecompressTest private String alreadyCompressedFilename; private String expectedContentType; - private CompressionType compressionType; + private String compressionType; - public GzipFilterDefaultNoRecompressTest(String testFilename, String expectedContentType, CompressionType compressionType) + public GzipFilterDefaultNoRecompressTest(String testFilename, String expectedContentType, String compressionType) { this.alreadyCompressedFilename = testFilename; this.expectedContentType = expectedContentType; diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java index 47f637150cd..6c6faba5198 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipFilterDefaultTest.java @@ -10,8 +10,7 @@ import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.eclipse.jetty.http.HttpStatus; -import org.eclipse.jetty.http.gzip.CompressionType; -import org.eclipse.jetty.http.gzip.GzipResponseWrapperImpl; +import org.eclipse.jetty.http.gzip.CompressedResponseWrapper; import org.eclipse.jetty.servlet.DefaultServlet; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlets.gzip.GzipTester; @@ -29,20 +28,20 @@ import org.junit.runners.Parameterized.Parameters; public class GzipFilterDefaultTest { @Parameters - public static Collection data() + public static Collection data() { - CompressionType[][] data = new CompressionType[][] + String[][] data = new String[][] { - { CompressionType.GZIP }, - { CompressionType.DEFLATE } + { GzipFilter.GZIP }, + { GzipFilter.DEFLATE } }; return Arrays.asList(data); } - private CompressionType compressionType; + private String compressionType; - public GzipFilterDefaultTest(CompressionType compressionType) + public GzipFilterDefaultTest(String compressionType) { this.compressionType = compressionType; } @@ -80,7 +79,7 @@ public class GzipFilterDefaultTest GzipTester tester = new GzipTester(testingdir, compressionType); // Test content that is smaller than the buffer. - int filesize = GzipResponseWrapperImpl.DEFAULT_BUFFER_SIZE / 4; + int filesize = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE / 4; tester.prepareServerFile("file.txt",filesize); FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class); @@ -103,7 +102,7 @@ public class GzipFilterDefaultTest GzipTester tester = new GzipTester(testingdir, compressionType); // Test content that is smaller than the buffer. - int filesize = GzipResponseWrapperImpl.DEFAULT_BUFFER_SIZE * 4; + int filesize = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE * 4; tester.prepareServerFile("file.txt",filesize); FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class); @@ -126,7 +125,7 @@ public class GzipFilterDefaultTest GzipTester tester = new GzipTester(testingdir, compressionType); // Test content that is smaller than the buffer. - int filesize = GzipResponseWrapperImpl.DEFAULT_BUFFER_SIZE * 4; + int filesize = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE * 4; tester.prepareServerFile("file.mp3",filesize); FilterHolder holder = tester.setContentServlet(org.eclipse.jetty.servlet.DefaultServlet.class); @@ -173,7 +172,7 @@ public class GzipFilterDefaultTest holder.setInitParameter("excludedAgents", "foo"); tester.setUserAgent("foo"); - int filesize = GzipResponseWrapperImpl.DEFAULT_BUFFER_SIZE * 4; + int filesize = CompressedResponseWrapper.DEFAULT_BUFFER_SIZE * 4; tester.prepareServerFile("file.txt",filesize); try diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipWithPipeliningTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipWithPipeliningTest.java index 65a66898fc4..4144b0702d1 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipWithPipeliningTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/GzipWithPipeliningTest.java @@ -18,7 +18,6 @@ import java.util.regex.Pattern; import java.util.zip.GZIPInputStream; import java.util.zip.InflaterInputStream; -import org.eclipse.jetty.http.gzip.CompressionType; import org.eclipse.jetty.server.Connector; import org.eclipse.jetty.server.Server; import org.eclipse.jetty.servlet.DefaultServlet; @@ -50,10 +49,10 @@ public class GzipWithPipeliningTest // Test different Content-Encoding header combinations. So implicitly testing that gzip is preferred oder deflate String[][] data = new String[][] { - { CompressionType.GZIP.getEncodingHeader() }, - { CompressionType.DEFLATE.getEncodingHeader() + ", " + CompressionType.GZIP.getEncodingHeader() }, - { CompressionType.GZIP.getEncodingHeader() + ", " + CompressionType.DEFLATE.getEncodingHeader() }, - { CompressionType.DEFLATE.getEncodingHeader() } + { GzipFilter.GZIP }, + { GzipFilter.DEFLATE + ", " + GzipFilter.GZIP }, + { GzipFilter.GZIP + ", " + GzipFilter.DEFLATE }, + { GzipFilter.DEFLATE } }; return Arrays.asList(data); @@ -137,7 +136,7 @@ public class GzipWithPipeliningTest respHeader = client.readResponseHeader(); System.out.println("Response Header #1 --\n" + respHeader); - String expectedEncodingHeader = encodingHeader.equals(CompressionType.DEFLATE.getEncodingHeader()) ? CompressionType.DEFLATE.getEncodingHeader() : CompressionType.GZIP.getEncodingHeader(); + String expectedEncodingHeader = encodingHeader.equals(GzipFilter.DEFLATE) ? GzipFilter.DEFLATE : GzipFilter.GZIP; assertThat("Content-Encoding should be gzipped",respHeader,containsString("Content-Encoding: " + expectedEncodingHeader + "\r\n")); assertThat("Transfer-Encoding should be chunked",respHeader,containsString("Transfer-Encoding: chunked\r\n")); @@ -182,7 +181,7 @@ public class GzipWithPipeliningTest IO.close(rawOutputStream); FileInputStream rawInputStream = new FileInputStream(rawOutputFile); InputStream uncompressedStream = null; - if (CompressionType.DEFLATE.getEncodingHeader().equals(encodingHeader)) + if (GzipFilter.DEFLATE.equals(encodingHeader)) { uncompressedStream = new InflaterInputStream(rawInputStream); } diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterMinSizeTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterMinSizeTest.java index e12abff667a..6d37b0f1e6d 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterMinSizeTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterMinSizeTest.java @@ -18,7 +18,6 @@ import java.util.Collection; import javax.servlet.Servlet; -import org.eclipse.jetty.http.gzip.CompressionType; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlets.gzip.GzipTester; import org.eclipse.jetty.servlets.gzip.TestMinGzipSizeServlet; @@ -39,18 +38,18 @@ import org.junit.runners.Parameterized.Parameters; public class IncludableGzipFilterMinSizeTest { @Parameters - public static Collection data() + public static Collection data() { - CompressionType[][] data = new CompressionType[][] + String[][] data = new String[][] { - { CompressionType.GZIP }, - { CompressionType.DEFLATE } + { GzipFilter.GZIP }, + { GzipFilter.DEFLATE } }; return Arrays.asList(data); } - public IncludableGzipFilterMinSizeTest(CompressionType compressionType) + public IncludableGzipFilterMinSizeTest(String compressionType) { this.compressionType = compressionType; } @@ -58,7 +57,7 @@ public class IncludableGzipFilterMinSizeTest @Rule public TestingDir testdir = new TestingDir(); - private CompressionType compressionType; + private String compressionType; private Class testServlet = TestMinGzipSizeServlet.class; @Test diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterTest.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterTest.java index 49459e4e2ef..9872c198014 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterTest.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/IncludableGzipFilterTest.java @@ -29,7 +29,6 @@ import java.util.zip.InflaterInputStream; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.http.gzip.CompressionType; import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.testing.HttpTester; @@ -48,12 +47,12 @@ import org.junit.runners.Parameterized.Parameters; public class IncludableGzipFilterTest { @Parameters - public static Collection data() + public static Collection data() { - CompressionType[][] data = new CompressionType[][] + String[][] data = new String[][] { - { CompressionType.GZIP }, - { CompressionType.DEFLATE } + { GzipFilter.GZIP }, + { GzipFilter.DEFLATE } }; return Arrays.asList(data); @@ -77,9 +76,9 @@ public class IncludableGzipFilterTest "et cursus magna. Donec orci enim, molestie a lobortis eu, imperdiet vitae neque."; private ServletTester tester; - private CompressionType compressionType; + private String compressionType; - public IncludableGzipFilterTest(CompressionType compressionType) + public IncludableGzipFilterTest(String compressionType) { this.compressionType = compressionType; } @@ -121,7 +120,7 @@ public class IncludableGzipFilterTest request.setMethod("GET"); request.setVersion("HTTP/1.0"); request.setHeader("Host","tester"); - request.setHeader("accept-encoding", compressionType.getEncodingHeader()); + request.setHeader("accept-encoding", compressionType); request.setURI("/context/file.txt"); ByteArrayBuffer reqsBuff = new ByteArrayBuffer(request.generate().getBytes()); @@ -129,16 +128,16 @@ public class IncludableGzipFilterTest response.parse(respBuff.asArray()); assertTrue(response.getMethod()==null); - assertTrue(response.getHeader("Content-Encoding").equalsIgnoreCase(compressionType.getEncodingHeader())); + assertTrue(response.getHeader("Content-Encoding").equalsIgnoreCase(compressionType)); assertEquals(HttpServletResponse.SC_OK,response.getStatus()); InputStream testIn = null; ByteArrayInputStream compressedResponseStream = new ByteArrayInputStream(response.getContentBytes()); - if (compressionType.equals(CompressionType.GZIP)) + if (compressionType.equals(GzipFilter.GZIP)) { testIn = new GZIPInputStream(compressedResponseStream); } - else if (compressionType.equals(CompressionType.DEFLATE)) + else if (compressionType.equals(GzipFilter.DEFLATE)) { testIn = new InflaterInputStream(compressedResponseStream); } diff --git a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java index 91cc374c893..36cec8037b9 100644 --- a/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java +++ b/jetty-servlets/src/test/java/org/eclipse/jetty/servlets/gzip/GzipTester.java @@ -25,7 +25,6 @@ import java.util.zip.InflaterInputStream; import javax.servlet.Servlet; import javax.servlet.http.HttpServletResponse; -import org.eclipse.jetty.http.gzip.CompressionType; import org.eclipse.jetty.io.ByteArrayBuffer; import org.eclipse.jetty.servlet.FilterHolder; import org.eclipse.jetty.servlet.ServletHolder; @@ -44,9 +43,9 @@ public class GzipTester private String userAgent = null; private ServletTester servletTester; private TestingDir testdir; - private CompressionType compressionType; + private String compressionType; - public GzipTester(TestingDir testingdir, CompressionType compressionType) + public GzipTester(TestingDir testingdir, String compressionType) { this.testdir = testingdir; this.compressionType = compressionType; @@ -68,7 +67,7 @@ public class GzipTester request.setMethod("GET"); request.setVersion("HTTP/1.0"); request.setHeader("Host","tester"); - request.setHeader("Accept-Encoding",compressionType.getEncodingHeader()); + request.setHeader("Accept-Encoding",compressionType); if (this.userAgent != null) request.setHeader("User-Agent", this.userAgent); request.setURI("/context/" + requestedFilename); @@ -83,7 +82,7 @@ public class GzipTester Assert.assertThat("Response.method",response.getMethod(),nullValue()); Assert.assertThat("Response.status",response.getStatus(),is(HttpServletResponse.SC_OK)); Assert.assertThat("Response.header[Content-Length]",response.getHeader("Content-Length"),notNullValue()); - Assert.assertThat("Response.header[Content-Encoding]",response.getHeader("Content-Encoding"),containsString(compressionType.getEncodingHeader())); + Assert.assertThat("Response.header[Content-Encoding]",response.getHeader("Content-Encoding"),containsString(compressionType)); // Assert that the decompressed contents are what we expect. File serverFile = testdir.getFile(serverFilename); @@ -96,11 +95,11 @@ public class GzipTester try { bais = new ByteArrayInputStream(response.getContentBytes()); - if (compressionType.equals(CompressionType.GZIP)) + if (compressionType.equals(GzipFilter.GZIP)) { in = new GZIPInputStream(bais); } - else if (compressionType.equals(CompressionType.DEFLATE)) + else if (compressionType.equals(GzipFilter.DEFLATE)) { in = new InflaterInputStream(bais); } @@ -142,7 +141,7 @@ public class GzipTester request.setMethod("GET"); request.setVersion("HTTP/1.0"); request.setHeader("Host","tester"); - request.setHeader("Accept-Encoding",compressionType.getEncodingHeader()); + request.setHeader("Accept-Encoding",compressionType); if (this.userAgent != null) request.setHeader("User-Agent", this.userAgent); request.setURI("/context/" + requestedFilename); @@ -229,7 +228,7 @@ public class GzipTester request.setMethod("GET"); request.setVersion("HTTP/1.0"); request.setHeader("Host","tester"); - request.setHeader("Accept-Encoding",compressionType.getEncodingHeader()); + request.setHeader("Accept-Encoding",compressionType); if (this.userAgent != null) request.setHeader("User-Agent", this.userAgent); if (filename == null) @@ -252,7 +251,7 @@ public class GzipTester int serverLength = Integer.parseInt(response.getHeader("Content-Length")); Assert.assertThat("Response.header[Content-Length]",serverLength,is(expectedFilesize)); } - Assert.assertThat("Response.header[Content-Encoding]",response.getHeader("Content-Encoding"),not(containsString(compressionType.getEncodingHeader()))); + Assert.assertThat("Response.header[Content-Encoding]",response.getHeader("Content-Encoding"),not(containsString(compressionType))); // Assert that the contents are what we expect. if (filename != null) From 28de69760a768ee537191e5631cccc76fa3ba3bb Mon Sep 17 00:00:00 2001 From: Jan Bartel Date: Mon, 2 Apr 2012 12:35:12 +1000 Subject: [PATCH 3/5] JETTY-1504 HttpServletResponseWrapper ignored when using asyncContext? --- .../jetty/server/AsyncContinuation.java | 1 + .../jetty/servlet/AsyncContextTest.java | 24 ++++++++++++++++--- 2 files changed, 22 insertions(+), 3 deletions(-) diff --git a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java index 7c68dfa3793..382d0ed12c8 100644 --- a/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java +++ b/jetty-server/src/main/java/org/eclipse/jetty/server/AsyncContinuation.java @@ -819,6 +819,7 @@ public class AsyncContinuation implements AsyncContext, Continuation { synchronized (this) { + _responseWrapped=!(response instanceof Response); doSuspend(context,request,response); if (request instanceof HttpServletRequest) { diff --git a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextTest.java b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextTest.java index bf38fb92b46..f10d24fa93a 100644 --- a/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextTest.java +++ b/jetty-servlet/src/test/java/org/eclipse/jetty/servlet/AsyncContextTest.java @@ -3,6 +3,7 @@ package org.eclipse.jetty.servlet; import static org.hamcrest.Matchers.equalTo; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertThat; +import static org.junit.Assert.assertTrue; import java.io.BufferedReader; import java.io.IOException; @@ -12,6 +13,7 @@ import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpServletResponseWrapper; import junit.framework.Assert; @@ -223,17 +225,20 @@ public class AsyncContextTest } else { + boolean wrapped = false; final AsyncContext asyncContext; if (request.getParameter("dispatchRequestResponse") != null) { - asyncContext = request.startAsync(request,response); + wrapped = true; + asyncContext = request.startAsync(request, new Wrapper(response)); } else { asyncContext = request.startAsync(); } - new Thread(new DispatchingRunnable(asyncContext)).start(); + + new Thread(new DispatchingRunnable(asyncContext, wrapped)).start(); } } } @@ -241,14 +246,18 @@ public class AsyncContextTest private class DispatchingRunnable implements Runnable { private AsyncContext asyncContext; + private boolean wrapped; - public DispatchingRunnable(AsyncContext asyncContext) + public DispatchingRunnable(AsyncContext asyncContext, boolean wrapped) { this.asyncContext = asyncContext; + this.wrapped = wrapped; } public void run() { + if (wrapped) + assertTrue(asyncContext.getResponse() instanceof Wrapper); asyncContext.dispatch(); } } @@ -347,4 +356,13 @@ public class AsyncContextTest } } + private class Wrapper extends HttpServletResponseWrapper + { + public Wrapper (HttpServletResponse response) + { + super(response); + } + } + + } From cc1bef6f2e43f120e417e9771976e992ba73d7f0 Mon Sep 17 00:00:00 2001 From: Greg Wilkins Date: Mon, 2 Apr 2012 18:18:39 +1000 Subject: [PATCH 4/5] 375594 fixed SSL tests so they are not order dependent --- .../eclipse/jetty/server/ssl/SSLEngineTest.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SSLEngineTest.java b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SSLEngineTest.java index 2fcb497d05f..df08d35508c 100644 --- a/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SSLEngineTest.java +++ b/jetty-server/src/test/java/org/eclipse/jetty/server/ssl/SSLEngineTest.java @@ -99,8 +99,6 @@ public class SSLEngineTest connector.setRequestHeaderSize(512); server.setConnectors(new Connector[]{connector }); - server.setHandler(new HelloWorldHandler()); - server.start(); } @AfterClass @@ -109,10 +107,15 @@ public class SSLEngineTest server.stop(); server.join(); } + @Test public void testBigResponse() throws Exception { + server.stop(); + server.setHandler(new HelloWorldHandler()); + server.start(); + SSLContext ctx=SSLContext.getInstance("TLS"); ctx.init(null,SslContextFactory.TRUST_ALL_CERTS,new java.security.SecureRandom()); @@ -123,7 +126,7 @@ public class SSLEngineTest String request = "GET /?dump=102400 HTTP/1.1\r\n"+ - "Host: localhost:8080\r\n"+ + "Host: localhost:"+port+"\r\n"+ "Connection: close\r\n"+ "\r\n"; @@ -138,6 +141,10 @@ public class SSLEngineTest @Test public void testRequestJettyHttps() throws Exception { + server.stop(); + server.setHandler(new HelloWorldHandler()); + server.start(); + final int loops=10; final int numConns=10; @@ -204,8 +211,7 @@ public class SSLEngineTest @Test public void testServletPost() throws Exception { - stopServer(); - + server.stop(); StreamHandler handler = new StreamHandler(); server.setHandler(handler); server.start(); @@ -308,6 +314,7 @@ public class SSLEngineTest { ServletOutputStream out=response.getOutputStream(); byte[] buf = new byte[Integer.valueOf(request.getParameter("dump"))]; + // System.err.println("DUMP "+buf.length); for (int i=0;i Date: Mon, 2 Apr 2012 13:41:36 +0200 Subject: [PATCH 5/5] 375692: cosmetic changes to get rid of warnings, etc. Change-Id: Id4d76a7f6e5bd989505e5233af73d5526b8e7c1f --- .../http/gzip/AbstractCompressedStream.java | 4 +-- .../eclipse/jetty/servlets/GzipFilter.java | 31 +++++++++---------- 2 files changed, 16 insertions(+), 19 deletions(-) diff --git a/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/AbstractCompressedStream.java b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/AbstractCompressedStream.java index f879610be29..77ac1fe41d0 100644 --- a/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/AbstractCompressedStream.java +++ b/jetty-http/src/main/java/org/eclipse/jetty/http/gzip/AbstractCompressedStream.java @@ -13,8 +13,6 @@ package org.eclipse.jetty.http.gzip; -import java.io.Closeable; -import java.io.Flushable; import java.io.IOException; import java.io.OutputStream; import java.io.OutputStreamWriter; @@ -32,7 +30,7 @@ import org.eclipse.jetty.util.ByteArrayOutputStream2; /** * Skeletal implementation of a CompressedStream. This class adds compression features to a ServletOutputStream and takes care of setting response headers, etc. * Major work and configuration is done here. Subclasses using different kinds of compression only have to implement the abstract methods doCompress() and - * setContentEncoding() using the desired compression and setting the appropiate Content-Encoding header string. + * setContentEncoding() using the desired compression and setting the appropriate Content-Encoding header string. */ public abstract class AbstractCompressedStream extends ServletOutputStream { diff --git a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java index 40564cae0e8..2f4128da184 100644 --- a/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java +++ b/jetty-servlets/src/main/java/org/eclipse/jetty/servlets/GzipFilter.java @@ -150,21 +150,6 @@ public class GzipFilter extends UserAgentFilter { } - /* ------------------------------------------------------------ */ - public String selectCompression(String encodingHeader) - { - // TODO, this could be a little more robust. - // prefer gzip over deflate - if (encodingHeader!=null) - { - if (encodingHeader.toLowerCase().contains(GZIP)) - return GZIP; - if (encodingHeader.toLowerCase().contains(DEFLATE)) - return DEFLATE; - } - return null; - } - /* ------------------------------------------------------------ */ /** * @see org.eclipse.jetty.servlets.UserAgentFilter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain) @@ -176,7 +161,6 @@ public class GzipFilter extends UserAgentFilter HttpServletRequest request=(HttpServletRequest)req; HttpServletResponse response=(HttpServletResponse)res; - String ae = request.getHeader("accept-encoding"); String compressionType = selectCompression(request.getHeader("accept-encoding")); if (compressionType!=null && !response.containsHeader("Content-Encoding") && !HttpMethods.HEAD.equalsIgnoreCase(request.getMethod())) { @@ -223,6 +207,21 @@ public class GzipFilter extends UserAgentFilter } } + /* ------------------------------------------------------------ */ + private String selectCompression(String encodingHeader) + { + // TODO, this could be a little more robust. + // prefer gzip over deflate + if (encodingHeader!=null) + { + if (encodingHeader.toLowerCase().contains(GZIP)) + return GZIP; + else if (encodingHeader.toLowerCase().contains(DEFLATE)) + return DEFLATE; + } + return null; + } + protected CompressedResponseWrapper createWrappedResponse(HttpServletRequest request, HttpServletResponse response, final String compressionType) { CompressedResponseWrapper wrappedResponse = null;