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.Set;
23  
24  import javax.servlet.ServletOutputStream;
25  import javax.servlet.http.HttpServletRequest;
26  import javax.servlet.http.HttpServletResponse;
27  import javax.servlet.http.HttpServletResponseWrapper;
28  
29  import org.eclipse.jetty.util.StringUtil;
30  
31  
32  /* ------------------------------------------------------------ */
33  /**
34   */
35  public class GzipResponseWrapper extends HttpServletResponseWrapper
36  {
37      public static final int DEFAULT_BUFFER_SIZE = 8192;
38      public static final int DEFAULT_MIN_GZIP_SIZE = 256;
39      
40      private HttpServletRequest _request;
41      private Set<String> _mimeTypes;
42      private int _bufferSize=DEFAULT_BUFFER_SIZE;
43      private int _minGzipSize=DEFAULT_MIN_GZIP_SIZE;
44  
45      private PrintWriter _writer;
46      private GzipStream _gzStream;
47      private long _contentLength=-1;
48      private boolean _noGzip;
49  
50      /**
51       * Instantiates a new gzip response wrapper.
52       *
53       * @param request the request
54       * @param response the response
55       */
56      public GzipResponseWrapper(HttpServletRequest request, HttpServletResponse response)
57      {
58          super(response);
59          _request=request;
60      }
61  
62      /* ------------------------------------------------------------ */
63      /**
64       * Sets the mime types.
65       *
66       * @param mimeTypes the new mime types
67       */
68      public void setMimeTypes(Set<String> mimeTypes)
69      {
70          _mimeTypes = mimeTypes;
71      }
72  
73      /* ------------------------------------------------------------ */
74      /**
75       * @see javax.servlet.ServletResponseWrapper#setBufferSize(int)
76       */
77      public void setBufferSize(int bufferSize)
78      {
79          _bufferSize = bufferSize;
80      }
81  
82      /* ------------------------------------------------------------ */
83      /**
84       * Sets the min gzip size.
85       *
86       * @param minGzipSize the new min gzip size
87       */
88      public void setMinGzipSize(int minGzipSize)
89      {
90          _minGzipSize = minGzipSize;
91      }
92  
93      /* ------------------------------------------------------------ */
94      /**
95       * @see javax.servlet.ServletResponseWrapper#setContentType(java.lang.String)
96       */
97      public void setContentType(String ct)
98      {
99          super.setContentType(ct);
100 
101         if (ct!=null)
102         {
103             int colon=ct.indexOf(";");
104             if (colon>0)
105                 ct=ct.substring(0,colon);
106         }
107 
108         if ((_gzStream==null || _gzStream._out==null) && 
109             (_mimeTypes==null && "application/gzip".equalsIgnoreCase(ct) ||
110              _mimeTypes!=null && (ct==null||!_mimeTypes.contains(StringUtil.asciiToLowerCase(ct)))))
111         {
112             noGzip();
113         }
114     }
115 
116     /* ------------------------------------------------------------ */
117     /**
118      * @see javax.servlet.http.HttpServletResponseWrapper#setStatus(int, java.lang.String)
119      */
120     public void setStatus(int sc, String sm)
121     {
122         super.setStatus(sc,sm);
123         if (sc<200 || sc==204 || sc==205 || sc>=300)
124             noGzip();
125     }
126 
127     /* ------------------------------------------------------------ */
128     /**
129      * @see javax.servlet.http.HttpServletResponseWrapper#setStatus(int)
130      */
131     public void setStatus(int sc)
132     {
133         super.setStatus(sc);
134         if (sc<200 || sc==204 || sc==205 ||sc>=300)
135             noGzip();
136     }
137 
138     /* ------------------------------------------------------------ */
139     /**
140      * @see javax.servlet.ServletResponseWrapper#setContentLength(int)
141      */
142     public void setContentLength(int length)
143     {
144         setContentLength((long)length);
145     }
146     
147     /* ------------------------------------------------------------ */
148     protected void setContentLength(long length)
149     {
150         _contentLength=length;
151         if (_gzStream!=null)
152             _gzStream.setContentLength(length);
153         else if (_noGzip && _contentLength>=0)
154         {
155             HttpServletResponse response = (HttpServletResponse)getResponse();
156             if(_contentLength<Integer.MAX_VALUE)
157             {
158                 response.setContentLength((int)_contentLength);
159             }
160             else
161             {
162                 response.setHeader("Content-Length", Long.toString(_contentLength));
163             }
164         }
165     }
166 
167     /* ------------------------------------------------------------ */
168     /**
169      * @see javax.servlet.http.HttpServletResponseWrapper#addHeader(java.lang.String, java.lang.String)
170      */
171     public void addHeader(String name, String value)
172     {
173         if ("content-length".equalsIgnoreCase(name))
174         {
175             _contentLength=Long.parseLong(value);
176             if (_gzStream!=null)
177                 _gzStream.setContentLength(_contentLength);
178         }
179         else if ("content-type".equalsIgnoreCase(name))
180         {   
181             setContentType(value);
182         }
183         else if ("content-encoding".equalsIgnoreCase(name))
184         {   
185             super.addHeader(name,value);
186             if (!isCommitted())
187             {
188                 noGzip();
189             }
190         }
191         else
192             super.addHeader(name,value);
193     }
194 
195     /* ------------------------------------------------------------ */
196     /**
197      * @see javax.servlet.http.HttpServletResponseWrapper#setHeader(java.lang.String, java.lang.String)
198      */
199     public void setHeader(String name, String value)
200     {
201         if ("content-length".equalsIgnoreCase(name))
202         {
203             setContentLength(Long.parseLong(value));
204         }
205         else if ("content-type".equalsIgnoreCase(name))
206         {   
207             setContentType(value);
208         }
209         else if ("content-encoding".equalsIgnoreCase(name))
210         {   
211             super.setHeader(name,value);
212             if (!isCommitted())
213             {
214                 noGzip();
215             }
216         }
217         else
218             super.setHeader(name,value);
219     }
220 
221     /* ------------------------------------------------------------ */
222     /**
223      * @see javax.servlet.http.HttpServletResponseWrapper#setIntHeader(java.lang.String, int)
224      */
225     public void setIntHeader(String name, int value)
226     {
227         if ("content-length".equalsIgnoreCase(name))
228         {
229             _contentLength=value;
230             if (_gzStream!=null)
231                 _gzStream.setContentLength(_contentLength);
232         }
233         else
234             super.setIntHeader(name,value);
235     }
236 
237     /* ------------------------------------------------------------ */
238     /**
239      * @see javax.servlet.ServletResponseWrapper#flushBuffer()
240      */
241     public void flushBuffer() throws IOException
242     {
243         if (_writer!=null)
244             _writer.flush();
245         if (_gzStream!=null)
246             _gzStream.finish();
247         else
248             getResponse().flushBuffer();
249     }
250 
251     /* ------------------------------------------------------------ */
252     /**
253      * @see javax.servlet.ServletResponseWrapper#reset()
254      */
255     public void reset()
256     {
257         super.reset();
258         if (_gzStream!=null)
259             _gzStream.resetBuffer();
260         _writer=null;
261         _gzStream=null;
262         _noGzip=false;
263         _contentLength=-1;
264     }
265     
266     /* ------------------------------------------------------------ */
267     /**
268      * @see javax.servlet.ServletResponseWrapper#resetBuffer()
269      */
270     public void resetBuffer()
271     {
272         super.resetBuffer();
273         if (_gzStream!=null)
274             _gzStream.resetBuffer();
275         _writer=null;
276         _gzStream=null;
277     }
278     
279     /* ------------------------------------------------------------ */
280     /**
281      * @see javax.servlet.http.HttpServletResponseWrapper#sendError(int, java.lang.String)
282      */
283     public void sendError(int sc, String msg) throws IOException
284     {
285         resetBuffer();
286         super.sendError(sc,msg);
287     }
288     
289     /* ------------------------------------------------------------ */
290     /**
291      * @see javax.servlet.http.HttpServletResponseWrapper#sendError(int)
292      */
293     public void sendError(int sc) throws IOException
294     {
295         resetBuffer();
296         super.sendError(sc);
297     }
298     
299     /* ------------------------------------------------------------ */
300     /**
301      * @see javax.servlet.http.HttpServletResponseWrapper#sendRedirect(java.lang.String)
302      */
303     public void sendRedirect(String location) throws IOException
304     {
305         resetBuffer();
306         super.sendRedirect(location);
307     }
308 
309     /* ------------------------------------------------------------ */
310     /**
311      * @see javax.servlet.ServletResponseWrapper#getOutputStream()
312      */
313     public ServletOutputStream getOutputStream() throws IOException
314     {
315         if (_gzStream==null)
316         {
317             if (getResponse().isCommitted() || _noGzip)
318             {
319                 setContentLength(_contentLength);
320                 return getResponse().getOutputStream();
321             }
322             
323             _gzStream=newGzipStream(_request,(HttpServletResponse)getResponse(),_contentLength,_bufferSize,_minGzipSize);
324         }
325         else if (_writer!=null)
326             throw new IllegalStateException("getWriter() called");
327         
328         return _gzStream;   
329     }
330 
331     /* ------------------------------------------------------------ */
332     /**
333      * @see javax.servlet.ServletResponseWrapper#getWriter()
334      */
335     public PrintWriter getWriter() throws IOException
336     {
337         if (_writer==null)
338         { 
339             if (_gzStream!=null)
340                 throw new IllegalStateException("getOutputStream() called");
341             
342             if (getResponse().isCommitted() || _noGzip)
343             {
344                 setContentLength(_contentLength);
345                 return getResponse().getWriter();
346             }
347             
348             _gzStream=newGzipStream(_request,(HttpServletResponse)getResponse(),_contentLength,_bufferSize,_minGzipSize);
349             _writer=newWriter(_gzStream,getCharacterEncoding());
350         }
351         return _writer;   
352     }
353 
354     /* ------------------------------------------------------------ */
355     /**
356      * No gzip.
357      */
358     public void noGzip()
359     {
360         _noGzip=true;
361         if (_gzStream!=null)
362         {
363             try
364             {
365                 _gzStream.doNotGzip();
366             }
367             catch (IOException e)
368             {
369                 throw new IllegalStateException(e);
370             }
371         }
372     }
373     
374     /* ------------------------------------------------------------ */
375     /**
376      * Finish.
377      *
378      * @throws IOException Signals that an I/O exception has occurred.
379      */
380     public void finish() throws IOException
381     {
382         if (_writer!=null && !_gzStream._closed)
383             _writer.flush();
384         if (_gzStream!=null)
385             _gzStream.finish();
386     }
387  
388     /* ------------------------------------------------------------ */
389     /**
390      * Allows derived implementations to replace GzipStream implementation.
391      *
392      * @param request the request
393      * @param response the response
394      * @param contentLength the content length
395      * @param bufferSize the buffer size
396      * @param minGzipSize the min gzip size
397      * @return the gzip stream
398      * @throws IOException Signals that an I/O exception has occurred.
399      */
400     protected GzipStream newGzipStream(HttpServletRequest request,HttpServletResponse response,long contentLength,int bufferSize, int minGzipSize) throws IOException
401     {
402         return new GzipStream(request,response,contentLength,bufferSize,minGzipSize);
403     }
404 
405     /* ------------------------------------------------------------ */
406     /**
407      * Allows derived implementations to replace PrintWriter implementation.
408      *
409      * @param out the out
410      * @param encoding the encoding
411      * @return the prints the writer
412      * @throws UnsupportedEncodingException the unsupported encoding exception
413      */
414     protected PrintWriter newWriter(OutputStream out,String encoding) throws UnsupportedEncodingException
415     {
416         return encoding==null?new PrintWriter(out):new PrintWriter(new OutputStreamWriter(out,encoding));
417     }
418 }
419