View Javadoc

1   /**
2    *  Copyright 2003-2007 Greg Luck
3    *
4    *  Licensed under the Apache License, Version 2.0 (the "License");
5    *  you may not use this file except in compliance with the License.
6    *  You may obtain a copy of the License at
7    *
8    *      http://www.apache.org/licenses/LICENSE-2.0
9    *
10   *  Unless required by applicable law or agreed to in writing, software
11   *  distributed under the License is distributed on an "AS IS" BASIS,
12   *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   *  See the License for the specific language governing permissions and
14   *  limitations under the License.
15   */
16  
17  package net.sf.ehcache.constructs.web;
18  
19  import org.apache.commons.logging.Log;
20  import org.apache.commons.logging.LogFactory;
21  
22  import javax.servlet.http.HttpServletRequest;
23  import javax.servlet.http.HttpServletResponse;
24  
25  /**
26   * A collection of response processing utilities, which are shared between 2 or more filters
27   *
28   * @author Greg Luck
29   * @version $Id: ResponseUtil.java 512 2007-07-10 09:18:45Z gregluck $
30   */
31  public final class ResponseUtil {
32  
33  
34      private static final Log LOG = LogFactory.getLog(ResponseUtil.class.getName());
35  
36  
37      /**
38       * Gzipping an empty file or stream always results in a 20 byte output
39       * This is in java or elsewhere.
40       * <p/>
41       * On a unix system to reproduce do <code>gzip -n empty_file</code>. -n tells gzip to not
42       * include the file name. The resulting file size is 20 bytes.
43       * <p/>
44       * Therefore 20 bytes can be used indicate that the gzip byte[] will be empty when ungzipped.
45       */
46      private static final int EMPTY_GZIPPED_CONTENT_SIZE = 20;
47  
48      /**
49       * Utility class. No public constructor.
50       */
51      private ResponseUtil() {
52          //noop
53      }
54  
55  
56      /**
57       * Checks whether a gzipped body is actually empty and should just be zero.
58       * When the compressedBytes is {@link #EMPTY_GZIPPED_CONTENT_SIZE} it should be zero.
59       *
60       * @param compressedBytes the gzipped response body
61       * @param request         the client HTTP request
62       * @return true if the response should be 0, even if it is isn't.
63       */
64      public static boolean shouldGzippedBodyBeZero(byte[] compressedBytes, HttpServletRequest request) {
65  
66          //Check for 0 length body
67          if (compressedBytes.length == EMPTY_GZIPPED_CONTENT_SIZE) {
68              if (LOG.isDebugEnabled()) {
69                  LOG.debug(request.getRequestURL() + " resulted in an empty response.");
70              }
71              return true;
72          } else {
73              return false;
74          }
75      }
76  
77  
78      /**
79       * Performs a number of checks to ensure response saneness according to the rules of RFC2616:
80       * <ol>
81       * <li>If the response code is {@link javax.servlet.http.HttpServletResponse#SC_NO_CONTENT} then it is illegal for the body
82       * to contain anything. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.2.5
83       * <li>If the response code is {@link javax.servlet.http.HttpServletResponse#SC_NOT_MODIFIED} then it is illegal for the body
84       * to contain anything. See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html#sec10.3.5
85       * </ol>
86       *
87       * @param request         the client HTTP request
88       * @param responseStatus         the responseStatus
89       * @return true if the response should be 0, even if it is isn't.
90       */
91      public static boolean shouldBodyBeZero(HttpServletRequest request, int responseStatus) {
92  
93          //Check for NO_CONTENT
94          if (responseStatus == HttpServletResponse.SC_NO_CONTENT) {
95              if (LOG.isDebugEnabled()) {
96                  LOG.debug(request.getRequestURL() + " resulted in a " + HttpServletResponse.SC_NO_CONTENT
97                          + " response. Removing message body in accordance with RFC2616.");
98              }
99              return true;
100         }
101 
102         //Check for NOT_MODIFIED
103         if (responseStatus == HttpServletResponse.SC_NOT_MODIFIED) {
104             if (LOG.isDebugEnabled()) {
105                 LOG.debug(request.getRequestURL() + " resulted in a " + HttpServletResponse.SC_NOT_MODIFIED
106                         + " response. Removing message body in accordance with RFC2616.");
107             }
108             return true;
109         }
110 
111         return false;
112     }
113 
114     /**
115      * Adds the gzip HTTP header to the response. This is need when a gzipped body is returned so that browsers can properly decompress it.
116      * <p/>
117      * @param response the response which will have a header added to it. I.e this method changes its parameter
118      * @throws ResponseHeadersNotModifiableException Either the response is committed or we were called using the include method
119      * from a {@link javax.servlet.RequestDispatcher#include(javax.servlet.ServletRequest, javax.servlet.ServletResponse)}
120      * method and the set set header is ignored.
121      */
122     public static void addGzipHeader(final HttpServletResponse response) throws ResponseHeadersNotModifiableException {
123         response.setHeader("Content-Encoding", "gzip");
124         boolean containsEncoding = response.containsHeader("Content-Encoding");
125         if (!containsEncoding) {
126             throw new ResponseHeadersNotModifiableException("Failure when attempting to set "
127                     + "Content-Encoding: gzip");
128         }
129     }
130 
131 
132 }