View Javadoc

1   /*
2    * $Id: ExtendedHttpServlet.java,v 1.18 2011/06/16 09:29:41 jbmeslin Exp $
3    * 
4    */
5   package org.rcfaces.core.internal.webapp;
6   
7   import java.io.IOException;
8   import java.security.MessageDigest;
9   import java.text.DateFormat;
10  import java.text.ParseException;
11  import java.text.SimpleDateFormat;
12  import java.util.Date;
13  import java.util.HashSet;
14  import java.util.Locale;
15  import java.util.Map;
16  import java.util.Set;
17  
18  import javax.faces.context.FacesContext;
19  import javax.servlet.ServletConfig;
20  import javax.servlet.ServletException;
21  import javax.servlet.http.HttpServlet;
22  import javax.servlet.http.HttpServletRequest;
23  import javax.servlet.http.HttpServletResponse;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.rcfaces.core.internal.Constants;
28  import org.rcfaces.core.internal.lang.StringAppender;
29  import org.rcfaces.core.internal.util.Base64;
30  import org.rcfaces.core.internal.util.MessageDigestSelector;
31  
32  /**
33   * 
34   * @author Olivier Oeuillot (latest modification by $Author: jbmeslin $)
35   * @version $Revision: 1.18 $ $Date: 2011/06/16 09:29:41 $
36   */
37  public class ExtendedHttpServlet extends HttpServlet {
38      private static final long serialVersionUID = -8822434295699331135L;
39  
40      private static final Log LOG = LogFactory.getLog(ExtendedHttpServlet.class);
41  
42      public static final String HTTP_CONTENT_ENCODING = "Content-Encoding";
43  
44      public static final String HTTP_ACCEPT_ENCODING = "Accept-Encoding";
45  
46      public static final String HTTP_LAST_MODIFIED = "Last-Modified";
47  
48      public static final String HTTP_ETAG = "ETag";
49  
50      public static final String HTTP_HASH = "Content-MD5";
51  
52      public static final String HTTP_EXPIRES = "Expires";
53  
54      public static final String HTTP_CACHE_CONTROL = "Cache-Control";
55  
56      public static final String HTTP_IF_MODIFIED_SINCE = "If-Modified-Since";
57  
58      public static final String HTTP_IF_NONE_MATCH = "If-None-Match";
59  
60      public static final String HTTP_IF_NOT_HASH = "If-Not-Hash";
61  
62      public static final String HTTP_VARY = "Vary";
63  
64      public static final String HTTP_PRAGMA = "Pragma";
65  
66      public static final String ACCEPT_ENCODING = "Accept-Encoding";
67  
68      public static final String USER_AGENT = "User-Agent";
69  
70      public static final String GZIP_CONTENT_ENCODING = "gzip";
71  
72      public static final String HEAD_HTTP_METHOD = "HEAD";
73  
74      public static final DateFormat HTTP_DATE_FORMATS[] = {
75              new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss zzz", Locale.US),
76              new SimpleDateFormat("EEEEEE, dd-MMM-yy HH:mm:ss zzz", Locale.US),
77              new SimpleDateFormat("EEE MMMM d HH:mm:ss yyyy", Locale.US) };
78  
79      public static final String CSS_MIME_TYPE = "text/css";
80  
81      public static final String HTML_MIME_TYPE = "text/html";
82  
83      public static final String JAVASCRIPT_MIME_TYPE = "text/javascript";
84  
85      public static final String TEXT_PLAIN_MIME_TYPE = "text/plain";
86  
87      private static Set useGZIPExtensions = new HashSet();
88      static {
89          useGZIPExtensions.add(CSS_MIME_TYPE);
90          useGZIPExtensions.add(HTML_MIME_TYPE);
91          useGZIPExtensions.add(JAVASCRIPT_MIME_TYPE);
92          useGZIPExtensions.add(TEXT_PLAIN_MIME_TYPE);
93      }
94  
95      public static final boolean isMimeTypeSupportGZip(String mimeType) {
96          if (mimeType == null || mimeType.length() < 1) {
97              return false;
98          }
99  
100         int idx = mimeType.indexOf(";");
101         if (idx >= 0) {
102             mimeType = mimeType.substring(0, idx);
103         }
104 
105         mimeType = mimeType.trim().toLowerCase();
106 
107         return useGZIPExtensions.contains(mimeType);
108     }
109 
110     public static final boolean hasGzipSupport(HttpServletRequest request) {
111         return hasGzipSupport(request.getHeader(HTTP_ACCEPT_ENCODING));
112     }
113 
114     public static boolean hasGzipSupport(FacesContext facesContext) {
115         Map requestMap = facesContext.getExternalContext()
116                 .getRequestHeaderMap();
117         String contentEncoding = (String) requestMap.get(HTTP_ACCEPT_ENCODING);
118 
119         return hasGzipSupport(contentEncoding);
120     }
121 
122     private static final boolean hasGzipSupport(String encoding) {
123         if (encoding == null) {
124             return false;
125         }
126 
127         if (encoding.toLowerCase().indexOf(GZIP_CONTENT_ENCODING) >= 0) {
128             if (LOG.isDebugEnabled()) {
129                 LOG.debug("Detected GZIP content encoding. (encoding="
130                         + encoding + ")");
131             }
132 
133             return true;
134         }
135 
136         if (LOG.isDebugEnabled()) {
137             LOG.debug("GZIP content encoding not accepted ! (encoding="
138                     + encoding + ")");
139         }
140 
141         return false;
142     }
143 
144     public static final String computeETag(byte[] buffer) {
145         MessageDigest messageDigest = MessageDigestSelector
146                 .getInstance(Constants.ETAG_DIGEST_ALGORITHMS);
147 
148         byte digest[] = messageDigest.digest(buffer);
149 
150         StringAppender sb = new StringAppender(digest.length * 2 + 16);
151         sb.append("\"rcfaces:");
152         for (int i = 0; i < digest.length; i++) {
153             int v = digest[i] & 0xff;
154             if (v < 16) {
155                 sb.append('0');
156             }
157             sb.append(Integer.toHexString(v));
158         }
159 
160         sb.append(':');
161         sb.append(Integer.toHexString(buffer.length));
162 
163         sb.append('\"');
164         return sb.toString();
165     }
166 
167     public static final String computeHash(byte[] buffer) {
168         MessageDigest messageDigest = MessageDigestSelector
169                 .getInstance(Constants.HASH_DIGEST_ALGORITHMS);
170 
171         // messageDigest.update(buffer);
172         byte digest[] = messageDigest.digest(buffer);
173 
174         return Base64.encodeBytes(digest, Base64.DONT_BREAK_LINES);
175 
176     }
177 
178     public static final Date parseHttpDate(String date) throws ParseException {
179 
180         ParseException ex = null;
181         for (int i = 0; i < HTTP_DATE_FORMATS.length; i++) {
182             try {
183                 Date d = HTTP_DATE_FORMATS[i].parse(date);
184 
185                 if (LOG.isDebugEnabled()) {
186                     LOG.debug("ParseHttpDate returns '" + d + "' for string '"
187                             + date + "'.");
188                 }
189 
190                 return d;
191 
192             } catch (ParseException e) {
193                 ex = e;
194             }
195         }
196 
197         if (ex == null) {
198             if (LOG.isDebugEnabled()) {
199                 LOG.debug("ParseHttpDate has not recognized date '" + date
200                         + "'.");
201             }
202 
203             return null;
204         }
205 
206         LOG.error("ParseHttpDate has not recognized date '" + date + "'.", ex);
207 
208         throw ex;
209     }
210 
211     protected final String getParameter(String name) {
212         return getParameter(getServletConfig(), name);
213     }
214 
215     public static final String getParameter(ServletConfig config, String name) {
216         String initParameter = config.getInitParameter(name);
217         if (initParameter != null) {
218             return initParameter;
219         }
220 
221         initParameter = config.getServletContext().getInitParameter(name);
222         return initParameter;
223     }
224 
225     public static final void setNoCache(HttpServletResponse response) {
226         // Set standard HTTP/1.0 no-cache header.
227         response.setHeader(HTTP_PRAGMA, "no-cache");
228 
229         // Set standard HTTP/1.1 no-cache headers.
230         response.setHeader(HTTP_CACHE_CONTROL,
231                 "no-cache, no-store, must-revalidate");
232 
233         // Set IE extended HTTP/1.1 no-cache headers (use addHeader)
234         response.addHeader(HTTP_CACHE_CONTROL, "post-check=0, pre-check=0");
235 
236         response.setDateHeader(HTTP_EXPIRES, 0);
237         response.setDateHeader(HTTP_LAST_MODIFIED, System.currentTimeMillis());
238     }
239 
240     public static void setVaryAcceptEncoding(HttpServletResponse response) {
241         response.setHeader(HTTP_VARY, ACCEPT_ENCODING);
242 
243         if (LOG.isDebugEnabled()) {
244             LOG.debug("Set Vary accept encoding.");
245         }
246     }
247 
248     public static void setVaryUserAgent(HttpServletResponse response) {
249         response.setHeader(HTTP_VARY, USER_AGENT);
250 
251         if (LOG.isDebugEnabled()) {
252             LOG.debug("Set Vary user agent.");
253         }
254     }
255 
256     public static void setGzipContentEncoding(HttpServletResponse response,
257             boolean declareVaryAcceptEncoding) {
258         response.setHeader(HTTP_CONTENT_ENCODING, GZIP_CONTENT_ENCODING);
259         if (declareVaryAcceptEncoding) {
260             response.setHeader(HTTP_VARY, ACCEPT_ENCODING);
261         }
262 
263         if (LOG.isDebugEnabled()) {
264             LOG.debug("Set GZIP content encoding.");
265         }
266     }
267 
268     protected void service(HttpServletRequest req, HttpServletResponse resp)
269             throws ServletException, IOException {
270         try {
271             if (LOG.isTraceEnabled()) {
272                 LOG.trace("Process http request requestURI='"
273                         + req.getRequestURI() + "'.");
274             }
275 
276             super.service(req, resp);
277 
278             if (LOG.isTraceEnabled()) {
279                 LOG.trace("Http request processed requestURI='"
280                         + req.getRequestURI() + "'. (response contentType="
281                         + resp.getContentType() + ")");
282             }
283 
284         } catch (RuntimeException ex) {
285             LOG.error("Exception request=" + req.getRequestURI(), ex);
286 
287         } catch (Error ex) {
288             LOG.error("Error request=" + req.getRequestURI(), ex);
289         }
290     }
291 
292 }