375692: GzipFilter support for deflate

Change-Id: I4a42d750cfbbb61078adafa1e2bcbc1973198dca
This commit is contained in:
Thomas Becker 2012-03-30 11:02:44 +02:00
parent 85ade6ae86
commit 2278d27235
21 changed files with 1332 additions and 681 deletions

View File

@ -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<String> _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<String> 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<Integer.MAX_VALUE)
@ -166,15 +161,16 @@ public class GzipResponseWrapper extends HttpServletResponseWrapper
/* ------------------------------------------------------------ */
/**
* @see javax.servlet.http.HttpServletResponseWrapper#addHeader(java.lang.String, java.lang.String)
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#addHeader(java.lang.String, java.lang.String)
*/
@Override
public void addHeader(String name, String value)
{
if ("content-length".equalsIgnoreCase(name))
{
_contentLength=Long.parseLong(value);
if (_gzStream!=null)
_gzStream.setContentLength(_contentLength);
if (_compressedStream!=null)
_compressedStream.setContentLength(_contentLength);
}
else if ("content-type".equalsIgnoreCase(name))
{
@ -185,7 +181,7 @@ public class GzipResponseWrapper extends HttpServletResponseWrapper
super.addHeader(name,value);
if (!isCommitted())
{
noGzip();
noCompression();
}
}
else
@ -194,8 +190,119 @@ public class GzipResponseWrapper extends HttpServletResponseWrapper
/* ------------------------------------------------------------ */
/**
* @see javax.servlet.http.HttpServletResponseWrapper#setHeader(java.lang.String, java.lang.String)
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#flushBuffer()
*/
@Override
public void flushBuffer() throws IOException
{
if (_writer!=null)
_writer.flush();
if (_compressedStream!=null)
_compressedStream.finish();
else
getResponse().flushBuffer();
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#reset()
*/
@Override
public void reset()
{
super.reset();
if (_compressedStream!=null)
_compressedStream.resetBuffer();
_writer=null;
_compressedStream=null;
_noCompression=false;
_contentLength=-1;
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#resetBuffer()
*/
@Override
public void resetBuffer()
{
super.resetBuffer();
if (_compressedStream!=null)
_compressedStream.resetBuffer();
_writer=null;
_compressedStream=null;
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#sendError(int, java.lang.String)
*/
@Override
public void sendError(int sc, String msg) throws IOException
{
resetBuffer();
super.sendError(sc,msg);
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#sendError(int)
*/
@Override
public void sendError(int sc) throws IOException
{
resetBuffer();
super.sendError(sc);
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#sendRedirect(java.lang.String)
*/
@Override
public void sendRedirect(String location) throws IOException
{
resetBuffer();
super.sendRedirect(location);
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#noCompression()
*/
public void noCompression()
{
_noCompression=true;
if (_compressedStream!=null)
{
try
{
_compressedStream.doNotCompress();
}
catch (IOException e)
{
throw new IllegalStateException(e);
}
}
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#finish()
*/
public void finish() throws IOException
{
if (_writer!=null && !_compressedStream.isClosed())
_writer.flush();
if (_compressedStream!=null)
_compressedStream.finish();
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setHeader(java.lang.String, java.lang.String)
*/
@Override
public void setHeader(String name, String value)
{
if ("content-length".equalsIgnoreCase(name))
@ -211,197 +318,77 @@ public class GzipResponseWrapper extends HttpServletResponseWrapper
super.setHeader(name,value);
if (!isCommitted())
{
noGzip();
noCompression();
}
}
else
super.setHeader(name,value);
}
/* ------------------------------------------------------------ */
/**
* @see javax.servlet.http.HttpServletResponseWrapper#setIntHeader(java.lang.String, int)
*/
public void setIntHeader(String name, int value)
{
if ("content-length".equalsIgnoreCase(name))
{
_contentLength=value;
if (_gzStream!=null)
_gzStream.setContentLength(_contentLength);
}
else
super.setIntHeader(name,value);
}
/* ------------------------------------------------------------ */
/**
* @see javax.servlet.ServletResponseWrapper#flushBuffer()
*/
public void flushBuffer() throws IOException
{
if (_writer!=null)
_writer.flush();
if (_gzStream!=null)
_gzStream.finish();
else
getResponse().flushBuffer();
}
/* ------------------------------------------------------------ */
/**
* @see javax.servlet.ServletResponseWrapper#reset()
*/
public void reset()
{
super.reset();
if (_gzStream!=null)
_gzStream.resetBuffer();
_writer=null;
_gzStream=null;
_noGzip=false;
_contentLength=-1;
}
/* ------------------------------------------------------------ */
/**
* @see javax.servlet.ServletResponseWrapper#resetBuffer()
*/
public void resetBuffer()
{
super.resetBuffer();
if (_gzStream!=null)
_gzStream.resetBuffer();
_writer=null;
_gzStream=null;
}
/* ------------------------------------------------------------ */
/**
* @see javax.servlet.http.HttpServletResponseWrapper#sendError(int, java.lang.String)
*/
public void sendError(int sc, String msg) throws IOException
{
resetBuffer();
super.sendError(sc,msg);
}
/* ------------------------------------------------------------ */
/**
* @see javax.servlet.http.HttpServletResponseWrapper#sendError(int)
*/
public void sendError(int sc) throws IOException
{
resetBuffer();
super.sendError(sc);
}
/* ------------------------------------------------------------ */
/**
* @see javax.servlet.http.HttpServletResponseWrapper#sendRedirect(java.lang.String)
*/
public void sendRedirect(String location) throws IOException
{
resetBuffer();
super.sendRedirect(location);
}
/* ------------------------------------------------------------ */
/**
* @see javax.servlet.ServletResponseWrapper#getOutputStream()
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#getOutputStream()
*/
@Override
public ServletOutputStream getOutputStream() throws IOException
{
if (_gzStream==null)
if (_compressedStream==null)
{
if (getResponse().isCommitted() || _noGzip)
if (getResponse().isCommitted() || _noCompression)
{
setContentLength(_contentLength);
return getResponse().getOutputStream();
}
_gzStream=newGzipStream(_request,(HttpServletResponse)getResponse(),_contentLength,_bufferSize,_minGzipSize);
_compressedStream=newCompressedStream(_request,(HttpServletResponse)getResponse(),_contentLength,_bufferSize,_minCompressSize);
}
else if (_writer!=null)
throw new IllegalStateException("getWriter() called");
return _gzStream;
return (ServletOutputStream)_compressedStream;
}
/* ------------------------------------------------------------ */
/**
* @see javax.servlet.ServletResponseWrapper#getWriter()
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#getWriter()
*/
@Override
public PrintWriter getWriter() throws IOException
{
if (_writer==null)
{
if (_gzStream!=null)
if (_compressedStream!=null)
throw new IllegalStateException("getOutputStream() called");
if (getResponse().isCommitted() || _noGzip)
if (getResponse().isCommitted() || _noCompression)
{
setContentLength(_contentLength);
return getResponse().getWriter();
}
_gzStream=newGzipStream(_request,(HttpServletResponse)getResponse(),_contentLength,_bufferSize,_minGzipSize);
_writer=newWriter(_gzStream,getCharacterEncoding());
_compressedStream=newCompressedStream(_request,(HttpServletResponse)getResponse(),_contentLength,_bufferSize,_minCompressSize);
_writer=newWriter((OutputStream)_compressedStream,getCharacterEncoding());
}
return _writer;
}
/* ------------------------------------------------------------ */
/**
* No gzip.
*/
public void noGzip()
{
_noGzip=true;
if (_gzStream!=null)
{
try
{
_gzStream.doNotGzip();
}
catch (IOException e)
{
throw new IllegalStateException(e);
}
}
}
/* ------------------------------------------------------------ */
/**
* Finish.
*
* @throws IOException Signals that an I/O exception has occurred.
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setIntHeader(java.lang.String, int)
*/
public void finish() throws IOException
@Override
public void setIntHeader(String name, int value)
{
if (_writer!=null && !_gzStream._closed)
_writer.flush();
if (_gzStream!=null)
_gzStream.finish();
if ("content-length".equalsIgnoreCase(name))
{
_contentLength=value;
if (_compressedStream!=null)
_compressedStream.setContentLength(_contentLength);
}
else
super.setIntHeader(name,value);
}
/* ------------------------------------------------------------ */
/**
* Allows derived implementations to replace GzipStream implementation.
*
* @param request the request
* @param response the response
* @param contentLength the content length
* @param bufferSize the buffer size
* @param minGzipSize the min gzip size
* @return the gzip stream
* @throws IOException Signals that an I/O exception has occurred.
*/
protected GzipStream newGzipStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minGzipSize) throws IOException
{
return new GzipStream(request,response,contentLength,bufferSize,minGzipSize);
}
/* ------------------------------------------------------------ */
/**
* Allows derived implementations to replace PrintWriter implementation.
@ -415,5 +402,11 @@ public class GzipResponseWrapper extends HttpServletResponseWrapper
{
return encoding==null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding));
}
}
/* ------------------------------------------------------------ */
/**
*@return the underlying CompressedStream implementation
*/
protected abstract CompressedStream newCompressedStream(HttpServletRequest _request, HttpServletResponse response, long _contentLength2, int _bufferSize2, int _minCompressedSize2) throws IOException;
}

View File

@ -0,0 +1,343 @@
// ========================================================================
// 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.zip.DeflaterOutputStream;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
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.
*/
public abstract class AbstractCompressedStream extends ServletOutputStream implements CompressedStream
{
protected HttpServletRequest _request;
protected HttpServletResponse _response;
protected OutputStream _out;
protected ByteArrayOutputStream2 _bOut;
protected DeflaterOutputStream _compressedOutputStream;
protected boolean _closed;
protected int _bufferSize;
protected int _minCompressSize;
protected long _contentLength;
protected boolean _doNotCompress;
/**
* Instantiates a new compressed stream.
*
* @param request
* the request
* @param response
* the response
* @param contentLength
* the content length
* @param bufferSize
* the buffer size
* @param minCompressSize
* the min compress size
* @throws IOException
* Signals that an I/O exception has occurred.
*/
public AbstractCompressedStream(HttpServletRequest request, HttpServletResponse response, long contentLength, int bufferSize, int minCompressSize)
throws IOException
{
_request = request;
_response = response;
_contentLength = contentLength;
_bufferSize = bufferSize;
_minCompressSize = minCompressSize;
if (minCompressSize == 0)
doCompress();
}
/**
* Reset buffer.
*/
public void resetBuffer()
{
if (_response.isCommitted())
throw new IllegalStateException("Committed");
_closed = false;
_out = null;
_bOut = null;
if (_compressedOutputStream != null)
_response.setHeader("Content-Encoding",null);
_compressedOutputStream = null;
_doNotCompress = false;
}
/**
* Sets the content length.
*
* @param length
* the new content length
*/
public void setContentLength(long length)
{
_contentLength = length;
if (_doNotCompress && length >= 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;
}

View File

@ -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<String> 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;
}

View File

@ -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();
}

View File

@ -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;
}
}
}

View File

@ -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);
}
}

