Uploaded image for project: 'Shindig'
  1. Shindig
  2. SHINDIG-1957

JavaScript is not being cached in browser via ETag support when using WAS Liberty Profile

    XMLWordPrintableJSON

Details

    • Bug
    • Status: Patch Available
    • Major
    • Resolution: Unresolved
    • 2.5.1
    • None
    • Java
    • None

    Description

      --------------------------------------------------
      Problem
      --------------------------------------------------

      JavaScript served by the Shindig code loader is not being cached by the browser via provided ETag support when using the WAS Liberty Profile.
      Note: Everything works as expected when using Tomcat.

      --------------------------------------------------
      Steps To Reproduce
      --------------------------------------------------

      (1) Run Shindig server using WAS Liberty Profile
      (2) Open browser and track network traffic (via Firebug Net tab, etc.)
      (3) Go to common container sample page
      => e.g. /containers/commoncontainer/index.html
      => Initial request to fetch Shindig JavaScript loads successfully

      --------------------------------------------------
      Cause #1
      --------------------------------------------------

      URL pattern specified by ETag servlet filter is invalid and not being applied at all to incoming requests when using WAS Liberty Profile.

      e.g.
      <filter-mapping>
      <filter-name>etagFilter</filter-name>
      <url-pattern>*</url-pattern>
      </filter-mapping>

      According to Java Servlet Specification - Version 3.0:

      12.2 Specification of Mappings
      In the Web application deployment descriptor, the following syntax is used to define mappings:

      • A string beginning with a ‘/’ character and ending with a ‘/*’ suffix is used for path mapping.
      • A string beginning with a ‘*.’ prefix is used as an extension mapping.
      • The empty string ("") is a special URL pattern that exactly maps to the application's context root, i.e., requests of the form http://host:port/<contextroot>/.
        In this case the path info is ’/’ and the servlet path and context path is empty string (““).
      • A string containing only the ’/’ character indicates the "default" servlet of the
        application. In this case the servlet path is the request URI minus the context path
        and the path info is null.
      • All other strings are used for exact matches only

      Also, see: http://stackoverflow.com/questions/9443975/servlet-mapping-in-web-xml-vs-any-pattern

      Note: Tomcat tolerates the "*" pattern.

      --------------------------------------------------
      Solution #1
      --------------------------------------------------

      <filter-mapping>
      <filter-name>etagFilter</filter-name>
      <url-pattern>/*</url-pattern>
      </filter-mapping>

      --------------------------------------------------
      Cause #2
      --------------------------------------------------

      After fixing the path issue, the ETag servlet filter was then applied to each incoming request as expected.
      However, the filter started throwing exceptions into the Java Console / server log for every incoming request.

      e.g.

      SRVE8094W: WARNING: Cannot set header. Response already committed.

      Exception = com.ibm.wsspi.http.channel.exception.WriteBeyondContentLengthException
      Source = com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter
      probeid = 149
      Stack Dump = com.ibm.wsspi.http.channel.exception.WriteBeyondContentLengthException
      at com.ibm.wsspi.http.HttpOutputStream.writeToBuffers(HttpOutputStream.java:251)
      at com.ibm.wsspi.http.HttpOutputStream.write(HttpOutputStream.java:575)
      at com.ibm.ws.webcontainer.osgi.response.WCOutputStream.write(WCOutputStream.java:234)
      at org.apache.shindig.gadgets.servlet.ETaggingHttpResponse.writeToOutput(ETaggingHttpResponse.java:170)
      at org.apache.shindig.gadgets.servlet.ETagFilter.doFilter(ETagFilter.java:60)
      at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:194)
      at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:85)
      at org.apache.shindig.auth.AuthenticationServletFilter.callChain(AuthenticationServletFilter.java:186)
      at org.apache.shindig.auth.AuthenticationServletFilter.doFilter(AuthenticationServletFilter.java:97)
      at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:194)
      at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:85)
      at org.apache.shindig.common.servlet.HostFilter.doFilter(HostFilter.java:38)
      at com.ibm.ws.webcontainer.filter.FilterInstanceWrapper.doFilter(FilterInstanceWrapper.java:194)
      at com.ibm.ws.webcontainer.filter.WebAppFilterChain.doFilter(WebAppFilterChain.java:85)
      at com.ibm.ws.webcontainer.filter.WebAppFilterManager.doFilter(WebAppFilterManager.java:949)
      at com.ibm.ws.webcontainer.filter.WebAppFilterManager.invokeFilters(WebAppFilterManager.java:1029)
      at com.ibm.ws.webcontainer.webapp.WebApp.handleRequest(WebApp.java:4499)
      at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost$2.handleRequest(DynamicVirtualHost.java:282)
      at com.ibm.ws.webcontainer.WebContainer.handleRequest(WebContainer.java:954)
      at com.ibm.ws.webcontainer.osgi.DynamicVirtualHost$2.run(DynamicVirtualHost.java:252)
      at com.ibm.ws.http.dispatcher.internal.channel.HttpDispatcherLink$TaskWrapper.run(HttpDispatcherLink.java:584)
      at com.ibm.ws.threading.internal.Worker.executeWork(Worker.java:439)
      at com.ibm.ws.threading.internal.Worker.run(Worker.java:421)
      at java.lang.Thread.run(Thread.java:738)

      When using WAS Liberty Profile the following method is called repeatedly (but not when using Tomcat):
      org.apache.shindig.gadgets.servlet.ETaggingHttpResponse#flushBuffer
      This turns off batching mode
      e.g.
      batching = false;

      The subsequent method call causes the exception when batching mode is off:
      org.apache.shindig.gadgets.servlet.ETaggingHttpResponse#writeToOutput

      if (batching) {
      ...
      } else if (bytes.length != 0) {
      originalStream.write(bytes);
      stream.getBuffer().clear();
      }

      --------------------------------------------------
      Solution #2
      --------------------------------------------------

      Add a check to see whether the response has been committed already before trying to write to it.

      if (batching) {
      ...
      } else if ((bytes.length != 0) && !isCommitted()) {
      originalStream.write(bytes);
      stream.getBuffer().clear();
      }

      --------------------------------------------------
      Patch
      --------------------------------------------------

      Attached.

      Attachments

        1. etag-filter_v1.patch
          1 kB
          Mike Pawlowski

        Activity

          People

            Unassigned Unassigned
            mpawlow Mike Pawlowski
            Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

              Created:
              Updated: