Modified: roller/trunk/app/src/main/java/org/apache/roller/weblogger/ui/rendering/servlets/ResourceServlet.java URL: http://svn.apache.org/viewvc/roller/trunk/app/src/main/java/org/apache/roller/weblogger/ui/rendering/servlets/ResourceServlet.java?rev=1530968&r1=1530967&r2=1530968&view=diff ============================================================================== --- roller/trunk/app/src/main/java/org/apache/roller/weblogger/ui/rendering/servlets/ResourceServlet.java (original) +++ roller/trunk/app/src/main/java/org/apache/roller/weblogger/ui/rendering/servlets/ResourceServlet.java Thu Oct 10 13:19:58 2013 @@ -39,88 +39,87 @@ import org.apache.roller.weblogger.pojos import org.apache.roller.weblogger.ui.rendering.util.ModDateHeaderUtil; import org.apache.roller.weblogger.ui.rendering.util.WeblogResourceRequest; - /** - * Serves fixed-path files such as old-style uploads and theme resources, - * which must exist at a fixed-path even if moved in media file folders. + * Serves fixed-path files such as old-style uploads and theme resources, which + * must exist at a fixed-path even if moved in media file folders. */ public class ResourceServlet extends HttpServlet { private static Log log = LogFactory.getLog(ResourceServlet.class); - - private ServletContext context = null; + private ServletContext context = null; public void init(ServletConfig config) throws ServletException { super.init(config); log.info("Initializing ResourceServlet"); - + this.context = config.getServletContext(); } - /** * Handles requests for user uploaded resources. */ public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { - + Weblog weblog = null; String ctx = request.getContextPath(); String servlet = request.getServletPath(); String reqURI = request.getRequestURI(); - + WeblogResourceRequest resourceRequest = null; try { // parse the incoming request and extract the relevant data resourceRequest = new WeblogResourceRequest(request); weblog = resourceRequest.getWeblog(); - if(weblog == null) { - throw new WebloggerException("unable to lookup weblog: "+ - resourceRequest.getWeblogHandle()); + if (weblog == null) { + throw new WebloggerException("unable to lookup weblog: " + + resourceRequest.getWeblogHandle()); } - } catch(Exception e) { + } catch (Exception e) { // invalid resource request or weblog doesn't exist log.debug("error creating weblog resource request", e); response.sendError(HttpServletResponse.SC_NOT_FOUND); return; } - - log.debug("Resource requested ["+resourceRequest.getResourcePath()+"]"); - + + log.debug("Resource requested [" + resourceRequest.getResourcePath() + + "]"); + long resourceLastMod = 0; InputStream resourceStream = null; - + // first see if resource comes from weblog's shared theme try { WeblogTheme weblogTheme = weblog.getTheme(); - if(weblogTheme != null) { - ThemeResource resource = weblogTheme.getResource(resourceRequest.getResourcePath()); - if(resource != null) { + if (weblogTheme != null) { + ThemeResource resource = weblogTheme + .getResource(resourceRequest.getResourcePath()); + if (resource != null) { resourceLastMod = resource.getLastModified(); resourceStream = resource.getInputStream(); } } } catch (Exception ex) { - // hmmm, some kind of error getting theme. that's an error. + // hmmm, some kind of error getting theme. that's an error. response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); return; } - + // if not from theme then see if resource is in weblog's upload dir - if(resourceStream == null) { + if (resourceStream == null) { try { - MediaFileManager mmgr = - WebloggerFactory.getWeblogger().getMediaFileManager(); - MediaFile mf = mmgr.getMediaFileByOriginalPath( - weblog, resourceRequest.getResourcePath()); + MediaFileManager mmgr = WebloggerFactory.getWeblogger() + .getMediaFileManager(); + MediaFile mf = mmgr.getMediaFileByOriginalPath(weblog, + resourceRequest.getResourcePath()); resourceLastMod = mf.getLastModified(); resourceStream = mf.getInputStream(); - + } catch (Exception ex) { // still not found? then we don't have it, 404. log.debug("Unable to get resource", ex); @@ -128,34 +127,36 @@ public class ResourceServlet extends Htt return; } } - + // Respond with 304 Not Modified if it is not modified. - if (ModDateHeaderUtil.respondIfNotModified(request, response, resourceLastMod)) { + if (ModDateHeaderUtil.respondIfNotModified(request, response, + resourceLastMod, resourceRequest.getDeviceType())) { return; } else { // set last-modified date - ModDateHeaderUtil.setLastModifiedHeader(response, resourceLastMod); + ModDateHeaderUtil.setLastModifiedHeader(response, resourceLastMod, + resourceRequest.getDeviceType()); } - // set the content type based on whatever is in our web.xml mime defs - response.setContentType(this.context.getMimeType(resourceRequest.getResourcePath())); - + response.setContentType(this.context.getMimeType(resourceRequest + .getResourcePath())); + OutputStream out = null; try { // ok, lets serve up the file byte[] buf = new byte[8192]; int length = 0; out = response.getOutputStream(); - while((length = resourceStream.read(buf)) > 0) { + while ((length = resourceStream.read(buf)) > 0) { out.write(buf, 0, length); } - + // close output stream out.close(); - + } catch (Exception ex) { - if(!response.isCommitted()) { + if (!response.isCommitted()) { response.reset(); response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); }
Modified: roller/trunk/app/src/main/java/org/apache/roller/weblogger/ui/rendering/util/ModDateHeaderUtil.java URL: http://svn.apache.org/viewvc/roller/trunk/app/src/main/java/org/apache/roller/weblogger/ui/rendering/util/ModDateHeaderUtil.java?rev=1530968&r1=1530967&r2=1530968&view=diff ============================================================================== --- roller/trunk/app/src/main/java/org/apache/roller/weblogger/ui/rendering/util/ModDateHeaderUtil.java (original) +++ roller/trunk/app/src/main/java/org/apache/roller/weblogger/ui/rendering/util/ModDateHeaderUtil.java Thu Oct 10 13:19:58 2013 @@ -18,76 +18,147 @@ package org.apache.roller.weblogger.ui.rendering.util; -import org.apache.commons.logging.Log; -import org.apache.commons.logging.LogFactory; +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.DateUtil; +import org.apache.roller.weblogger.ui.rendering.mobile.MobileDeviceRepository; + /** * Utility class to localize the modification date header-related logic. */ public class ModDateHeaderUtil { - private static final Log log = LogFactory.getLog(ModDateHeaderUtil.class); - // Utility class with static methods; inhibit construction - private 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 = 0; + 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 % 1000); + + 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"); - } + } - /** - * 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 - * @param response - * @param lastModifiedTimeMillis - * @return true if a response status was sent, false otherwise. - */ - public static boolean respondIfNotModified(HttpServletRequest request, - HttpServletResponse response, - long lastModifiedTimeMillis) { - long sinceDate = 0; - 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 % 1000); - log.debug("since date = " + sinceDate); - log.debug("last mod date (trucated to seconds) = " + lastModifiedTimeMillis); - if (lastModifiedTimeMillis <= sinceDate) { - log.debug("NOT MODIFIED " + request.getRequestURL()); - response.setStatus(HttpServletResponse.SC_NOT_MODIFIED); - 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 - * @param lastModifiedTimeMillis - */ - public static void setLastModifiedHeader(HttpServletResponse response, long lastModifiedTimeMillis) { - 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"); - } }
