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