You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@tapestry.apache.org by hl...@apache.org on 2013/04/02 15:01:37 UTC

[3/5] git commit: Add ETag support

Add ETag support


Project: http://git-wip-us.apache.org/repos/asf/tapestry-5/repo
Commit: http://git-wip-us.apache.org/repos/asf/tapestry-5/commit/97b0d4fb
Tree: http://git-wip-us.apache.org/repos/asf/tapestry-5/tree/97b0d4fb
Diff: http://git-wip-us.apache.org/repos/asf/tapestry-5/diff/97b0d4fb

Branch: refs/heads/master
Commit: 97b0d4fba108295858dfd9b53deb14004530dade
Parents: 398f6bd
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Tue Apr 2 05:51:26 2013 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Tue Apr 2 06:01:18 2013 -0700

----------------------------------------------------------------------
 .../internal/services/ResourceStreamerImpl.java    |   21 ++++++++
 .../services/assets/StackAssetRequestHandler.java  |   40 ++++++++------
 .../services/javascript/ModuleDispatcher.java      |    4 +-
 3 files changed, 47 insertions(+), 18 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/97b0d4fb/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamerImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamerImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamerImpl.java
index c4a6464..8daec39 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamerImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/ResourceStreamerImpl.java
@@ -125,14 +125,35 @@ public class ResourceStreamerImpl implements ResourceStreamer
             }
         }
 
+        // ETag should be surrounded with quotes.
+        String token = "\"" + streamable.getChecksum() + "\"";
+
+        // Even when sending a 304, we want the ETag associated with the request.
+        // In most cases (except JavaScript modules), the checksum is also embedded into the URL.
+        // However, E-Tags are also useful for enabling caching inside intermediate servers, CDNs, etc.
+        response.setHeader("ETag", token);
+
+        // If the client can send the correct ETag token, then its cache already contains the correct
+        // content.
+
+        String providedToken = request.getHeader("If-None-Match");
+
+        if (providedToken != null && providedToken.equals(token)) {
+            response.setStatus(HttpServletResponse.SC_NOT_MODIFIED);
+            return;
+        }
+
         // Prevent the upstream code from compressing when we don't want to.
 
         response.disableCompression();
 
         response.setDateHeader("Last-Modified", lastModified);
 
+
         if (productionMode)
         {
+            // Starting in 5.4, this is a lot less necessary; any change to a Resource will result
+            // in a new asset URL with the changed checksum incorporated into the URL.
             response.setDateHeader("Expires", lastModified + InternalConstants.TEN_YEARS);
         }
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/97b0d4fb/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StackAssetRequestHandler.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StackAssetRequestHandler.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StackAssetRequestHandler.java
index 31c6b08..39f1e31 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StackAssetRequestHandler.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StackAssetRequestHandler.java
@@ -14,19 +14,16 @@
 
 package org.apache.tapestry5.internal.services.assets;
 
-import org.apache.tapestry5.SymbolConstants;
 import org.apache.tapestry5.internal.services.ResourceStreamer;
+import org.apache.tapestry5.ioc.IOOperation;
 import org.apache.tapestry5.ioc.OperationTracker;
-import org.apache.tapestry5.ioc.annotations.Symbol;
 import org.apache.tapestry5.services.LocalizationSetter;
 import org.apache.tapestry5.services.Request;
 import org.apache.tapestry5.services.Response;
 import org.apache.tapestry5.services.ResponseCompressionAnalyzer;
 import org.apache.tapestry5.services.assets.AssetRequestHandler;
-import org.apache.tapestry5.services.assets.ResourceMinimizer;
 import org.apache.tapestry5.services.assets.StreamableResource;
-import org.apache.tapestry5.services.assets.StreamableResourceSource;
-import org.apache.tapestry5.services.javascript.JavaScriptStackSource;
+import org.slf4j.Logger;
 
 import java.io.IOException;
 import java.util.regex.Matcher;
