blob: 790390cb93dc54c18eb0a751a0d40ac02542a410 [file] [log] [blame]
//
// ========================================================================
// Copyright (c) 1995-2014 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;
/*------------------------------------------------------------ */
/**
*/
public abstract class CompressedResponseWrapper extends HttpServletResponseWrapper
{
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 _minCompressSize=DEFAULT_MIN_COMPRESS_SIZE;
protected HttpServletRequest _request;
private PrintWriter _writer;
private AbstractCompressedStream _compressedStream;
private String _etag;
private long _contentLength=-1;
private boolean _noCompression;
/* ------------------------------------------------------------ */
public CompressedResponseWrapper(HttpServletRequest request, HttpServletResponse response)
{
super(response);
_request = request;
}
/* ------------------------------------------------------------ */
public long getContentLength()
{
return _contentLength;
}
/* ------------------------------------------------------------ */
public int getBufferSize()
{
return _bufferSize;
}
/* ------------------------------------------------------------ */
public int getMinCompressSize()
{
return _minCompressSize;
}
/* ------------------------------------------------------------ */
public String getETag()
{
return _etag;
}
/* ------------------------------------------------------------ */
public HttpServletRequest getRequest()
{
return _request;
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setMimeTypes(java.util.Set)
*/
public void setMimeTypes(Set<String> mimeTypes)
{
_mimeTypes = mimeTypes;
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setBufferSize(int)
*/
@Override
public void setBufferSize(int bufferSize)
{
_bufferSize = bufferSize;
if (_compressedStream!=null)
_compressedStream.setBufferSize(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 (!_noCompression)
{
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)
{
if (_noCompression)
super.setContentLength(length);
else
setContentLength((long)length);
}
/* ------------------------------------------------------------ */
protected void setContentLength(long length)
{
_contentLength=length;
if (_compressedStream!=null)
_compressedStream.setContentLength();
else if (_noCompression && _contentLength>=0)
{
HttpServletResponse response = (HttpServletResponse)getResponse();
if(_contentLength<Integer.MAX_VALUE)
{
response.setContentLength((int)_contentLength);
}
else
{
response.setHeader("Content-Length", Long.toString(_contentLength));
}
}
}
/* ------------------------------------------------------------ */
/**
* @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 (_compressedStream!=null)
_compressedStream.setContentLength();
}
else if ("content-type".equalsIgnoreCase(name))
{
setContentType(value);
}
else if ("content-encoding".equalsIgnoreCase(name))
{
super.addHeader(name,value);
if (!isCommitted())
{
noCompression();
}
}
else if ("etag".equalsIgnoreCase(name))
_etag=value;
else
super.addHeader(name,value);
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#flushBuffer()
*/
@Override
public void flushBuffer() throws IOException
{
if (_writer!=null)
_writer.flush();
if (_compressedStream!=null)
_compressedStream.flush();
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()
{
if (!_noCompression)
setDeferredHeaders();
_noCompression=true;
if (_compressedStream!=null)
{
try
{
_compressedStream.doNotCompress(false);
}
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();
else
setDeferredHeaders();
}
/* ------------------------------------------------------------ */
private void setDeferredHeaders()
{
if (!isCommitted())
{
if (_contentLength>=0)
{
if (_contentLength < Integer.MAX_VALUE)
super.setContentLength((int)_contentLength);
else
super.setHeader("Content-Length",Long.toString(_contentLength));
}
if(_etag!=null)
super.setHeader("ETag",_etag);
}
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setHeader(java.lang.String, java.lang.String)
*/
@Override
public void setHeader(String name, String value)
{
if (_noCompression)
super.setHeader(name,value);
else if ("content-length".equalsIgnoreCase(name))
{
setContentLength(Long.parseLong(value));
}
else if ("content-type".equalsIgnoreCase(name))
{
setContentType(value);
}
else if ("content-encoding".equalsIgnoreCase(name))
{
super.setHeader(name,value);
if (!isCommitted())
{
noCompression();
}
}
else if ("etag".equalsIgnoreCase(name))
_etag=value;
else
super.setHeader(name,value);
}
/* ------------------------------------------------------------ */
@Override
public boolean containsHeader(String name)
{
if (!_noCompression && "etag".equalsIgnoreCase(name) && _etag!=null)
return true;
return super.containsHeader(name);
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#getOutputStream()
*/
@Override
public ServletOutputStream getOutputStream() throws IOException
{
if (_compressedStream==null)
{
if (getResponse().isCommitted() || _noCompression)
return getResponse().getOutputStream();
_compressedStream=newCompressedStream(_request,(HttpServletResponse)getResponse());
}
else if (_writer!=null)
throw new IllegalStateException("getWriter() called");
return _compressedStream;
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#getWriter()
*/
@Override
public PrintWriter getWriter() throws IOException
{
if (_writer==null)
{
if (_compressedStream!=null)
throw new IllegalStateException("getOutputStream() called");
if (getResponse().isCommitted() || _noCompression)
return getResponse().getWriter();
_compressedStream=newCompressedStream(_request,(HttpServletResponse)getResponse());
_writer=newWriter(_compressedStream,getCharacterEncoding());
}
return _writer;
}
/* ------------------------------------------------------------ */
/**
* @see org.eclipse.jetty.http.gzip.CompressedResponseWrapper#setIntHeader(java.lang.String, int)
*/
@Override
public void setIntHeader(String name, int value)
{
if ("content-length".equalsIgnoreCase(name))
{
_contentLength=value;
if (_compressedStream!=null)
_compressedStream.setContentLength();
}
else
super.setIntHeader(name,value);
}
/* ------------------------------------------------------------ */
/**
* Allows derived implementations to replace PrintWriter implementation.
*
* @param out the out
* @param encoding the encoding
* @return the prints the writer
* @throws UnsupportedEncodingException the unsupported encoding exception
*/
protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException
{
return encoding==null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding));
}
/* ------------------------------------------------------------ */
/**
*@return the underlying CompressedStream implementation
*/
protected abstract AbstractCompressedStream newCompressedStream(HttpServletRequest _request, HttpServletResponse response) throws IOException;
}