0

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?

  • Looks like you're missing a call to `chain.doFilter(request, response)`. Does the behaviour change if you include it at the end of your `doFilter` method? – JonK Mar 27 '14 at 14:43
  • Apologies - I was hasty in my initial comment and wasn't specific enough. The call to `doFilter` only needs to happen if you're not sending a redirect. When you redirect you should just `return;` afterwards, `doFilter` is for when you're not redirecting. – JonK Mar 27 '14 at 14:58
  • If you're going to be doing a lot of redirects, look into [UrlRewriteFilter](http://tuckey.org/urlrewrite/). It was made for just this purpose. – David Ehrmann Mar 27 '14 at 15:21

2 Answers2

1

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.

Jason Nichols
  • 11,603
  • 5
  • 34
  • 53
  • Perhaps try looking at it from this angle: *How does your Filter know if it has already previously redirected a request?* At the moment it doesn't - it assumes that anything it receives hasn't been redirected yet and redirects it. – JonK Mar 27 '14 at 15:11
  • 2
    You could add an attribute to the request such as `request.setAttribute("redirected", "true");`, then have the Filter check that attribute to see if it has been redirected yet. If it hasn't, modify the attribute and then redirect it, otherwise don't redirect it and pass the request along the application filter chain. – JonK Mar 27 '14 at 15:16
  • This, but I think you need to do ```else if (request.getRequestURI.equals("/Servlet1")) { filterChain.dofilter(request, response); }``` – David Ehrmann Mar 27 '14 at 15:20
0

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);
}
JonK
  • 2,097
  • 2
  • 25
  • 36