View Javadoc

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