jersey
  1. jersey
  2. JERSEY-834

Filter fails when there is a servlet mapped to a prefix of the jersey filter (jersey filter="/rest"; spring servlet="/")

    Details

    • Type: Bug Bug
    • Status: Resolved
    • Priority: Major Major
    • Resolution: Complete
    • Affects Version/s: 1.10
    • Fix Version/s: backlog
    • Component/s: containers
    • Labels:
      None

      Description

      The Jersey filter fails when there is a servlet mapped to a prefix of the jersey filter, for example as follows:

      • The jersey filter is mapped to "/private/rest/*"
      • The jersey FilterContextPath is specified to "/private/rest"
      • A third party servlet (such as spring mvc) is mapped to "/"

      When I submit a request for http://localhost/private/rest/users (which is mapped), the following happens:

      • The servlet container will match the request to the spring servlet ("/")
      • The httpServletRequest.getServletPath() will yield "", which is reasonable
      • Before being passed to the servlet, it is passed to the jersey filter (which is the point, right?)
      • ServletContainer#doFilter(line 862 in 1.10) has code that dislikes this, and throws an exception:
          if (!servletPath.startsWith(filterContextPath)) {
              throw new ContainerException("The servlet path, \"" + servletPath +
              "\", does not start with the filter context path, \"" + filterContextPath + "\"");
          }
      

      I have to admin that I don't quite understand the reason for that entire set of tests, but I'm fairly sure that they don't work as they were hoped to work

              if (filterContextPath != null) {
                  if (!servletPath.startsWith(filterContextPath)) {
                      throw new ContainerException("The servlet path, \"" + servletPath +
                              "\", does not start with the filter context path, \"" + filterContextPath + "\"");
                  } else if (servletPath.length() == filterContextPath.length()) {
                      // Path does not end in a slash, may need to redirect
                      if (webComponent.getResourceConfig().getFeature(ResourceConfig.FEATURE_REDIRECT)) {
                          URI l = UriBuilder.fromUri(request.getRequestURL().toString()).
                                  path("/").
                                  replaceQuery(queryString).build();
      
                          response.setStatus(307);
                          response.setHeader("Location", l.toASCIIString());
                          return;
                      } else {
                          requestURI += "/";
                      }
                  }
              }
      

      If I were to venture a guess, the code would have to examine not "httpServletRequest.getServletPath()", but "httpServletRequest.getServletPath() + httpServletRequest.getPathInfo()", e.g. in ServletContainer.java, line 840 (single line change):

          public void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
              if (request.getAttribute("javax.servlet.include.request_uri") != null) {
                  final String includeRequestURI = (String)request.getAttribute("javax.servlet.include.request_uri");
      
                  if (!includeRequestURI.equals(request.getRequestURI())) {
                      doFilter(request, response, chain,
                              includeRequestURI,
                              (String)request.getAttribute("javax.servlet.include.servlet_path"),
                              (String)request.getAttribute("javax.servlet.include.query_string"));
                      return;
                  }
              }
      
              doFilter(request, response, chain,
                      request.getRequestURI(),
                      // request.getServletPath(),                             // OLD CODE, NOT WORKING
                      request.getServletPath() + request.getPathInfo(),        // NEW CODE, SEEMS TO WORK
                      request.getQueryString());
          }
      

      Here is the filter and servlet definitions, just in case.

          <filter>
              <filter-name>Jersey Spring Web Application</filter-name>
              <filter-class>com.sun.jersey.spi.spring.container.servlet.SpringServlet</filter-class>
              <init-param>
                  <param-name>com.sun.jersey.config.feature.FilterForwardOn404</param-name>
                  <param-value>true</param-value>
              </init-param>
              <init-param>
                  <param-name>com.sun.jersey.config.feature.FilterContextPath</param-name>
                  <param-value>/private/rest</param-value>
              </init-param>
          </filter>
          <filter-mapping>
              <filter-name>Jersey Spring Web Application</filter-name>
              <url-pattern>/private/rest/*</url-pattern>
          </filter-mapping>
      
          <servlet>
              <servlet-name>springapp</servlet-name>
              <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
          </servlet>
          <servlet-mapping>
              <servlet-name>springapp</servlet-name>
              <url-pattern>/*</url-pattern>
          </servlet-mapping>
      

        Activity

        No work has yet been logged on this issue.

          People

          • Assignee:
            Unassigned
            Reporter:
            elygre
          • Votes:
            0 Vote for this issue
            Watchers:
            1 Start watching this issue

            Dates

            • Created:
              Updated:
              Resolved: