Question

Simple instance of Embedded Tomcat with a Servlet and a Filter:

            Tomcat tomcat = new Tomcat();
            Context rootCtx = tomcat.addContext("", base.getAbsolutePath());
            FilterDef filterDefinition = new FilterDef();
            filterDefinition.setFilterName(URLFilter.class.getSimpleName());
            filterDefinition.setFilterClass(URLFilter.class.getName());
            rootCtx.addFilterDef(filterDefinition);

            FilterMap filter1mapping = new FilterMap();
            filter1mapping.setFilterName(URLFilter.class.getSimpleName());
            filter1mapping.addURLPattern("/*");
            rootCtx.addFilterMap(filter1mapping);

            Tomcat.addServlet(rootCtx, "Servlet1", new Servlet1());
            rootCtx.addServletMapping("/Servlet1", "Servlet1");

URL Filter Implementation:

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException {
    Boolean filtered = false;
    System.out.println("request intercepted");
    if (request.getAttribute("filtered") != null) {
        filtered = true;
        request.setAttribute("filtered", filtered);
        HttpServletResponse httpResponse = (HttpServletResponse) response;
        httpResponse.sendRedirect("/Servlet1");
        return;
    } else {
        filterChain.doFilter(request, response);
    }
}

For some reason this ends up in an infinite loop and never arrives at Servlet1. What is the correct way of implementing a URL Filter so that I can double check the parameters around the request before delivering the response?

Was it helpful?

Solution 2

As this solved your problem, posting it as an answer.

Firstly, you need to ensure that you're either passing the request along the application filter chain, or you're redirecting it:

@Override
public void doFilter(ServletRequest request, ServletResponse response,
    FilterChain filterChain) throws IOException, ServletException {

    Boolean filtered = false;
    System.out.println("request intercepted");
    if (!filtered) {
        filtered = true;
        ((HttpServletResponse) response).sendRedirect("/Servlet1");
        return;
    }

    filterChain.doFilter(request, response);
}

Then you need to ensure that the filter knows when an incoming request has already been redirected, so that it doesn't redirect it again:

@Override
public void doFilter(ServletRequest request, ServletResponse response,
    FilterChain filterChain) throws IOException, ServletException {

    Boolean filtered = false;
    System.out.println("request intercepted");
    if (request.getAttribute("filtered") != null) {
        filtered = (Boolean) request.getAttribute("filtered");
    }

    if (!filtered) {
        request.setAttribute("filtered", Boolean.TRUE);
        ((HttpServletResponse) response).sendRedirect("/Servlet1");
        return;
    }

    filterChain.doFilter(request, response);
}

OTHER TIPS

Look at the JavaDocs for sendRedirect(). You're telling the client on each request to go back to /Servlet1, but then you're filtering it indefinitely. At some point you need to stop sending redirects in your filter!

To clarify some more. If you don't intend to actively filter a request, the only thing you need to do is call

filterChain.dofilter(request, response);

Don't send back a redirect unless you really mean to send an HTTP 302 (Temporary Redirect). The Servlet Filter Chain is an important part of the servlet process and although it may seem counterintuitive, you can make your filter appear to do nothing by calling the filterChain.doFilter command, which allows the request to proceed to other filters that are configured by your application server.

What's not clear to me is what filtering your filter is attempting to do. If you intend to filter by URL then you should look for matching URLs and then redirect only if there's a match.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top