Can I exclude some concrete urls from <url-pattern> inside <filter-mapping>?

JavaServletsServlet Filters

Java Problem Overview


I want some concrete filter to be applied for all urls except for one concrete (i.e. for /* except for /specialpath).

Is there a possibility to do that?


sample code:

<filter>
    <filter-name>SomeFilter</filter-name>
    <filter-class>org.somproject.AFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>SomeFilter</filter-name>
    <url-pattern>/*</url-pattern>   <!-- the question is: how to modify this line?  -->
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
</filter-mapping>

Java Solutions


Solution 1 - Java

The standard Servlet API doesn't support this facility. You may want either to use a rewrite-URL filter for this like Tuckey's one (which is much similar Apache HTTPD's mod_rewrite), or to add a check in the doFilter() method of the Filter listening on /*.

String path = ((HttpServletRequest) request).getRequestURI();
if (path.startsWith("/specialpath/")) {
    chain.doFilter(request, response); // Just continue chain.
} else {
    // Do your business stuff here for all paths other than /specialpath.
}

You can if necessary specify the paths-to-be-ignored as an init-param of the filter so that you can control it in the web.xml anyway. You can get it in the filter as follows:

private String pathToBeIgnored;

public void init(FilterConfig config) {
    pathToBeIgnored = config.getInitParameter("pathToBeIgnored");
}

If the filter is part of 3rd party API and thus you can't modify it, then map it on a more specific url-pattern, e.g. /otherfilterpath/* and create a new filter on /* which forwards to the path matching the 3rd party filter.

String path = ((HttpServletRequest) request).getRequestURI();
if (path.startsWith("/specialpath/")) {
    chain.doFilter(request, response); // Just continue chain.
} else {
    request.getRequestDispatcher("/otherfilterpath" + path).forward(request, response);
}

To avoid that this filter will call itself in an infinite loop you need to let it listen (dispatch) on REQUEST only and the 3rd party filter on FORWARD only.

See also:

Solution 2 - Java

I used an approach described by Eric Daugherty: I created a special servlet that always answers with 403 code and put its mapping before the general one.

Mapping fragment:

  <servlet>
    <servlet-name>generalServlet</servlet-name>
    <servlet-class>project.servlet.GeneralServlet</servlet-class>
  </servlet>
 <servlet>
    <servlet-name>specialServlet</servlet-name>
    <servlet-class>project.servlet.SpecialServlet</servlet-class>
 </servlet>
 <servlet-mapping>
    <servlet-name>specialServlet</servlet-name>
    <url-pattern>/resources/restricted/*</url-pattern>
 </servlet-mapping>
 <servlet-mapping>
    <servlet-name>generalServlet</servlet-name>
    <url-pattern>/resources/*</url-pattern>
 </servlet-mapping>

And the servlet class:

public class SpecialServlet extends HttpServlet {
    public SpecialServlet() {
        super();
    }
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
     	response.sendError(HttpServletResponse.SC_FORBIDDEN);
    }
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
		response.sendError(HttpServletResponse.SC_FORBIDDEN);
    }
}

Solution 3 - Java

This approach works when you want to prevent a certain filter and all the following ones. It should work well if you eg. want to serve some content as static resources within your servlet container instead of letting your application logic (through a filter like GuiceFilter):

Map the folder with your static resource files to the default servlet. Create a servlet filter and put it before the GuiceFilter in your web.xml. In your created filter, you can separate between forwarding some requests to the GuiceFilter and others directly to the dispatcher. Example follows...

web.xml

<servlet-mapping>
    <servlet-name>default</servlet-name>
    <url-pattern>/static/*</url-pattern>
</servlet-mapping>

<filter>
    <filter-name>StaticResourceFilter</filter-name>
    <filter-class>com.project.filter.StaticResourceFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>StaticResourceFilter</filter-name>
    <url-pattern>/static/*</url-pattern>
</filter-mapping>

<filter>
    <filter-name>guiceFilter</filter-name>
    <filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>guiceFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

StaticResourceFilter.class

public class StaticResourceFilter implements Filter {

    private final static Logger LOGGER = LoggerFactory.getLogger(StaticResourceFilter.class);

    private static final String RESOURCE_PATH = "/static/";
    @Override
    public void init(final FilterConfig filterConfig) throws ServletException {
        LOGGER.info("StaticResourceFilter initialized");
    }

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

        String path = ((HttpServletRequest) request).getServletPath();
        if (path.toLowerCase().startsWith(RESOURCE_PATH)) {
            request.getRequestDispatcher(path).forward(request, response);
        } else {
            chain.doFilter(request, response);
        }
    }

    @Override
    public void destroy() {
        LOGGER.info("StaticResourceFilter destroyed");
    }
}

Unfortunately if you just want to skip a single step in the filter chain while keeping those that follows, this will not work.

Solution 4 - Java

I don't think you can, the only other configuration alternative is to enumerate the paths that you want to be filtered, so instead of /* you could add some for /this/* and /that/* etc, but that won't lead to a sufficient solution when you have alot of those paths.

What you can do is add a parameter to the filter providing an expression (like a regular expression) which is used to skip the filter functionality for the paths matched. The servlet container will still call your filter for those url's but you will have better control over the configuration.

Edit

Now that you mention you have no control over the filter, what you could do is either inherit from that filter calling super methods in its methods except when the url path you want to skip is present and follow the filter chain like @BalusC proposed, or build a filter which instantiates your filter and delegates under the same circumstances. In both cases the filter parameters would include both the expression parameter you add and those of the filter you inherit from or delegate to.

The advantage of building a delegating filter (a wrapper) is that you can add the filter class of the wrapped filter as parameter and reuse it in other situations like this one.

Solution 5 - Java

I also Had to filter based on the URL pattern(/{servicename}/api/stats/)in java code .

if (path.startsWith("/{servicename}/api/statistics/")) {
validatingAuthToken(((HttpServletRequest) request).getHeader("auth_token"));
filterChain.doFilter(request, response);			
}

But its bizarre, that servlet doesn't support url pattern other than (/*), This should be a very common case for servlet API's !

Solution 6 - Java

I have encounterd the same issue, but I find a anwser showing below.

web.xml

 <!-- set this param value for the filter-->
    <init-param>
			<param-name>freePages</param-name>
			<param-value>
			MainFrame.jsp;
			</param-value>
	</init-param>

filter.java

strFreePages = config.getInitParameter("freePages"); //get the exclue pattern from config file
isFreePage(strRequestPage)  //decide the exclude path

this way you don't have to harass the concrete Filter class.

Solution 7 - Java

If for any reason you cannot change the original filter mapping ("/*" in my case) and you are dispatching to an unchangeable third-party filter, you can find useful the following:

  • Intercept the path to be bypassed
  • Skip to and execute the last ring of the filter chain (the servlet itself)
  • The skipping is done via reflection, inspecting the container instances in debug mode

The following works in Weblogic 12.1.3:

> import org.apache.commons.lang3.reflect.FieldUtils; > import javax.servlet.Filter;

> [...]

> @Override > public void doFilter(ServletRequest request, ServletRespons response, FilterChain chain) throws IOException, ServletException { > String path = ((HttpServletRequest) request).getRequestURI(); > > if(!bypassSWA(path)){ > swpFilterHandler.doFilter(request, response, chain);

> } else { > try { > ((Filter) (FieldUtils.readField( > (FieldUtils.readField( > (FieldUtils.readField(chain, "filters", true)), "last", true)), "item", true))) > .doFilter(request, response, chain); > } catch (IllegalAccessException e) { > e.printStackTrace(); > } > } > }

Solution 8 - Java

I was able to handle this in Spring 2 as following

 private boolean isInPath(ServletRequest request) {
   String PATH_TO_VALIDATE = "/path/";
   String path = ((HttpServletRequest) request).getRequestURI();
   return path != null && path.toLowerCase().contains(PATH_TO_VALIDATE);
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionRomanView Question on Stackoverflow
Solution 1 - JavaBalusCView Answer on Stackoverflow
Solution 2 - JavamrzasaView Answer on Stackoverflow
Solution 3 - JavakvitsoView Answer on Stackoverflow
Solution 4 - JavarspView Answer on Stackoverflow
Solution 5 - JavaSindhuView Answer on Stackoverflow
Solution 6 - JavanelsonView Answer on Stackoverflow
Solution 7 - JavarobermannView Answer on Stackoverflow
Solution 8 - Javauser2739602View Answer on Stackoverflow