You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2014/06/21 01:13:15 UTC

git commit: TAP5-2352: Add hooks to StreamableResource to enable special Response logic

Repository: tapestry-5
Updated Branches:
  refs/heads/master 09985ff63 -> 6ee341ae2


TAP5-2352: Add hooks to StreamableResource to enable special Response logic


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

Branch: refs/heads/master
Commit: 6ee341ae2578d0a455a6deccb392a0f352c6f624
Parents: 09985ff
Author: Howard M. Lewis Ship <hl...@apache.org>
Authored: Fri Jun 20 15:35:55 2014 -0700
Committer: Howard M. Lewis Ship <hl...@apache.org>
Committed: Fri Jun 20 15:36:12 2014 -0700

----------------------------------------------------------------------
 .../internal/services/ResourceStreamerImpl.java |  14 ++--
 .../services/assets/CSSURLRewriter.java         |   4 +-
 .../assets/CompressedStreamableResource.java    |   4 +-
 .../assets/JavaScriptStackAssemblerImpl.java    |   4 +-
 .../services/assets/StreamableResourceImpl.java |  41 +++++++++++-
 .../assets/StreamableResourceSourceImpl.java    |   4 +-
 .../services/assets/AssetRequestHandler.java    |   3 -
 .../services/assets/ResponseCustomizer.java     |  33 ++++++++++
 .../services/assets/StreamableResource.java     |  20 +++++-
 tapestry-core/src/test/app5/tapestry_banner.gif | Bin 0 -> 3205 bytes
 .../app5/ResourceCustomizerTests.groovy         |  34 ++++++++++
 .../integration/app5/services/AppModule.groovy  |  36 +++++++++-
 .../integration/app5/components/Layout.tml      |  66 ++++++++++---------
 .../tapestry5/integration/app5/pages/Index.tml  |   2 +
 .../webresources/AbstractMinimizer.java         |   4 +-
 15 files changed, 206 insertions(+), 63 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6ee341ae/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 cbfe264..d2aec0a 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
@@ -1,5 +1,3 @@
-// Copyright 2006-2013 The Apache Software Foundation
-//
 // Licensed 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
@@ -23,10 +21,7 @@ import org.apache.tapestry5.ioc.Resource;
 import org.apache.tapestry5.ioc.annotations.Symbol;
 import org.apache.tapestry5.services.Request;
 import org.apache.tapestry5.services.Response;
-import org.apache.tapestry5.services.assets.CompressionStatus;
-import org.apache.tapestry5.services.assets.StreamableResource;
-import org.apache.tapestry5.services.assets.StreamableResourceProcessing;
-import org.apache.tapestry5.services.assets.StreamableResourceSource;
+import org.apache.tapestry5.services.assets.*;
 
 import javax.servlet.http.HttpServletResponse;
 import java.io.IOException;
@@ -181,6 +176,13 @@ public class ResourceStreamerImpl implements ResourceStreamer
             response.setHeader(InternalConstants.CONTENT_ENCODING_HEADER, InternalConstants.GZIP_CONTENT_ENCODING);
         }
 
+        ResponseCustomizer responseCustomizer = streamable.getResponseCustomizer();
+
+        if (responseCustomizer != null)
+        {
+            responseCustomizer.customizeResponse(streamable, response);
+        }
+
         OutputStream os = response.getOutputStream(streamable.getContentType());
 
         streamable.streamTo(os);

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6ee341ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/CSSURLRewriter.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/CSSURLRewriter.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/CSSURLRewriter.java
index d5053f5..2678411 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/CSSURLRewriter.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/CSSURLRewriter.java
@@ -1,5 +1,3 @@
-// Copyright 2013 The Apache Software Foundation
-//
 // Licensed 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
@@ -118,7 +116,7 @@ public class CSSURLRewriter extends DelegatingSRS
                         return new StreamableResourceImpl(base.getDescription(), "text/css",
                                 CompressionStatus.COMPRESSABLE,
                                 base.getLastModified(),
-                                cache, checksumGenerator);
+                                cache, checksumGenerator, base.getResponseCustomizer());
                     }
                 });
     }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6ee341ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/CompressedStreamableResource.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/CompressedStreamableResource.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/CompressedStreamableResource.java
index 5dc7ea2..d6fb161 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/CompressedStreamableResource.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/CompressedStreamableResource.java
@@ -1,5 +1,3 @@
-// Copyright 2013 The Apache Software Foundation
-//
 // Licensed 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