View File

@ -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());
}
}

View File

@ -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);
}
}

View File

@ -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(_contentLength<Integer.MAX_VALUE)
_response.setContentLength((int)_contentLength);
else
_response.setHeader("Content-Length",Long.toString(_contentLength));
}
}
/* ------------------------------------------------------------ */
/**
* @see java.io.OutputStream#flush()
*/
public void flush() throws IOException
{
if (_out==null || _bOut!=null)
{
if (_contentLength>0 && _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));
}
}

View File

@ -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);
}
}

View File

@ -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

View File

@ -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: <ul>
* This filter will gzip or deflate the content of a response if: <ul>
* <li>The filter is mapped to a matching path</li>
* <li>accept-encoding header is set to either gzip, deflate or a combination of those</li>
* <li>The response status code is >=200 and <300
* <li>The content length is unknown or more than the <code>minGzipSize</code> initParameter or the minGzipSize is 0(default)</li>
* <li>The content-type is in the comma separated list of mimeTypes set in the <code>mimeTypes</code> initParameter or
@ -50,8 +50,11 @@ import org.eclipse.jetty.util.log.Logger;
* </ul>
*
* <p>
* If both gzip and deflate are specified in the accept-encoding header, then gzip will be used.
* </p>
* <p>
* 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.
* </p>
@ -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));
}
}

View File

@ -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");
}
}
}

View File

@ -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<? extends Servlet> testServlet, CompressionType compressionType)
{
this.testServlet = testServlet;
this.compressionType = compressionType;
}
@Rule
public TestingDir testingdir = new TestingDir();
private Class<? extends Servlet> testServlet;
public GzipFilterContentLengthTest(Class<? extends Servlet> 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);

View File

@ -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);

View File

@ -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<CompressionType[]> 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

View File

@ -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<String[]> 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();
}

View File

@ -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 <a href="Eclipse Bug 366106">http://bugs.eclipse.org/366106</a>
*/
@RunWith(Parameterized.class)
public class IncludableGzipFilterMinSizeTest
{
@Parameters
public static Collection<CompressionType[]> 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<? extends Servlet> 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);

View File

@ -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<CompressionType[]> 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);

View File

@ -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;

View File

@ -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<? extends GzipFilter> 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)