View Javadoc

1   // ========================================================================
2   // Copyright (c) Webtide LLC
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  
14  
15  package org.eclipse.jetty.http.gzip;
16  
17  import java.io.IOException;
18  import java.io.OutputStream;
19  import java.io.OutputStreamWriter;
20  import java.io.PrintWriter;
21  import java.io.UnsupportedEncodingException;
22  import java.util.zip.GZIPOutputStream;
23  
24  import javax.servlet.ServletOutputStream;
25  import javax.servlet.http.HttpServletRequest;
26  import javax.servlet.http.HttpServletResponse;
27  
28  import org.eclipse.jetty.util.ByteArrayOutputStream2;
29  
30  
31  /* ------------------------------------------------------------ */
32  /**
33   */
34  public class GzipStream extends ServletOutputStream
35  {
36      protected HttpServletRequest _request;
37      protected HttpServletResponse _response;
38      protected OutputStream _out;
39      protected ByteArrayOutputStream2 _bOut;
40      protected GZIPOutputStream _gzOut;
41      protected boolean _closed;
42      protected int _bufferSize;
43      protected int _minGzipSize;
44      protected long _contentLength;
45  
46      /**
47       * Instantiates a new gzip stream.
48       *
49       * @param request the request
50       * @param response the response
51       * @param contentLength the content length
52       * @param bufferSize the buffer size
53       * @param minGzipSize the min gzip size
54       * @throws IOException Signals that an I/O exception has occurred.
55       */
56      public GzipStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minGzipSize) throws IOException
57      {
58          _request=request;
59          _response=response;
60          _contentLength=contentLength;
61          _bufferSize=bufferSize;
62          _minGzipSize=minGzipSize;
63          if (minGzipSize==0)
64              doGzip();
65      }
66  
67      /**
68       * Reset buffer.
69       */
70      public void resetBuffer()
71      {
72          if (_response.isCommitted())
73              throw new IllegalStateException("Committed");
74          _closed=false;
75          _out=null;
76          _bOut=null;
77          if (_gzOut!=null)
78              _response.setHeader("Content-Encoding",null);
79          _gzOut=null;
80      }
81  
82      /**
83       * Sets the content length.
84       *
85       * @param length the new content length
86       */
87      public void setContentLength(long length)
88      {
89          _contentLength=length;
90      }
91      
92      /* ------------------------------------------------------------ */
93      /**
94       * @see java.io.OutputStream#flush()
95       */
96      public void flush() throws IOException
97      {
98          if (_out==null || _bOut!=null)
99          {
100             if (_contentLength>0 && _contentLength<_minGzipSize)
101                 doNotGzip();
102             else
103                 doGzip();
104         }
105         
106         _out.flush();
107     }
108 
109     /* ------------------------------------------------------------ */
110     /**
111      * @see java.io.OutputStream#close()
112      */
113     public void close() throws IOException
114     {
115         if (_closed)
116             return;
117         
118         if (_request.getAttribute("javax.servlet.include.request_uri")!=null)            
119             flush();
120         else
121         {
122             if (_bOut!=null)
123             {
124                 if (_contentLength<0)
125                     _contentLength=_bOut.getCount();
126                 if (_contentLength<_minGzipSize)
127                     doNotGzip();
128                 else
129                     doGzip();
130             }
131             else if (_out==null)
132             {
133                 doNotGzip();
134             }
135 
136             if (_gzOut!=null)
137                 _gzOut.close();
138             else
139                 _out.close();
140             _closed=true;
141         }
142     }  
143 
144     /**
145      * Finish.
146      *
147      * @throws IOException Signals that an I/O exception has occurred.
148      */
149     public void finish() throws IOException
150     {
151         if (!_closed)
152         {
153             if (_out==null || _bOut!=null)
154             {
155                 if (_contentLength>0 && _contentLength<_minGzipSize)
156                     doNotGzip();
157                 else
158                     doGzip();
159             }
160             
161             if (_gzOut!=null && !_closed)
162             {
163                 _closed=true;
164                 _gzOut.close();
165             }
166         }
167     }  
168 
169     /* ------------------------------------------------------------ */
170     /**
171      * @see java.io.OutputStream#write(int)
172      */
173     public void write(int b) throws IOException
174     {    
175         checkOut(1);
176         _out.write(b);
177     }
178 
179     /* ------------------------------------------------------------ */
180     /**
181      * @see java.io.OutputStream#write(byte[])
182      */
183     public void write(byte b[]) throws IOException
184     {
185         checkOut(b.length);
186         _out.write(b);
187     }
188 
189     /* ------------------------------------------------------------ */
190     /**
191      * @see java.io.OutputStream#write(byte[], int, int)
192      */
193     public void write(byte b[], int off, int len) throws IOException
194     {
195         checkOut(len);
196         _out.write(b,off,len);
197     }
198     
199     /**
200      * Sets the content encoding gzip.
201      *
202      * @return true, if successful
203      */
204     protected boolean setContentEncodingGzip()
205     {
206         _response.setHeader("Content-Encoding", "gzip");
207         return _response.containsHeader("Content-Encoding");
208     }
209     
210     /**
211      * Do gzip.
212      *
213      * @throws IOException Signals that an I/O exception has occurred.
214      */
215     public void doGzip() throws IOException
216     {
217         if (_gzOut==null) 
218         {
219             if (_response.isCommitted())
220                 throw new IllegalStateException();
221             
222             if (setContentEncodingGzip())
223             {
224                 _out=_gzOut=new GZIPOutputStream(_response.getOutputStream(),_bufferSize);
225 
226                 if (_bOut!=null)
227                 {
228                     _out.write(_bOut.getBuf(),0,_bOut.getCount());
229                     _bOut=null;
230                 }
231             }
232             else 
233                 doNotGzip();
234         }
235     }
236     
237     /**
238      * Do not gzip.
239      *
240      * @throws IOException Signals that an I/O exception has occurred.
241      */
242     public void doNotGzip() throws IOException
243     {
244         if (_gzOut!=null) 
245             throw new IllegalStateException();
246         if (_out==null || _bOut!=null )
247         {
248             _out=_response.getOutputStream();
249             if (_contentLength>=0)
250             {
251                 if(_contentLength<Integer.MAX_VALUE)
252                     _response.setContentLength((int)_contentLength);
253                 else
254                     _response.setHeader("Content-Length",Long.toString(_contentLength));
255             }
256 
257             if (_bOut!=null)
258                 _out.write(_bOut.getBuf(),0,_bOut.getCount());
259             _bOut=null;
260         }   
261     }
262     
263     /**
264      * Check out.
265      *
266      * @param length the length
267      * @throws IOException Signals that an I/O exception has occurred.
268      */
269     private void checkOut(int length) throws IOException 
270     {
271         if (_closed) 
272             throw new IOException("CLOSED");
273         
274         if (_out==null)
275         {
276             if (_response.isCommitted() || (_contentLength>=0 && _contentLength<_minGzipSize))
277                 doNotGzip();
278             else if (length>_minGzipSize)
279                 doGzip();
280             else
281                 _out=_bOut=new ByteArrayOutputStream2(_bufferSize);
282         }
283         else if (_bOut!=null)
284         {
285             if (_response.isCommitted() || (_contentLength>=0 && _contentLength<_minGzipSize))
286                 doNotGzip();
287             else if (length>=(_bOut.getBuf().length -_bOut.getCount()))
288                 doGzip();
289         }
290     }
291 
292     /**
293      * Allows derived implementations to replace PrintWriter implementation.
294      */
295     protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException
296     {
297         return encoding==null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding));
298     }
299 }
300