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