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      protected boolean _doNotGzip;
46  
47      /**
48       * Instantiates a new gzip stream.
49       *
50       * @param request the request
51       * @param response the response
52       * @param contentLength the content length
53       * @param bufferSize the buffer size
54       * @param minGzipSize the min gzip size
55       * @throws IOException Signals that an I/O exception has occurred.
56       */
57      public GzipStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minGzipSize) throws IOException
58      {
59          _request=request;
60          _response=response;
61          _contentLength=contentLength;
62          _bufferSize=bufferSize;
63          _minGzipSize=minGzipSize;
64          if (minGzipSize==0)
65              doGzip();
66      }
67  
68      /**
69       * Reset buffer.
70       */
71      public void resetBuffer()
72      {
73          if (_response.isCommitted())
74              throw new IllegalStateException("Committed");
75          _closed=false;
76          _out=null;
77          _bOut=null;
78          if (_gzOut!=null)
79              _response.setHeader("Content-Encoding",null);
80          _gzOut=null;
81          _doNotGzip=false;
82      }
83  
84      /**
85       * Sets the content length.
86       *
87       * @param length the new content length
88       */
89      public void setContentLength(long length)
90      {
91          _contentLength=length;
92          if (_doNotGzip && length>=0)
93          {
94              if(_contentLength<Integer.MAX_VALUE)
95                  _response.setContentLength((int)_contentLength);
96              else
97                  _response.setHeader("Content-Length",Long.toString(_contentLength));
98          }
99      }
100     
101     /* ------------------------------------------------------------ */
102     /**
103      * @see java.io.OutputStream#flush()
104      */
105     public void flush() throws IOException
106     {
107         if (_out==null || _bOut!=null)
108         {
109             if (_contentLength>0 && _contentLength<_minGzipSize)
110                 doNotGzip();
111             else
112                 doGzip();
113         }
114         
115         _out.flush();
116     }
117 
118     /* ------------------------------------------------------------ */
119     /**
120      * @see java.io.OutputStream#close()
121      */
122     public void close() throws IOException
123     {
124         if (_closed)
125             return;
126         
127         if (_request.getAttribute("javax.servlet.include.request_uri")!=null)            
128             flush();
129         else
130         {
131             if (_bOut!=null)
132             {
133                 if (_contentLength<0)
134                     _contentLength=_bOut.getCount();
135                 if (_contentLength<_minGzipSize)
136                     doNotGzip();
137                 else
138                     doGzip();
139             }
140             else if (_out==null)
141             {
142                 doNotGzip();
143             }
144 
145             if (_gzOut!=null)
146                 _gzOut.close();
147             else
148                 _out.close();
149             _closed=true;
150         }
151     }  
152 
153     /**
154      * Finish.
155      *
156      * @throws IOException Signals that an I/O exception has occurred.
157      */
158     public void finish() throws IOException
159     {
160         if (!_closed)
161         {
162             if (_out==null || _bOut!=null)
163             {
164                 if (_contentLength>0 && _contentLength<_minGzipSize)
165                     doNotGzip();
166                 else
167                     doGzip();
168             }
169             
170             if (_gzOut!=null && !_closed)
171             {
172                 _closed=true;
173                 _gzOut.close();
174             }
175         }
176     }  
177 
178     /* ------------------------------------------------------------ */
179     /**
180      * @see java.io.OutputStream#write(int)
181      */
182     public void write(int b) throws IOException
183     {    
184         checkOut(1);
185         _out.write(b);
186     }
187 
188     /* ------------------------------------------------------------ */
189     /**
190      * @see java.io.OutputStream#write(byte[])
191      */
192     public void write(byte b[]) throws IOException
193     {
194         checkOut(b.length);
195         _out.write(b);
196     }
197 
198     /* ------------------------------------------------------------ */
199     /**
200      * @see java.io.OutputStream#write(byte[], int, int)
201      */
202     public void write(byte b[], int off, int len) throws IOException
203     {
204         checkOut(len);
205         _out.write(b,off,len);
206     }
207     
208     /**
209      * Sets the content encoding gzip.
210      *
211      * @return true, if successful
212      */
213     protected boolean setContentEncodingGzip()
214     {
215         _response.setHeader("Content-Encoding", "gzip");
216         return _response.containsHeader("Content-Encoding");
217     }
218     
219     /**
220      * Do gzip.
221      *
222      * @throws IOException Signals that an I/O exception has occurred.
223      */
224     public void doGzip() throws IOException
225     {
226         if (_gzOut==null) 
227         {
228             if (_response.isCommitted())
229                 throw new IllegalStateException();
230             
231             if (setContentEncodingGzip())
232             {
233                 _out=_gzOut=new GZIPOutputStream(_response.getOutputStream(),_bufferSize);
234 
235                 if (_bOut!=null)
236                 {
237                     _out.write(_bOut.getBuf(),0,_bOut.getCount());
238                     _bOut=null;
239                 }
240             }
241             else 
242                 doNotGzip();
243         }
244     }
245     
246     /**
247      * Do not gzip.
248      *
249      * @throws IOException Signals that an I/O exception has occurred.
250      */
251     public void doNotGzip() throws IOException
252     {
253         if (_gzOut!=null) 
254             throw new IllegalStateException();
255         if (_out==null || _bOut!=null )
256         {
257             _doNotGzip = true;
258 
259             _out=_response.getOutputStream();
260             setContentLength(_contentLength);
261 
262             if (_bOut!=null)
263                 _out.write(_bOut.getBuf(),0,_bOut.getCount());
264             _bOut=null;
265         }   
266     }
267     
268     /**
269      * Check out.
270      *
271      * @param length the length
272      * @throws IOException Signals that an I/O exception has occurred.
273      */
274     private void checkOut(int length) throws IOException 
275     {
276         if (_closed) 
277             throw new IOException("CLOSED");
278         
279         if (_out==null)
280         {
281             if (_response.isCommitted() || (_contentLength>=0 && _contentLength<_minGzipSize))
282                 doNotGzip();
283             else if (length>_minGzipSize)
284                 doGzip();
285             else
286                 _out=_bOut=new ByteArrayOutputStream2(_bufferSize);
287         }
288         else if (_bOut!=null)
289         {
290             if (_response.isCommitted() || (_contentLength>=0 && _contentLength<_minGzipSize))
291                 doNotGzip();
292             else if (length>=(_bOut.getBuf().length -_bOut.getCount()))
293                 doGzip();
294         }
295     }
296 
297     /**
298      * Allows derived implementations to replace PrintWriter implementation.
299      */
300     protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException
301     {
302         return encoding==null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding));
303     }
304 }
305