@@ -34,6 +31,8 @@ import java.util.regex.Pattern;
 
 public class StackAssetRequestHandler implements AssetRequestHandler
 {
+    private final Logger logger;
+
     private final LocalizationSetter localizationSetter;
 
     private final ResponseCompressionAnalyzer compressionAnalyzer;
@@ -49,12 +48,13 @@ public class StackAssetRequestHandler implements AssetRequestHandler
 
     private final JavaScriptStackAssembler javaScriptStackAssembler;
 
-    public StackAssetRequestHandler(LocalizationSetter localizationSetter,
+    public StackAssetRequestHandler(Logger logger, LocalizationSetter localizationSetter,
                                     ResponseCompressionAnalyzer compressionAnalyzer,
                                     ResourceStreamer resourceStreamer,
                                     OperationTracker tracker,
                                     JavaScriptStackAssembler javaScriptStackAssembler)
     {
+        this.logger = logger;
         this.localizationSetter = localizationSetter;
         this.compressionAnalyzer = compressionAnalyzer;
         this.resourceStreamer = resourceStreamer;
@@ -64,22 +64,25 @@ public class StackAssetRequestHandler implements AssetRequestHandler
 
     public boolean handleAssetRequest(Request request, Response response, final String extraPath) throws IOException
     {
-        tracker.perform(String.format("Streaming asset stack %s", extraPath),
-                new org.apache.tapestry5.ioc.IOOperation<Void>()
+        return tracker.perform(String.format("Streaming asset stack %s", extraPath),
+                new IOOperation<Boolean>()
                 {
-                    public Void perform() throws IOException
+                    public Boolean perform() throws IOException
                     {
                         boolean compress = compressionAnalyzer.isGZipSupported();
 
                         StreamableResource resource = getResource(extraPath, compress);
 
+                        if (resource == null)
+                        {
+                            return false;
+                        }
+
                         resourceStreamer.streamResource(resource);
 
-                        return null;
+                        return true;
                     }
                 });
-
-        return true;
     }
 
     private StreamableResource getResource(String extraPath, boolean compressed) throws IOException
@@ -88,11 +91,12 @@ public class StackAssetRequestHandler implements AssetRequestHandler
 
         if (!matcher.matches())
         {
-            throw new RuntimeException("Invalid path for a stack asset request.");
-        }
+            logger.warn(String.format("Unable to parse '%s' as an asset stack path", extraPath));
 
-        // TODO: Extract the stack's aggregate checksum as well
+            return null;
+        }
 
+        String checksum = matcher.group(1);
         String localeName = matcher.group(2);
         String stackName = matcher.group(3);
 
@@ -101,8 +105,10 @@ public class StackAssetRequestHandler implements AssetRequestHandler
 
         localizationSetter.setNonPersistentLocaleFromLocaleName(localeName);
 
-        // TODO: Verify request checksum against actual
+        StreamableResource resource = javaScriptStackAssembler.assembleJavaScriptResourceForStack(stackName, compressed);
 
-        return javaScriptStackAssembler.assembleJavaScriptResourceForStack(stackName, compressed);
+        return checksum.equals(resource.getChecksum())
+                ? resource
+                : null;
     }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/97b0d4fb/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/ModuleDispatcher.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/ModuleDispatcher.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/ModuleDispatcher.java
index b81dd0f..284e23c 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/ModuleDispatcher.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/javascript/ModuleDispatcher.java
@@ -69,7 +69,9 @@ public class ModuleDispatcher implements Dispatcher
         String extraPath = requestPath.substring(prefix.length());
 
         // Ensure request ends with '.js'.  That's the extension tacked on by RequireJS because it expects there
-        // to be a hierarchy of static JavaScript files here.
+        // to be a hierarchy of static JavaScript files here. In reality, we may be cross-compiling CoffeeScript to
+        // JavaScript, or generating modules on-the-fly, or exposing arbitrary Resources from somewhere on the classpath
+        // as a module.
 
         int dotx = extraPath.lastIndexOf('.');