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