This is an automated email from the ASF dual-hosted git repository.

svenmeier pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/wicket.git


The following commit(s) were added to refs/heads/master by this push:
     new 813d420  WICKET-6821 fixed header decorator ordering
813d420 is described below

commit 813d42093fd3e064ed80c35e2e0e3295f1a9b1a3
Author: Sven Meier <[email protected]>
AuthorDate: Wed Oct 7 09:06:11 2020 +0200

    WICKET-6821 fixed header decorator ordering
    
    The CSP header decorator must be added after any filtering decorator
    (i.e. immediately before the aggregator) so it has the chance to add CSP
    nonce before a possible filter might move the header item elsewhere.
---
 .../wicket/csp/ContentSecurityPolicySettings.java  |  2 +-
 .../html/HeaderResponseDecoratorCollection.java    | 42 ++++++++++++++++---
 .../wicket/markup/html/HeaderContributorTest.java  | 48 ++++++++++++++++++++++
 3 files changed, 86 insertions(+), 6 deletions(-)

diff --git 
a/wicket-core/src/main/java/org/apache/wicket/csp/ContentSecurityPolicySettings.java
 
b/wicket-core/src/main/java/org/apache/wicket/csp/ContentSecurityPolicySettings.java
index de79be8..c6f550e 100644
--- 
a/wicket-core/src/main/java/org/apache/wicket/csp/ContentSecurityPolicySettings.java
+++ 
b/wicket-core/src/main/java/org/apache/wicket/csp/ContentSecurityPolicySettings.java
@@ -206,7 +206,7 @@ public class ContentSecurityPolicySettings
        {
                application.getRequestCycleListeners().add(new 
CSPRequestCycleListener(this));
                application.getHeaderResponseDecorators()
-                       .add(response -> new 
CSPNonceHeaderResponseDecorator(response, this));
+                       .addPreResourceAggregationDecorator(response -> new 
CSPNonceHeaderResponseDecorator(response, this));
                application.mount(new ReportCSPViolationMapper(this));
        }
 
diff --git 
a/wicket-core/src/main/java/org/apache/wicket/markup/html/HeaderResponseDecoratorCollection.java
 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/HeaderResponseDecoratorCollection.java
