View Javadoc

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