/* | |
* Licensed to the Apache Software Foundation (ASF) under one or more | |
* contributor license agreements. The ASF licenses this file to You | |
* under the Apache License, Version 2.0 (the "License"); you may not | |
* use this file except in compliance with the License. | |
* You may obtain a copy of the License at | |
* | |
* http://www.apache.org/licenses/LICENSE-2.0 | |
* | |
* Unless required by applicable law or agreed to in writing, software | |
* distributed under the License is distributed on an "AS IS" BASIS, | |
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
* See the License for the specific language governing permissions and | |
* limitations under the License. For additional information regarding | |
* copyright in this work, please see the NOTICE file in the top level | |
* directory of this distribution. | |
*/ | |
package org.apache.roller.weblogger.ui.rendering.util; | |
import java.text.SimpleDateFormat; | |
import java.util.Date; | |
import javax.servlet.http.HttpServletRequest; | |
import javax.servlet.http.HttpServletResponse; | |
import org.apache.commons.logging.Log; | |
import org.apache.commons.logging.LogFactory; | |
import org.apache.roller.util.RollerConstants; | |
import org.apache.roller.util.DateUtil; | |
import org.apache.roller.weblogger.ui.rendering.mobile.MobileDeviceRepository; | |
/** | |
* Utility class to localize the modification date header-related logic. | |
*/ | |
public final class ModDateHeaderUtil { | |
private static Log log = LogFactory.getLog(ModDateHeaderUtil.class); | |
/** | |
* Instantiates a new mod date header util. | |
*/ | |
private ModDateHeaderUtil() { | |
} | |
/** | |
* Sets the HTTP response status to 304 (NOT MODIFIED) if the request | |
* contains an If-Modified-Since header that specifies a time that is at or | |
* after the time specified by the value of lastModifiedTimeMillis | |
* <em>truncated to second granularity</em>. Returns true if the response | |
* status was set, false if not. | |
* | |
* @param request | |
* the request | |
* @param response | |
* the response | |
* @param lastModifiedTimeMillis | |
* the last modified time millis | |
* @param deviceType | |
* the device type. Null to ignore ie no theme device type | |
* swithing check. | |
* | |
* @return true if a response status was sent, false otherwise. | |
*/ | |
public static boolean respondIfNotModified(HttpServletRequest request, | |
HttpServletResponse response, long lastModifiedTimeMillis, | |
MobileDeviceRepository.DeviceType deviceType) { | |
long sinceDate; | |
try { | |
sinceDate = request.getDateHeader("If-Modified-Since"); | |
} catch (IllegalArgumentException ex) { | |
// this indicates there was some problem parsing the header value as | |
// a date | |
return false; | |
} | |
// truncate to seconds | |
lastModifiedTimeMillis -= (lastModifiedTimeMillis % RollerConstants.SEC_IN_MS); | |
if (log.isDebugEnabled()) { | |
SimpleDateFormat dateFormat = new SimpleDateFormat( | |
"EEE MMM dd 'at' h:mm:ss a"); | |
log.debug("since date = " | |
+ DateUtil.format(new Date(sinceDate), dateFormat)); | |
log.debug("last mod date (trucated to seconds) = " | |
+ DateUtil.format(new Date(lastModifiedTimeMillis), | |
dateFormat)); | |
} | |
// Set device type for device switching | |
String eTag = null; | |
if (deviceType != null) { | |
// int code = new HashCodeBuilder().append(deviceType.name()) | |
// .hashCode(); | |
// eTag = String.valueOf(code); | |
eTag = deviceType.name(); | |
} | |
String previousToken = request.getHeader("If-None-Match"); | |
if (eTag != null && previousToken != null && eTag.equals(previousToken) | |
&& lastModifiedTimeMillis <= sinceDate | |
|| (eTag == null || previousToken == null) | |
&& lastModifiedTimeMillis <= sinceDate) { | |
if (log.isDebugEnabled()) { | |
log.debug("NOT MODIFIED " + request.getRequestURL()); | |
} | |
response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); | |
// use the same date we sent when we created the ETag the | |
// first time through | |
response.setHeader("Last-Modified", | |
request.getHeader("If-Modified-Since")); | |
return true; | |
} else { | |
return false; | |
} | |
} | |
/** | |
* Set the Last-Modified header using the given time in milliseconds. Note | |
* that because the header has the granularity of one second, the value will | |
* get truncated to the nearest second that does not exceed the provided | |
* value. | |
* <p/> | |
* This will also set the Expires header to a date in the past. This forces | |
* clients to revalidate the cache each time. | |
* | |
* @param response | |
* the response | |
* @param lastModifiedTimeMillis | |
* the last modified time millis | |
* @param deviceType | |
* the device type. Null to ignore ie no theme device type | |
* swithing check. | |
*/ | |
public static void setLastModifiedHeader(HttpServletResponse response, | |
long lastModifiedTimeMillis, | |
MobileDeviceRepository.DeviceType deviceType) { | |
// Save our device type for device switching. Must use chaching on | |
// headers for this to work. | |
if (deviceType != null) { | |
// int code = new HashCodeBuilder().append(deviceType.name()) | |
// .hashCode(); | |
// String eTag = String.valueOf(code); | |
String eTag = deviceType.name(); | |
response.setHeader("ETag", eTag); | |
} | |
response.setDateHeader("Last-Modified", lastModifiedTimeMillis); | |
// Force clients to revalidate each time | |
// See RFC 2616 (HTTP 1.1 spec) secs 14.21, 13.2.1 | |
response.setDateHeader("Expires", 0); | |
// We may also want this (See 13.2.1 and 14.9.4) | |
// response.setHeader("Cache-Control","must-revalidate"); | |
} | |
} |