[JERSEY-834] Filter fails when there is a servlet mapped to a prefix of the jersey filter (jersey filter="/rest"; spring servlet="/") Created: 14/Nov/11  Updated: 04/Nov/13

Status: Open
Project: jersey
Component/s: containers
Affects Version/s: 1.10
Fix Version/s: backlog

Type: Bug Priority: Major
Reporter: elygre Assignee: Unassigned
Resolution: Unresolved Votes: 0
Labels: None
Remaining Estimate: Not Specified
Time Spent: Not Specified
Original Estimate: Not Specified

Tags: filter, filterchain, filters, mapping

 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>


 Comments   
Comment by elygre [ 14/Nov/11 ]

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

Comment by Pavel Bucek [ 15/Nov/11 ]

no problem, I've fixed it

Comment by Jakub Podlesak [ 07/Feb/13 ]

Moved to 2.0 backlog

Generated at Sat Aug 29 11:08:09 UTC 2015 using JIRA 6.2.3#6260-sha1:63ef1d6dac3f4f4d7db4c1effd405ba38ccdc558.