@@ -33,7 +31,7 @@ public class CompressedStreamableResource extends StreamableResourceImpl
 {
     public CompressedStreamableResource(StreamableResource base, AssetChecksumGenerator assetChecksumGenerator) throws IOException
     {
-        super(base.getDescription(), base.getContentType(), CompressionStatus.COMPRESSED, base.getLastModified(), compressContent(base), assetChecksumGenerator);
+        super(base.getDescription(), base.getContentType(), CompressionStatus.COMPRESSED, base.getLastModified(), compressContent(base), assetChecksumGenerator, base.getResponseCustomizer());
 
         assert base.getCompression() == CompressionStatus.COMPRESSABLE;
     }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6ee341ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/JavaScriptStackAssemblerImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/JavaScriptStackAssemblerImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/JavaScriptStackAssemblerImpl.java
index d7b426e..0494d08 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/JavaScriptStackAssemblerImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/JavaScriptStackAssemblerImpl.java
@@ -1,5 +1,3 @@
-// Copyright 2013 The Apache Software Foundation
-//
 // Licensed 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
@@ -195,7 +193,7 @@ public class JavaScriptStackAssemblerImpl implements JavaScriptStackAssembler
             return new StreamableResourceImpl(
                     description.toString(),
                     JAVASCRIPT_CONTENT_TYPE, CompressionStatus.COMPRESSABLE, lastModified,
-                    new BytestreamCache(outputStream), checksumGenerator);
+                    new BytestreamCache(outputStream), checksumGenerator, null);
         }
     }
 

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6ee341ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StreamableResourceImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StreamableResourceImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StreamableResourceImpl.java
index 6e4e7e7..d057d9f 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StreamableResourceImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StreamableResourceImpl.java
@@ -1,5 +1,3 @@
-// Copyright 2013 The Apache Software Foundation
-//
 // Licensed 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
@@ -14,8 +12,10 @@
 
 package org.apache.tapestry5.internal.services.assets;
 
+import org.apache.tapestry5.services.Response;
 import org.apache.tapestry5.services.assets.AssetChecksumGenerator;
 import org.apache.tapestry5.services.assets.CompressionStatus;
+import org.apache.tapestry5.services.assets.ResponseCustomizer;
 import org.apache.tapestry5.services.assets.StreamableResource;
 
 import java.io.IOException;
@@ -34,7 +34,9 @@ public class StreamableResourceImpl implements StreamableResource
 
     protected final AssetChecksumGenerator assetChecksumGenerator;
 
-    public StreamableResourceImpl(String description, String contentType, CompressionStatus compression, long lastModified, BytestreamCache bytestreamCache, AssetChecksumGenerator assetChecksumGenerator)
+    protected final ResponseCustomizer responseCustomizer;
+
+    public StreamableResourceImpl(String description, String contentType, CompressionStatus compression, long lastModified, BytestreamCache bytestreamCache, AssetChecksumGenerator assetChecksumGenerator, ResponseCustomizer responseCustomizer)
     {
         this.lastModified = lastModified;
         this.description = description;
@@ -42,6 +44,7 @@ public class StreamableResourceImpl implements StreamableResource
         this.contentType = contentType;
         this.compression = compression;
         this.assetChecksumGenerator = assetChecksumGenerator;
+        this.responseCustomizer = responseCustomizer;
     }
 
     public String getDescription()
@@ -92,4 +95,36 @@ public class StreamableResourceImpl implements StreamableResource
         // here (but must be threads-afe).
         return assetChecksumGenerator.generateChecksum(this);
     }
+
+    @Override
+    public StreamableResource addResponseCustomizer(final ResponseCustomizer customizer)
+    {
+        final ResponseCustomizer oldCustomizer = responseCustomizer;
+
+        if (oldCustomizer == null)
+        {
+            return withNewResourceCustomizer(customizer);
+        }
+
+        return withNewResourceCustomizer(new ResponseCustomizer()
+        {
+            @Override
+            public void customizeResponse(StreamableResource resource, Response response) throws IOException
+            {
+                oldCustomizer.customizeResponse(resource, response);
+                customizer.customizeResponse(resource, response);
+            }
+        });
+    }
+
+    @Override
+    public ResponseCustomizer getResponseCustomizer()
+    {
+        return responseCustomizer;
+    }
+
+    private StreamableResourceImpl withNewResourceCustomizer(ResponseCustomizer customizer)
+    {
+        return new StreamableResourceImpl(description, contentType, compression, lastModified, bytestreamCache, assetChecksumGenerator, customizer);
+    }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6ee341ae/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StreamableResourceSourceImpl.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StreamableResourceSourceImpl.java b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StreamableResourceSourceImpl.java
index 14e03dd..1c4a67a 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StreamableResourceSourceImpl.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/internal/services/assets/StreamableResourceSourceImpl.java
@@ -1,5 +1,3 @@
-// Copyright 2011, 2012 The Apache Software Foundation
-//
 // Licensed 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
