Mercurial Hosting > luan
view src/org/eclipse/jetty/http/gzip/AbstractCompressedStream.java @ 867:4f5547d29192
minor
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Sun, 02 Oct 2016 21:06:18 -0600 |
parents | 3428c60d7cfc |
children |
line wrap: on
line source
// // ======================================================================== // 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; }