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: None
    • 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

        Hide
        elygre added a comment -

        (Terribly sorry about the way the code turned out; I'm used to a non-formatting jira-instance...)

        Show
        elygre added a comment - (Terribly sorry about the way the code turned out; I'm used to a non-formatting jira-instance...)
        Hide
        Pavel Bucek added a comment -

        no problem, I've fixed it

        Show
        Pavel Bucek added a comment - no problem, I've fixed it
        Hide
        Jakub Podlesak added a comment -

        Moved to 2.0 backlog

        Show
        Jakub Podlesak added a comment - Moved to 2.0 backlog
        Hide
        Marek Potociar added a comment -

        Jersey 1.x branch is not under active development anymore. Only security issues and issues reported by the customers of commercially supported products that ship with Jersey are fixed on this code base right now.
        Please, move your code to Jersey 2.x and if you still see the issue there, feel free to file a bug against Jersey 2.x.

        Show
        Marek Potociar added a comment - Jersey 1.x branch is not under active development anymore. Only security issues and issues reported by the customers of commercially supported products that ship with Jersey are fixed on this code base right now. Please, move your code to Jersey 2.x and if you still see the issue there, feel free to file a bug against Jersey 2.x.

          People

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

            Dates

            • Created:
              Updated:
              Resolved: