View Javadoc

1   //
2   //  ========================================================================
3   //  Copyright (c) 1995-2013 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;
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.zip.Deflater;
27  import java.util.zip.DeflaterOutputStream;
28  import java.util.zip.GZIPOutputStream;
29  
30  import javax.servlet.DispatcherType;
31  import javax.servlet.FilterConfig;
32  import javax.servlet.ServletException;
33  import javax.servlet.http.HttpServletRequest;
34  import javax.servlet.http.HttpServletResponse;
35  
36  import org.eclipse.jetty.io.UncheckedPrintWriter;
37  import org.eclipse.jetty.servlets.gzip.AbstractCompressedStream;
38  import org.eclipse.jetty.servlets.gzip.CompressedResponseWrapper;
39  
40  /* ------------------------------------------------------------ */
41  /** Includable GZip Filter.
42   * This extension to the {@link GzipFilter} that uses Jetty features to allow
43   * headers to be set during calls to
44   * {@link javax.servlet.RequestDispatcher#include(javax.servlet.ServletRequest, javax.servlet.ServletResponse)}.
45   * This allows the gzip filter to function correct during includes and to make a decision to gzip or not
46   * at the time the buffer fills and on the basis of all response headers.
47   *
48   * If the init parameter "uncheckedPrintWriter" is set to "true", then the PrintWriter used by
49   * the wrapped getWriter will be {@link UncheckedPrintWriter}.
50   *
51   */
52  public class IncludableGzipFilter extends GzipFilter
53  {
54      boolean _uncheckedPrintWriter=false;
55  
56      @Override
57      public void init(FilterConfig filterConfig) throws ServletException
58      {
59          super.init(filterConfig);
60  
61          String tmp=filterConfig.getInitParameter("uncheckedPrintWriter");
62          if (tmp!=null)
63              _uncheckedPrintWriter=Boolean.valueOf(tmp).booleanValue();
64      }
65  
66      /* ------------------------------------------------------------ */
67      /**
68       * @see org.eclipse.jetty.servlets.GzipFilter#createWrappedResponse(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, java.lang.String)
69       */
70      @Override
71      protected CompressedResponseWrapper createWrappedResponse(HttpServletRequest request, HttpServletResponse response, final String compressionType)
72      {
73          CompressedResponseWrapper wrappedResponse = null;
74          if (compressionType==null)
75          {
76              wrappedResponse = new IncludableResponseWrapper(request,response)
77              {
78                  @Override
79                  protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
80                  {
81                      return new AbstractCompressedStream(null,request,this,_vary)
82                      {
83                          @Override
84                          protected DeflaterOutputStream createStream() throws IOException
85                          {
86                              return null;
87                          }
88                      };
89                  }
90              };
91          }
92          else if (compressionType.equals(GZIP))
93          {
94              wrappedResponse = new IncludableResponseWrapper(request,response)
95              {
96                  @Override
97                  protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
98                  {
99                      return new AbstractCompressedStream(compressionType,request,this,_vary)
100                     {
101                         @Override
102                         protected DeflaterOutputStream createStream() throws IOException
103                         {
104                             return new GZIPOutputStream(_response.getOutputStream(),_bufferSize);
105                         }
106                     };
107                 }
108             };
109         }
110         else if (compressionType.equals(DEFLATE))
111         {
112             wrappedResponse = new IncludableResponseWrapper(request,response)
113             {
114                 @Override
115                 protected AbstractCompressedStream newCompressedStream(HttpServletRequest request,HttpServletResponse response) throws IOException
116                 {
117                     return new AbstractCompressedStream(compressionType,request,this,_vary)
118                     {
119                         @Override
120                         protected DeflaterOutputStream createStream() throws IOException
121                         {
122                             return new DeflaterOutputStream(_response.getOutputStream(),new Deflater(_deflateCompressionLevel, _deflateNoWrap));
123                         }
124                     };
125                 }
126             };
127         }
128         else
129         {
130             throw new IllegalStateException(compressionType + " not supported");
131         }
132         configureWrappedResponse(wrappedResponse);
133         return wrappedResponse;
134     }
135 
136 
137     // Extend CompressedResponseWrapper to be able to set headers during include and to create unchecked printwriters
138     private abstract class IncludableResponseWrapper extends CompressedResponseWrapper
139     {
140         public IncludableResponseWrapper(HttpServletRequest request, HttpServletResponse response)
141         {
142             super(request,response);
143         }
144 
145         @Override
146         public void setHeader(String name,String value)
147         {
148             if (getRequest().getDispatcherType()==DispatcherType.INCLUDE)
149             {
150                 if (!"etag".equalsIgnoreCase(name) && !name.startsWith("content-"))
151                 {
152                     HttpServletResponse response = (HttpServletResponse)getResponse();
153                     response.setHeader("org.eclipse.jetty.server.include."+name,value);
154                 }
155             }
156             else
157                 super.setHeader(name,value);
158         }
159 
160         @Override
161         public void addHeader(String name, String value)
162         {
163             super.addHeader(name, value);
164             HttpServletResponse response = (HttpServletResponse)getResponse();
165             if (!response.containsHeader(name))
166                 setHeader(name,value);
167         }
168         
169         @Override
170         protected PrintWriter newWriter(OutputStream out, String encoding) throws UnsupportedEncodingException
171         {
172             if (_uncheckedPrintWriter)
173                 return encoding == null?new UncheckedPrintWriter(out):new UncheckedPrintWriter(new OutputStreamWriter(out,encoding));
174             return super.newWriter(out,encoding);
175         }
176     }
177 
178 }