Wicket
  1. Wicket
  2. WICKET-4995

Using CryptoMapper causes page to render twice

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: None
    • Fix Version/s: 6.7.0
    • Component/s: None
    • Labels:
      None

      Description

      Using Wicket 1.5.9 and CryptoMapper causes our Wicket pages to be rendered twice. I was investigating a problem where a DAO query was executed two times when navigating to a single page.

      In debug call stack I found out that first render is made at WebPageRenderer.respond(RequestCycle) line: 246
      and second at WebPageRenderer.respond(RequestCycle) line: 263

      Removing CryptoMapper from our app configuration fixes the problem.

      It is also possible we are doing something wrong so any help is appreciated.

        Issue Links

          Activity

          Hide
          Sven Meier added a comment -

          The culprit lies in WebPageRenderer#257:

          if (targetUrl.getSegments().equals(targetUrl2.getSegments()) == false)

          { // the amount of segments is different - generated relative URLs will not work, we // need to rerender the page. This shouldn't happen, but in theory it can - with // RequestHandlerEncoders that produce different URLs with different amount of // segments for stateless and stateful pages response = renderPage(targetUrl2, requestCycle); }

          With CryptoMapper the page id is included in the segments, the following urls:

          wicket/bookmarkable/org.apache.wicket.examples.compref.LinkPage
          wicket/bookmarkable/org.apache.wicket.examples.compref.LinkPage?0

          ... produce different encrypted segments:

          /L7ExSNbPC4sb6TPJDblCAopL53TWmZP5y7BQEaJSJABliOBEOWyBWvlruzSupJSCrybkqQ-xa2Ib_nrhWXToPw/L7E59/JDb97/SJA39
          /L7ExSNbPC4sb6TPJDblCAopL53TWmZP5y7BQEaJSJABliOBEOWyBWvlruzSupJSCrybkqQ-xa2J5M_AzHZAUgh-GKNtYnL4t/L7E59/TPJfd/YnLa6

          Show
          Sven Meier added a comment - The culprit lies in WebPageRenderer#257: if (targetUrl.getSegments().equals(targetUrl2.getSegments()) == false) { // the amount of segments is different - generated relative URLs will not work, we // need to rerender the page. This shouldn't happen, but in theory it can - with // RequestHandlerEncoders that produce different URLs with different amount of // segments for stateless and stateful pages response = renderPage(targetUrl2, requestCycle); } With CryptoMapper the page id is included in the segments, the following urls: wicket/bookmarkable/org.apache.wicket.examples.compref.LinkPage wicket/bookmarkable/org.apache.wicket.examples.compref.LinkPage?0 ... produce different encrypted segments: /L7ExSNbPC4sb6TPJDblCAopL53TWmZP5y7BQEaJSJABliOBEOWyBWvlruzSupJSCrybkqQ-xa2Ib_nrhWXToPw/L7E59/JDb97/SJA39 /L7ExSNbPC4sb6TPJDblCAopL53TWmZP5y7BQEaJSJABliOBEOWyBWvlruzSupJSCrybkqQ-xa2J5M_AzHZAUgh-GKNtYnL4t/L7E59/TPJfd/YnLa6
          Hide
          Sven Meier added a comment -

          Is there a reason why we render the page with the initial targetUrl first, just to initiate another render when targetUrl2 doesn't match after rendering?

          Why not create the page first and then render with the final url right away?

          diff --git a/wicket-core/src/main/java/org/apache/wicket/request/handler/render/WebPageRenderer.java b/wicket-core/src/main/java/org/apache/wicket/request/handler/render/WebPageRenderer.java
          index 8c94d1f..7208f50 100644
          — a/wicket-core/src/main/java/org/apache/wicket/request/handler/render/WebPageRenderer.java
          +++ b/wicket-core/src/main/java/org/apache/wicket/request/handler/render/WebPageRenderer.java
          @@ -242,25 +242,17 @@
          "matched. Details: " + details);
          }

          + // force creation of possible stateful page to get the final target url
          + getPage();
          +
          + Url targetUrl2 = requestCycle.mapUrlFor(getRenderPageRequestHandler());
          +
          // redirect to buffer

          • BufferedWebResponse response = renderPage(targetUrl, requestCycle);
            + BufferedWebResponse response = renderPage(targetUrl2, requestCycle);

          if (response == null)

          { return; - }

          -

          • // check if the url hasn't changed after page has been rendered
          • // (i.e. the stateless flag might have changed which could result in different page url)
          • Url targetUrl2 = requestCycle.mapUrlFor(getRenderPageRequestHandler());
            -
          • if (targetUrl.getSegments().equals(targetUrl2.getSegments()) == false)
          • { - // the amount of segments is different - generated relative URLs will not work, we - // need to rerender the page. This shouldn't happen, but in theory it can - with - // RequestHandlerEncoders that produce different URLs with different amount of - // segments for stateless and stateful pages - response = renderPage(targetUrl2, requestCycle); }

          if (currentUrl.equals(targetUrl2))

          This would solve the double-rendering for CryptoMapper, but I'm not sure if this has any negative side effects.

          Show
          Sven Meier added a comment - Is there a reason why we render the page with the initial targetUrl first, just to initiate another render when targetUrl2 doesn't match after rendering? Why not create the page first and then render with the final url right away? diff --git a/wicket-core/src/main/java/org/apache/wicket/request/handler/render/WebPageRenderer.java b/wicket-core/src/main/java/org/apache/wicket/request/handler/render/WebPageRenderer.java index 8c94d1f..7208f50 100644 — a/wicket-core/src/main/java/org/apache/wicket/request/handler/render/WebPageRenderer.java +++ b/wicket-core/src/main/java/org/apache/wicket/request/handler/render/WebPageRenderer.java @@ -242,25 +242,17 @@ "matched. Details: " + details); } + // force creation of possible stateful page to get the final target url + getPage(); + + Url targetUrl2 = requestCycle.mapUrlFor(getRenderPageRequestHandler()); + // redirect to buffer BufferedWebResponse response = renderPage(targetUrl, requestCycle); + BufferedWebResponse response = renderPage(targetUrl2, requestCycle); if (response == null) { return; - } - // check if the url hasn't changed after page has been rendered // (i.e. the stateless flag might have changed which could result in different page url) Url targetUrl2 = requestCycle.mapUrlFor(getRenderPageRequestHandler()); - if (targetUrl.getSegments().equals(targetUrl2.getSegments()) == false) { - // the amount of segments is different - generated relative URLs will not work, we - // need to rerender the page. This shouldn't happen, but in theory it can - with - // RequestHandlerEncoders that produce different URLs with different amount of - // segments for stateless and stateful pages - response = renderPage(targetUrl2, requestCycle); } if (currentUrl.equals(targetUrl2)) This would solve the double-rendering for CryptoMapper, but I'm not sure if this has any negative side effects.
          Hide
          Martin Grigorov added a comment - - edited

          @Sven: please commit your suggestion so we can test it before 6.7.0 is released.

          Show
          Martin Grigorov added a comment - - edited @Sven: please commit your suggestion so we can test it before 6.7.0 is released.
          Hide
          Martin Grigorov added a comment -

          The improvement is committed by Sven and so far there are no problems

          Show
          Martin Grigorov added a comment - The improvement is committed by Sven and so far there are no problems
          Hide
          Sven Meier added a comment -

          WICKET-5309 showed that the url of a page can indeed change after being rendered, when stateful components are added to an otherwise stateless page during rendering (e.g. by repeaters).

          Since CryptoMapper changes a url's segments for stateful pages, the page will be re-rendered. To prevent this, call #setStatelessHint(false) on your page.

          Show
          Sven Meier added a comment - WICKET-5309 showed that the url of a page can indeed change after being rendered, when stateful components are added to an otherwise stateless page during rendering (e.g. by repeaters). Since CryptoMapper changes a url's segments for stateful pages, the page will be re-rendered. To prevent this, call #setStatelessHint(false) on your page.

            People

            • Assignee:
              Sven Meier
              Reporter:
              Jukka Siivonen
            • Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development