Mercurial Hosting > luan
diff src/org/eclipse/jetty/http/gzip/AbstractCompressedStream.java @ 802:3428c60d7cfc
replace jetty jars with source
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Wed, 07 Sep 2016 21:15:48 -0600 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/src/org/eclipse/jetty/http/gzip/AbstractCompressedStream.java Wed Sep 07 21:15:48 2016 -0600 @@ -0,0 +1,388 @@ +// +// ======================================================================== +// 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.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 appropriate Content-Encoding header string. + */ +public abstract class AbstractCompressedStream extends ServletOutputStream +{ + private final String _encoding; + protected final String _vary; + protected final CompressedResponseWrapper _wrapper; + protected final HttpServletResponse _response; + protected OutputStream _out; + protected ByteArrayOutputStream2 _bOut; + protected DeflaterOutputStream _compressedOutputStream; + protected boolean _closed; + protected boolean _doNotCompress; + + /** + * Instantiates a new compressed stream. + * + */ + public AbstractCompressedStream(String encoding,HttpServletRequest request, CompressedResponseWrapper wrapper,String vary) + throws IOException + { + _encoding=encoding; + _wrapper = wrapper; + _response = (HttpServletResponse)wrapper.getResponse(); + _vary=vary; + + if (_wrapper.getMinCompressSize()==0) + doCompress(); + } + + /* ------------------------------------------------------------ */ + /** + * Reset buffer. + */ + public void resetBuffer() + { + if (_response.isCommitted() || _compressedOutputStream!=null ) + throw new IllegalStateException("Committed"); + _closed = false; + _out = null; + _bOut = null; + _doNotCompress = false; + } + + /* ------------------------------------------------------------ */ + public void setBufferSize(int bufferSize) + { + if (_bOut!=null && _bOut.getBuf().length<bufferSize) + { + ByteArrayOutputStream2 b = new ByteArrayOutputStream2(bufferSize); + b.write(_bOut.getBuf(),0,_bOut.size()); + _bOut=b; + } + } + + /* ------------------------------------------------------------ */ + public void setContentLength() + { + if (_doNotCompress) + { + long length=_wrapper.getContentLength(); + if (length>=0) + { + if (length < Integer.MAX_VALUE) + _response.setContentLength((int)length); + else + _response.setHeader("Content-Length",Long.toString(length)); + } + } + } + + /* ------------------------------------------------------------ */ + /** + * @see java.io.OutputStream#flush() + */ + @Override + public void flush() throws IOException + { + if (_out == null || _bOut != null) + { + long length=_wrapper.getContentLength(); + if (length > 0 && length < _wrapper.getMinCompressSize()) + doNotCompress(false); + else + doCompress(); + } + + _out.flush(); + } + + /* ------------------------------------------------------------ */ + /** + * @see java.io.OutputStream#close() + */ + @Override + public void close() throws IOException + { + if (_closed) + return; + + if (_wrapper.getRequest().getAttribute("javax.servlet.include.request_uri") != null) + flush(); + else + { + if (_bOut != null) + { + long length=_wrapper.getContentLength(); + if (length < 0) + { + length = _bOut.getCount(); + _wrapper.setContentLength(length); + } + if (length < _wrapper.getMinCompressSize()) + doNotCompress(false); + else + doCompress(); + } + else if (_out == null) + { + // No output + doNotCompress(false); + } + + 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) + { + long length=_wrapper.getContentLength(); + if (length >= 0 && length < _wrapper.getMinCompressSize()) + doNotCompress(false); + 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 (_encoding!=null) + { + setHeader("Content-Encoding", _encoding); + if (_response.containsHeader("Content-Encoding")) + { + addHeader("Vary",_vary); + _out=_compressedOutputStream=createStream(); + if (_out!=null) + { + if (_bOut!=null) + { + _out.write(_bOut.getBuf(),0,_bOut.getCount()); + _bOut=null; + } + + String etag=_wrapper.getETag(); + if (etag!=null) + setHeader("ETag",etag.substring(0,etag.length()-1)+'-'+_encoding+'"'); + return; + } + } + } + + doNotCompress(true); // Send vary as it could have been compressed if encoding was present + } + } + + /** + * Do not compress. + * + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public void doNotCompress(boolean sendVary) throws IOException + { + if (_compressedOutputStream != null) + throw new IllegalStateException("Compressed output stream is already assigned."); + if (_out == null || _bOut != null) + { + if (sendVary) + addHeader("Vary",_vary); + if (_wrapper.getETag()!=null) + setHeader("ETag",_wrapper.getETag()); + + _doNotCompress = true; + + _out = _response.getOutputStream(); + setContentLength(); + + if (_bOut != null) + _out.write(_bOut.getBuf(),0,_bOut.getCount()); + _bOut = null; + } + } + + /** + * Check out. + * + * @param lengthToWrite + * the length + * @throws IOException + * Signals that an I/O exception has occurred. + */ + private void checkOut(int lengthToWrite) throws IOException + { + if (_closed) + throw new IOException("CLOSED"); + + if (_out == null) + { + // If this first write is larger than buffer size, then we are committing now + if (lengthToWrite>_wrapper.getBufferSize()) + { + // if we know this is all the content and it is less than minimum, then do not compress, otherwise do compress + long length=_wrapper.getContentLength(); + if (length>=0 && length<_wrapper.getMinCompressSize()) + doNotCompress(false); // Not compressing by size, so no vary on request headers + else + doCompress(); + } + else + { + // start aggregating writes into a buffered output stream + _out = _bOut = new ByteArrayOutputStream2(_wrapper.getBufferSize()); + } + } + // else are we aggregating writes? + else if (_bOut !=null) + { + // We are aggregating into the buffered output stream. + + // If this write fills the buffer, then we are committing + if (lengthToWrite>=(_bOut.getBuf().length - _bOut.getCount())) + { + // if we know this is all the content and it is less than minimum, then do not compress, otherwise do compress + long length=_wrapper.getContentLength(); + if (length>=0 && length<_wrapper.getMinCompressSize()) + doNotCompress(false); // Not compressing by size, so no vary on request headers + else + 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)); + } + + protected void addHeader(String name,String value) + { + _response.addHeader(name, value); + } + + protected void setHeader(String name,String value) + { + _response.setHeader(name, value); + } + + /** + * 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; + + +}