@@ -95,7 +93,7 @@ public class StreamableResourceSourceImpl implements StreamableResourceSource
         long lastModified = resourceChangeTracker.trackResource(baseResource);
 
         return new StreamableResourceImpl(baseResource.toString(), contentType, compressable ? CompressionStatus.COMPRESSABLE
-                : CompressionStatus.NOT_COMPRESSABLE, lastModified, bytestreamCache, checksumGenerator);
+                : CompressionStatus.NOT_COMPRESSABLE, lastModified, bytestreamCache, checksumGenerator, null);
     }
 
     private BytestreamCache readStream(InputStream stream) throws IOException

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6ee341ae/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetRequestHandler.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetRequestHandler.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetRequestHandler.java
index e1eb7ed..e8c2e99 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetRequestHandler.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/AssetRequestHandler.java
@@ -1,5 +1,3 @@
-// Copyright 2010, 2012, 2013 The Apache Software Foundation
-//
 // Licensed 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
@@ -60,7 +58,6 @@ public interface AssetRequestHandler
      * @param extraPath
      *         additional path to identify the specific asset
      * @return true if request was handled (and response sent), false if asset not found
-     * @see org.apache.tapestry5.TapestryConstants#COMPRESS_CONTENT
      */
     boolean handleAssetRequest(Request request, Response response, String extraPath) throws IOException;
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6ee341ae/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/ResponseCustomizer.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/ResponseCustomizer.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/ResponseCustomizer.java
new file mode 100644
index 0000000..6958bdf
--- /dev/null
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/ResponseCustomizer.java
@@ -0,0 +1,33 @@
+// Licensed 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.
+
+package org.apache.tapestry5.services.assets;
+
+import org.apache.tapestry5.services.Response;
+
+import java.io.IOException;
+
+/**
+ * Used to customize the response prior to streaming content to the client; typically this is used to
+ * set special headers.
+ *
+ * @see org.apache.tapestry5.services.assets.StreamableResource#addResponseCustomizer(ResponseCustomizer)
+ * @since 5.4
+ */
+public interface ResponseCustomizer
+{
+    /**
+     * Invoked to customize the response; these are invoked in the order they are added to the
+     * StreamableResource.
+     */
+    void customizeResponse(StreamableResource resource, Response response) throws IOException;
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6ee341ae/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/StreamableResource.java
----------------------------------------------------------------------
diff --git a/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/StreamableResource.java b/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/StreamableResource.java
index ab6cd16..bfa3eb6 100644
--- a/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/StreamableResource.java
+++ b/tapestry-core/src/main/java/org/apache/tapestry5/services/assets/StreamableResource.java
@@ -1,5 +1,3 @@
-// Copyright 2011, 2013 The Apache Software Foundation
-//
 // Licensed 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
@@ -77,8 +75,24 @@ public interface StreamableResource
      * based on the uncompressed content.
      *
      * @return checksum for uncompressed content
-     * @since 5.4
      * @see AssetChecksumGenerator#generateChecksum(StreamableResource)
+     * @since 5.4
      */
     String getChecksum() throws IOException;
+
+
+    /**
+     * Returns a new StreamableResource that includes the provided customizer. Customizers are invoked
+     * in the order they are added.
+     *
+     * @since 5.4
+     */
+    StreamableResource addResponseCustomizer(ResponseCustomizer customizer);
+
+    /**
+     * Returns the customizer, if any, for this resource.  This may represent an aggregate customizer.
+     *
+     * @since 5.4
+     */
+    ResponseCustomizer getResponseCustomizer();
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6ee341ae/tapestry-core/src/test/app5/tapestry_banner.gif
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/app5/tapestry_banner.gif b/tapestry-core/src/test/app5/tapestry_banner.gif
new file mode 100644
index 0000000..42118f9
Binary files /dev/null and b/tapestry-core/src/test/app5/tapestry_banner.gif differ

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6ee341ae/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app5/ResourceCustomizerTests.groovy
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app5/ResourceCustomizerTests.groovy b/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app5/ResourceCustomizerTests.groovy
new file mode 100644
index 0000000..0ce49d6
--- /dev/null
+++ b/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app5/ResourceCustomizerTests.groovy
@@ -0,0 +1,34 @@
+package org.apache.tapestry5.integration.app5
+
+import org.apache.tapestry5.integration.TapestryCoreTestCase
+import org.apache.tapestry5.test.TapestryTestConfiguration
+import org.testng.annotations.Test
+
+
+@TapestryTestConfiguration(webAppFolder = "src/test/app5")
+class ResourceCustomizerTests extends TapestryCoreTestCase {
+
+
+    @Test
+    void response_header_present() {
+
+        openBaseURL()
+
+        def src = getAttribute("//img[@id='banner']/@src")
+
+        // println "src=$src"
+
+        def url = new URL("$baseURL${src.substring(1)}")
+
+        def connection = url.openConnection()
+
+        connection.connect()
+
+        def tag = connection.getHeaderField("X-Robots-Tag")
+
+        // println connection.getHeaderFields()
+
+        assertEquals tag, "noindex"
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6ee341ae/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app5/services/AppModule.groovy
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app5/services/AppModule.groovy b/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app5/services/AppModule.groovy
index 3f76e28..33c0f5b 100644
--- a/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app5/services/AppModule.groovy
+++ b/tapestry-core/src/test/groovy/org/apache/tapestry5/integration/app5/services/AppModule.groovy
@@ -1,5 +1,3 @@
-// Copyright 2011 The Apache Software Foundation
-//
 // Licensed 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
@@ -18,10 +16,14 @@ import org.apache.tapestry5.SymbolConstants
 import org.apache.tapestry5.func.F
 import org.apache.tapestry5.integration.app5.Client
 import org.apache.tapestry5.integration.app5.ClientTracker
+import org.apache.tapestry5.internal.services.assets.DelegatingSRS
 import org.apache.tapestry5.ioc.MappedConfiguration
 import org.apache.tapestry5.ioc.Resource
+import org.apache.tapestry5.ioc.annotations.Decorate
 import org.apache.tapestry5.model.ComponentModel
 import org.apache.tapestry5.services.ApplicationStateManager
+import org.apache.tapestry5.services.Response
+import org.apache.tapestry5.services.assets.*
 import org.apache.tapestry5.services.pageload.ComponentRequestSelectorAnalyzer
 import org.apache.tapestry5.services.pageload.ComponentResourceLocator
 import org.apache.tapestry5.services.pageload.ComponentResourceSelector
@@ -36,7 +38,7 @@ class AppModule {
     def decorateComponentRequestSelectorAnalyzer(ComponentRequestSelectorAnalyzer delegate, ApplicationStateManager mgr) {
         return {
             def selector = delegate.buildSelectorForRequest()
-            def tracker = mgr.getIfExists (ClientTracker.class)
+            def tracker = mgr.getIfExists(ClientTracker.class)
 
             tracker == null ? selector : selector.withAxis(Client.class, tracker.client)
         } as ComponentRequestSelectorAnalyzer
@@ -44,6 +46,7 @@ class AppModule {
 
     def decorateComponentResourceLocator(ComponentResourceLocator delegate) {
         return new ComponentResourceLocator() {
+
             Resource locateTemplate(ComponentModel model, ComponentResourceSelector selector) {
                 def client = selector.getAxis(Client.class)
 
@@ -80,4 +83,31 @@ class AppModule {
             }
         }
     }
+
+    @Decorate(id = "XRobots", serviceInterface = StreamableResourceSource.class)
+    def enableXRobotsHeader(StreamableResourceSource delegate) {
+
+        return new DelegatingSRS(delegate) {
+
+            @Override
+            StreamableResource getStreamableResource(Resource baseResource, StreamableResourceProcessing processing, ResourceDependencies dependencies) throws IOException {
+
+                def streamable = delegate.getStreamableResource(baseResource, processing, dependencies)
+
+                if (streamable == null) {
+                    return streamable
+                }
+                else {
+                    return streamable.addResponseCustomizer(new ResponseCustomizer() {
+
+                        @Override
+                        void customizeResponse(StreamableResource resource, Response response) throws IOException {
+                            response.setHeader("X-Robots-Tag", "noindex")
+                        }
+                    })
+                }
+
+            }
+        }
+    }
 }

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6ee341ae/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app5/components/Layout.tml
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app5/components/Layout.tml b/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app5/components/Layout.tml
index 6d0797a..59d5038 100644
--- a/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app5/components/Layout.tml
+++ b/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app5/components/Layout.tml
@@ -1,31 +1,37 @@
-<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd" xmlns:p="tapestry:parameter">
-  <head>
-    <title>Default Layout</title>
-  </head>
-  <body>
-    <h1>Default Layout</h1>
-
-    <t:body/>
-
-    <hr/>
-
-    <t:renderobject object="request"/>
-
-    <t:if test="session">
-      <h2>Session</h2>
-      <dl>
-        <t:loop source="session.attributeNames" value="attributeName">
-          <dt>${attributeName}</dt>
-          <dd>
-            <t:renderobject object="session.getAttribute(attributeName)"/>
-          </dd>
-        </t:loop>
-      </dl>
-    </t:if>
-    
-    <p>
-    <t:actionlink t:id="reset">reset session</t:actionlink>
-    </p>
-
-  </body>
+<html xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd">
+    <head>
+        <title>Default Layout</title>
+    </head>
+    <body>
+        <div class="container">
+
+            <h1>Default Layout</h1>
+
+            <t:body/>
+
+
+            <div class="panel">
+
+                <t:renderobject object="request"/>
+
+                <t:if test="session">
+                    <h2>Session</h2>
+                    <dl>
+                        <t:loop source="session.attributeNames" value="attributeName">
+                            <dt>${attributeName}</dt>
+                            <dd>
+                                <t:renderobject object="session.getAttribute(attributeName)"/>
+                            </dd>
+                        </t:loop>
+                    </dl>
+                </t:if>
+            </div>
+
+            <div class="row">
+                <t:actionlink t:id="reset" class="btn btn-large btn-warning">reset session</t:actionlink>
+
+            </div>
+
+        </div>
+    </body>
 </html>
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6ee341ae/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app5/pages/Index.tml
----------------------------------------------------------------------
diff --git a/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app5/pages/Index.tml b/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app5/pages/Index.tml
index 7834638..7aa70eb 100644
--- a/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app5/pages/Index.tml
+++ b/tapestry-core/src/test/resources/org/apache/tapestry5/integration/app5/pages/Index.tml
@@ -1,5 +1,7 @@
 <t:layout xmlns:t="http://tapestry.apache.org/schema/tapestry_5_1_0.xsd" xmlns:p="tapestry:parameter">
 
+  <img id="banner" src="${context:tapestry_banner.gif}"/>
+
   <dl>
     <dt>app</dt>
     <dd id="app">${message:app-message}</dd>

http://git-wip-us.apache.org/repos/asf/tapestry-5/blob/6ee341ae/tapestry-webresources/src/main/java/org/apache/tapestry5/internal/webresources/AbstractMinimizer.java
----------------------------------------------------------------------
diff --git a/tapestry-webresources/src/main/java/org/apache/tapestry5/internal/webresources/AbstractMinimizer.java b/tapestry-webresources/src/main/java/org/apache/tapestry5/internal/webresources/AbstractMinimizer.java
index b2bb015..849b691 100644
--- a/tapestry-webresources/src/main/java/org/apache/tapestry5/internal/webresources/AbstractMinimizer.java
+++ b/tapestry-webresources/src/main/java/org/apache/tapestry5/internal/webresources/AbstractMinimizer.java
@@ -1,5 +1,3 @@
-// Copyright 2011-2013 The Apache Software Foundation
-//
 // Licensed 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
@@ -80,7 +78,7 @@ public abstract class AbstractMinimizer implements ResourceMinimizer
 
         StreamableResource output = new StreamableResourceImpl("minimized " + input.getDescription(),
                 input.getContentType(), CompressionStatus.COMPRESSABLE,
-                input.getLastModified(), new BytestreamCache(bos), checksumGenerator);
+                input.getLastModified(), new BytestreamCache(bos), checksumGenerator, input.getResponseCustomizer());
 
         if (logger.isInfoEnabled())
         {