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