Wicket
  1. Wicket
  2. WICKET-4550

jsessionid is not added to resources if cookies are disabled by the server

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Fixed
    • Affects Version/s: 1.5.5
    • Fix Version/s: 1.5.7, 6.0.0-beta3
    • Component/s: wicket
    • Labels:
      None

      Description

      When I configure the container (either Jetty or Tomcat) to not support cookies, I expect the jsessionid to be added to all resource links in the page. However, with Wicket 1.5.5 this isn't the case, i.e. all URLs are lacking the jsessionid, both in development and deployment mode.

      Example IS:
      <script type="text/javascript" src="wicket/resource/org.apache.wicket.markup.html.WicketEventReference/wicket-event-ver-1331911540000.js"></script>

      Example SHOULD:
      <script type="text/javascript" src="wicket/resource/org.apache.wicket.markup.html.WicketEventReference/wicket-event-ver-1331911540000.js;jsessionid=$

      {something}

      "></script>

      This creates a new session for each and every resource in the page, which is an undesirable behavior. I have found a few issues regarding this topic, e.g. WICKET-4334 and WICKET-4312, but none of them could give me a clue about why it doesn't work the way I expect it. In Wicket 1.4.x the jsessionid was added to all resource links, so everything worked fine and the current session was reused.

      I created a quickstart do demonstrate the behavior - please see the attached file. The file jetty-web.xml tells Jetty to not support cookies, so mvn jetty:run can be run without any further configuration.

      By the way, I found a suggestion to use a custom IResourceCachingStrategy to append the jsessionid (or whatever) to URLs of resources in the archive of the mailinglist. Unfortunately, this doesn't work because the URL is encoded afterwards and the ; is turned into %3B.

      1. jsessionid-quickstart.tar.gz
        19 kB
        Michael Bruns
      2. WICKET-4550.patch
        8 kB
        Martin Grigorov

        Issue Links

          Activity

          Hide
          Michael Bruns added a comment -

          Quickstart to show the behavior described above. Please execute mvn verify jetty:run, open the application in the browser and look at the <script> tages in the source of the page.

          Show
          Michael Bruns added a comment - Quickstart to show the behavior described above. Please execute mvn verify jetty:run, open the application in the browser and look at the <script> tages in the source of the page.
          Hide
          Martin Grigorov added a comment -

          The reason is explained in WICKET-4334 - static resources do not need sessionid.
          Only temporary Wicket sessions are created which are discarded at the end of the request. No http sessions are created.

          Show
          Martin Grigorov added a comment - The reason is explained in WICKET-4334 - static resources do not need sessionid. Only temporary Wicket sessions are created which are discarded at the end of the request. No http sessions are created.
          Hide
          Michael Bruns added a comment -

          I still can't exactly understand the reason for this.

          In our scenario, we have two Tomcat instances running on the same machine. One is considered as active, i.e. new sessions are created on this instance, the other is considered as passive, i.e. it only serves sessions which are already open until they expire. When we deploy a new version of our application we deploy it to the passive instance and then switch the configuration of active and passive.

          Let's consider the following scenario:

          • Instance A is active, B is passive.
          • The application contains a static resource something.js, which has the hash ABC appended as its version.
          • something.js is changed in a new version of the application, so its new hash is now 123.
          • Then, this new version is deployed to B and B is then made the active instance.

          The page served by A now contains a resource link to something-ver-ABC.js. As the jsessionid is lacking, this request will be redirected to the active Tomcat instance, which is B. But B doesn't know the version ABC of something.js, it only knows something-ver-123.js. The result is a 404.

          Or am I missing something here?

          Show
          Michael Bruns added a comment - I still can't exactly understand the reason for this. In our scenario, we have two Tomcat instances running on the same machine. One is considered as active, i.e. new sessions are created on this instance, the other is considered as passive, i.e. it only serves sessions which are already open until they expire. When we deploy a new version of our application we deploy it to the passive instance and then switch the configuration of active and passive. Let's consider the following scenario: Instance A is active, B is passive. The application contains a static resource something.js, which has the hash ABC appended as its version. something.js is changed in a new version of the application, so its new hash is now 123. Then, this new version is deployed to B and B is then made the active instance. The page served by A now contains a resource link to something-ver-ABC.js. As the jsessionid is lacking, this request will be redirected to the active Tomcat instance, which is B. But B doesn't know the version ABC of something.js, it only knows something-ver-123.js. The result is a 404. Or am I missing something here?
          Hide
          Michael Bruns added a comment -

          As (bad) luck would have it we just tripped over another error caused by this bug

          Our Tomcats are clustered, i.e. there are three of them behind a load balancer. The sessions are sticky, so that a user stays on the same Tomcat throughout his session. Now we ran into this constellation:

          • A new version of our application has been freshly deployed to the three Tomcats T1, T2 and T3.
          • A page mounted at /somePage (or a component used in this page) mounts an image to static URL /img/something.png on instantiation, i.e. when the page is accessed for the first time.
          • A user logs into a new session on Tomcat T1 and accesses the page /somePage.
          • The resource link to /img/something.png served by T1 on page /somePage doesn't contain a jsessionid.

          This will lead to the fact that the new session for /img/something.png, be it temporary or not, will be created on either of the three Tomcats. However, /somePage has only been accessed on T1, which means that both T2 and T3 have not yet mounted the image on the given path and will thus answer with a 404. Only when /somePage has been accessed on all three Tomcats the image will always be delivered. Before that, there is always a chance of 2/3 or 1/3 that you'll get a 404.

          Show
          Michael Bruns added a comment - As (bad) luck would have it we just tripped over another error caused by this bug Our Tomcats are clustered, i.e. there are three of them behind a load balancer. The sessions are sticky, so that a user stays on the same Tomcat throughout his session. Now we ran into this constellation: A new version of our application has been freshly deployed to the three Tomcats T1, T2 and T3. A page mounted at /somePage (or a component used in this page) mounts an image to static URL /img/something.png on instantiation, i.e. when the page is accessed for the first time. A user logs into a new session on Tomcat T1 and accesses the page /somePage. The resource link to /img/something.png served by T1 on page /somePage doesn't contain a jsessionid. This will lead to the fact that the new session for /img/something.png, be it temporary or not, will be created on either of the three Tomcats. However, /somePage has only been accessed on T1, which means that both T2 and T3 have not yet mounted the image on the given path and will thus answer with a 404. Only when /somePage has been accessed on all three Tomcats the image will always be delivered. Before that, there is always a chance of 2/3 or 1/3 that you'll get a 404.
          Hide
          Chris Colman added a comment -

          After 4334 was fixed we confirmed that Wicket was serving static resources without creating a new session - and this is perfect. Static resources should never need a session in order to serve them (definition of static - unchanging regardless of session).

          If you are seeing a session being created now then maybe your code is creating one somehow or something has changed in Wicket since the release we tested that now does create a session even though it is not needed.

          From memory the problem in the Wicket code was a call to "get session" style of method that really was only checking if there was a session, it didn't really need a session, but it in fact created one in the process if there wasn't one.

          Check that you don't have any other filters in the chain in web.xml that might be creating a session. We use exPOJO for Dependency Injection and we need to tell it to ignore requests for wicket resources that have the path wicket/resource like this:

          <filter>
          <filter-name>exPOJO Filter</filter-name>
          <filter-class>com.sas.framework.expojo.servlet.ExpojoServletFilter</filter-class>
          <!-- exPOJO uses 'startsWith' method to match, not any regular expression matching so
          don't use blah/* here -->
          <init-param>
          <param-name>ignorePaths</param-name>
          <param-value>wicket/resource/,robots.txt,index.html,static/,css/,images/,swf/,fckeditor</param-value>
          </init-param>
          </filter>

          Show
          Chris Colman added a comment - After 4334 was fixed we confirmed that Wicket was serving static resources without creating a new session - and this is perfect. Static resources should never need a session in order to serve them (definition of static - unchanging regardless of session). If you are seeing a session being created now then maybe your code is creating one somehow or something has changed in Wicket since the release we tested that now does create a session even though it is not needed. From memory the problem in the Wicket code was a call to "get session" style of method that really was only checking if there was a session, it didn't really need a session, but it in fact created one in the process if there wasn't one. Check that you don't have any other filters in the chain in web.xml that might be creating a session. We use exPOJO for Dependency Injection and we need to tell it to ignore requests for wicket resources that have the path wicket/resource like this: <filter> <filter-name>exPOJO Filter</filter-name> <filter-class>com.sas.framework.expojo.servlet.ExpojoServletFilter</filter-class> <!-- exPOJO uses 'startsWith' method to match, not any regular expression matching so don't use blah/* here --> <init-param> <param-name>ignorePaths</param-name> <param-value>wicket/resource/,robots.txt,index.html,static/,css/,images/,swf/,fckeditor</param-value> </init-param> </filter>
          Hide
          Martin Grigorov added a comment -

          The problem is not that a Wicket Session is created but that there is no jsessionid in the url for static resources and thus the routing doesn't work.
          The problem can be solved by decorating the url of the resources. This way you can transform some/resource.ext to some/resource-server1.ext or some/resource.ext;server=1 and use this as a condition.

          I'd like to not revert 4334 because as its description says: the first request for a page comes with jsessionid in all urls for static resources and then the web container realizes that cookies are supported and removes the jsessionid for the next requests and this leads to double download of all static resources.

          Show
          Martin Grigorov added a comment - The problem is not that a Wicket Session is created but that there is no jsessionid in the url for static resources and thus the routing doesn't work. The problem can be solved by decorating the url of the resources. This way you can transform some/resource.ext to some/resource-server1.ext or some/resource.ext;server=1 and use this as a condition. I'd like to not revert 4334 because as its description says: the first request for a page comes with jsessionid in all urls for static resources and then the web container realizes that cookies are supported and removes the jsessionid for the next requests and this leads to double download of all static resources.
          Hide
          Martin Grigorov added a comment -

          Using custom IResourceCachingStrategy is not an option because adding ';jsessionid=...' is later url encoded and the ';' is being lost.
          Using custom request parameter is an option only if you have control on the load balancers. Most of the time the developers have no such control.

          I tried the brutal way: make a quickstart that enables the encoding of the jsessionid in the url even for static resources by either extending classes or copy/paste them but I faced several problems:
          1) org.apache.wicket.request.cycle.RequestCycle#renderUrl(Url, IRequestHandler) decides whether to pass the url to HttpServletResponse#encodeURL()
          By providing my own RequestCycle impl that overrides public CharSequence urlFor(IRequestHandler handler) I partially solved the problem, but
          #urlFor(Class<C> pageClass, PageParameters parameters) and #urlFor(ResourceReference reference, PageParameters params) are final and it is not possible to override them.

          2) HeaderResponse#internalRenderXyzResourceReference() also strips the jsessionid from the url.
          The only way I see here is to copy/paste HeaderResponse and setup it by using IHeaderResponseDecorator (this works)

          After all these hacks I think it will be much easier to introduce a new setting in IResourceSettings with which the application will be able to enable encoding of jsessionid even for the static resources. By default its value will be 'do-not-encode-for-static-resources'.

          A patch will come soon.

          Show
          Martin Grigorov added a comment - Using custom IResourceCachingStrategy is not an option because adding ';jsessionid=...' is later url encoded and the ';' is being lost. Using custom request parameter is an option only if you have control on the load balancers. Most of the time the developers have no such control. I tried the brutal way: make a quickstart that enables the encoding of the jsessionid in the url even for static resources by either extending classes or copy/paste them but I faced several problems: 1) org.apache.wicket.request.cycle.RequestCycle#renderUrl(Url, IRequestHandler) decides whether to pass the url to HttpServletResponse#encodeURL() By providing my own RequestCycle impl that overrides public CharSequence urlFor(IRequestHandler handler) I partially solved the problem, but #urlFor(Class<C> pageClass, PageParameters parameters) and #urlFor(ResourceReference reference, PageParameters params) are final and it is not possible to override them. 2) HeaderResponse#internalRenderXyzResourceReference() also strips the jsessionid from the url. The only way I see here is to copy/paste HeaderResponse and setup it by using IHeaderResponseDecorator (this works) After all these hacks I think it will be much easier to introduce a new setting in IResourceSettings with which the application will be able to enable encoding of jsessionid even for the static resources. By default its value will be 'do-not-encode-for-static-resources'. A patch will come soon.
          Hide
          Michael Bruns added a comment -

          That's perfect, thank you

          Show
          Michael Bruns added a comment - That's perfect, thank you

            People

            • Assignee:
              Martin Grigorov
              Reporter:
              Michael Bruns
            • Votes:
              1 Vote for this issue
              Watchers:
              3 Start watching this issue

              Dates

              • Created:
                Updated:
                Resolved:

                Development