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