index ce71f8b..1b94522 100644
--- 
a/wicket-core/src/main/java/org/apache/wicket/markup/html/HeaderResponseDecoratorCollection.java
+++ 
b/wicket-core/src/main/java/org/apache/wicket/markup/html/HeaderResponseDecoratorCollection.java
@@ -33,13 +33,15 @@ public class HeaderResponseDecoratorCollection implements 
IHeaderResponseDecorat
 {
        private final List<IHeaderResponseDecorator> decorators = new 
CopyOnWriteArrayList<>();
 
+       private IHeaderResponseDecorator resourceAggregation = 
ResourceAggregator::new;
+
        public HeaderResponseDecoratorCollection()
        {
-               decorators.add(response -> new ResourceAggregator(response));
+               decorators.add(resourceAggregation);
        }
 
        /**
-        * Adds a new {@link IHeaderResponseDecorator} that will be invoked 
prior to all already
+        * Adds a new {@link IHeaderResponseDecorator} that will decorates 
prior to all already
         * registered decorators. That means, the first to be added will be 
wrapped by a
         * {@link ResourceAggregator} like this: {@code new 
ResourceAggregator(first)}. The second will
         * be wrapped by the first and the aggregator: {@code new 
ResourceAggregator(first(second))}.
@@ -56,15 +58,42 @@ public class HeaderResponseDecoratorCollection implements 
IHeaderResponseDecorat
        }
 
        /**
-        * Adds a new {@link IHeaderResponseDecorator} that will be invoked 
after all already registered
+        * Adds a new {@link IHeaderResponseDecorator} that decorates 
immediately prior to resource
+        * aggregation.
+        * 
+        * @param decorator
+        *            The decorator to add, cannot be null.
+        * @return {@code this} for chaining.
+        * 
+        * @see ResourceAggregator
+        */
+       public HeaderResponseDecoratorCollection 
addPreResourceAggregationDecorator(
+               IHeaderResponseDecorator decorator)
+       {
+               Args.notNull(decorator, "decorator");
+
+               for (int i = 0; i < decorators.size(); i++)
+               {
+                       if (decorators.get(i) == resourceAggregation)
+                       {
+                               decorators.add(i, decorator);
+                               return this;
+                       }
+               }
+
+               throw new IllegalStateException("no resource aggregation");
+       }
+
+       /**
+        * Adds a new {@link IHeaderResponseDecorator} that decorates after all 
already registered
         * decorators.
         * 
         * @param decorator
         *            The decorator to add, cannot be null.
         * @return {@code this} for chaining.
         */
-       public HeaderResponseDecoratorCollection
-                       addPostProcessingDecorator(IHeaderResponseDecorator 
decorator)
+       public HeaderResponseDecoratorCollection addPostProcessingDecorator(
+               IHeaderResponseDecorator decorator)
        {
                Args.notNull(decorator, "decorator");
                decorators.add(decorator);
@@ -83,6 +112,7 @@ public class HeaderResponseDecoratorCollection implements 
IHeaderResponseDecorat
        {
                Args.notNull(decorator, "decorator");
                decorators.clear();
+               resourceAggregation = null;
                decorators.add(decorator);
                return this;
        }
@@ -92,7 +122,9 @@ public class HeaderResponseDecoratorCollection implements 
IHeaderResponseDecorat
        {
                IHeaderResponse ret = response;
                for (IHeaderResponseDecorator curDecorator : decorators)
+               {
                        ret = curDecorator.decorate(ret);
+               }
                return ret;
        }
 }
diff --git 
a/wicket-core/src/test/java/org/apache/wicket/markup/html/HeaderContributorTest.java
 
b/wicket-core/src/test/java/org/apache/wicket/markup/html/HeaderContributorTest.java
index f6d8d54..4936107 100644
--- 
a/wicket-core/src/test/java/org/apache/wicket/markup/html/HeaderContributorTest.java
+++ 
b/wicket-core/src/test/java/org/apache/wicket/markup/html/HeaderContributorTest.java
@@ -16,9 +16,11 @@
  */
 package org.apache.wicket.markup.html;
 
+import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
 import java.util.concurrent.atomic.AtomicBoolean;
+import java.util.concurrent.atomic.AtomicInteger;
 
 import org.apache.wicket.Component;
 import org.apache.wicket.MarkupContainer;
@@ -29,6 +31,8 @@ import 
org.apache.wicket.ajax.attributes.AjaxRequestAttributes;
 import org.apache.wicket.behavior.Behavior;
 import org.apache.wicket.markup.IMarkupResourceStreamProvider;
 import org.apache.wicket.markup.head.IHeaderResponse;
+import org.apache.wicket.markup.head.internal.HeaderResponse;
+import org.apache.wicket.request.Response;
 import org.apache.wicket.util.resource.IResourceStream;
 import org.apache.wicket.util.resource.StringResourceStream;
 import org.apache.wicket.util.tester.WicketTestCase;
@@ -56,6 +60,50 @@ class HeaderContributorTest extends WicketTestCase
        }
 
        /**
+        * WICKET-6821 ensure correct ordering of header decorators
+        */
+       @Test
+       void testHeaderContributorOrder()
+       {
+               final AtomicInteger counter = new AtomicInteger();
+               
+               class AssertOrder implements IHeaderResponseDecorator {
+                       
+                       private int order;
+                       
+                       AssertOrder(int order)
+                       {
+                               this.order = order;
+                       }
+                       
+                       @Override
+                       public IHeaderResponse decorate(IHeaderResponse 
response)
+                       {
+                               assertEquals(order, counter.getAndIncrement());
+                               
+                               return response;
+                       }
+               }
+               
+               HeaderResponseDecoratorCollection decorators = 
tester.getApplication().getHeaderResponseDecorators();
+               decorators.add(new AssertOrder(2));
+               decorators.add(new AssertOrder(1));
+               decorators.addPreResourceAggregationDecorator(new 
AssertOrder(3));
+               decorators.add(new AssertOrder(0));
+               decorators.addPostProcessingDecorator(new AssertOrder(4));
+               
+               tester.getApplication().decorateHeaderResponse(new 
HeaderResponse()
+               {
+                       
+                       @Override
+                       protected Response getRealResponse()
+                       {
+                               return null;
+                       }
+               });
+       }
+
+       /**
         * A page for the test
         */
        public static class HeaderContributorTestPage extends WebPage

Reply via email to