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>
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:
How to prevent static resources from being handled by front controller servlet which is mapped on /*
How to handle static content in Spring MVC?
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);
}
}
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.
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.
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 !
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.
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();
}
}
}
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);
}
Related
i'm looking for a way to write a programm wich should intercept all browser's post and get requests.
The program should filter these requests and search for some resources. I want to forbit access to these resources.
It should be a kind of parental control.
I have:
apache tomcad;
java.
P.S. Sorry for my english, i know it's not perfect=)
Thanks.
Remark: the program should be a desktop appleication.
Try with a Filter. Here a short description about it.
A filter is an object that performs filtering tasks on either the request to a resource (a servlet or static content), or on the response from a resource, or both.
Examples that have been identified for this design are:
Authentication Filters
Logging and Auditing Filters
Image conversion Filters
Data compression Filters
Encryption Filters
Tokenizing Filters
Filters that trigger resource access events
XSL/T filters
Mime-type chain Filter
Sample code:
web.xml:
<filter>
<filter-name>MyFilter</filter-name>
<filter-class>com.x.y.z.servlet.MyFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>MyFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
MyFilter.java:
public class MyFilter implements Filter {
#Override
public void init(FilterConfig filterConfig) throws ServletException {
// read init-parameter from web.xml
}
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse,
FilterChain filterChain) throws ServletException, IOException {
HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;
String uri = httpServletRequest.getRequestURI();
// do what you want to do based on uri
// call below method to propagate it to next servet/jsp/filter in the chain
// filterChain.doFilter(servletRequest, servletResponse);
}
#Override
public void destroy() {
}
}
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>
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:
How to prevent static resources from being handled by front controller servlet which is mapped on /*
How to handle static content in Spring MVC?
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);
}
}
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.
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.
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 !
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.
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();
}
}
}
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);
}
This is what I want to do :
A servlet is called.Before a servlet is called , the request is intercepted by a filter. Filter gets some details out from the request,sets them as an attribute and the forwards it to a servlet via chain.doFilter(request,response). Request finally reaches the servlet. Servlet gets the attribute set by the filter before and sets a new attribute by another name. Then it forwards it to some jsp page where the page gets the attribute and processes it.
How do I do this ? I know how to write a filter and a servlet but how do I forward it to a jsp page from the servlet or is there any other way to achieve this ?
You can use the RequestDispatcher.forward method from your servlet:
public class YourServlet extends HttpServlet {
public void doGet(HttpServletRequest request,
HttpServletResponse response) throws ServletException, IOException {
RequestDispatcher rd = getServletConfig().getServletContext()
.getRequestDispatcher("/yourJsp.jsp");
rd.forward(request, response);
}
}
See also javaee 5 tutorial
EDIT: I've tested this approach on tomcat 7 examples:
I've enabled the example timing filter
I've invoked the servletToJsp example (in this example a servlet forwards to a jsp)
Everything works perfectly. The filter does his job and there are no exceptions.
You should have specified from the start that you had a problem and provide stacktrace, etc.
Regarding the question in the comments:
why not request.getRequestDispatcher ?
In the example I provided makes no difference as I'm calling an absolute path. The request.getRequestDispatcher is useful when dealing with relative paths. See this SO question.
EDIT 2:
I'm attaching the sources with the filter, servlet and jsp.
Filter:
package tests.filters;
import javax.servlet.*;
import java.io.IOException;
public final class ExampleFilter implements Filter {
private String attribute = null;
private FilterConfig filterConfig = null;
#Override
public void destroy() {
this.attribute = null;
this.filterConfig = null;
}
#Override
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
if (attribute != null)
request.setAttribute(attribute, this);
long startTime = System.currentTimeMillis();
chain.doFilter(request, response);
long stopTime = System.currentTimeMillis();
filterConfig.getServletContext().log
(this.toString() + ": " + (stopTime - startTime) +
" milliseconds");
}
#Override
public void init(FilterConfig fConfig) throws ServletException {
this.filterConfig = fConfig;
this.attribute = fConfig.getInitParameter("attribute");
}
#Override
public String toString() {
if (filterConfig == null)
return ("TimingFilter()");
StringBuilder sb = new StringBuilder("TimingFilter(");
sb.append(filterConfig);
sb.append(")");
return (sb.toString());
}
}
Servlet:
package tests.servlets;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class ServletToJsp extends HttpServlet {
private static final long serialVersionUID = 1L;
#Override
public void doGet (HttpServletRequest request,
HttpServletResponse response) {
try {
request.setAttribute ("servletName", "servletToJsp");
getServletConfig().getServletContext().getRequestDispatcher(
"/jsp/jsp-to-servlet/hello.jsp").forward(request, response);
} catch (Exception ex) {
ex.printStackTrace ();
}
}
}
JSP:
<html>
<body bgcolor="white">
<h1>
I have been invoked by
<% out.print (request.getAttribute("servletName").toString()); %> Servlet.
</h1>
</html>
web.xml
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0"
metadata-complete="true">
<filter>
<filter-name>Timing Filter</filter-name>
<filter-class>tests.filters.ExampleFilter</filter-class>
<init-param>
<param-name>attribute</param-name>
<param-value>tests.filters.ExampleFilter</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>Timing Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<servlet>
<servlet-name>ServletToJsp</servlet-name>
<servlet-class>tests.servlets.ServletToJsp</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ServletToJsp</servlet-name>
<url-pattern>/servletToJsp</url-pattern>
</servlet-mapping>
</web-app>
I also provide a download link that contains the example packaged as a war: http://goo.gl/GaV5w (7 days availability)
Just copy the file in your tomcat 7 webapps directory and call from your browser: http://localhost:8080/webapp-javaee6-1.0-SNAPSHOT/servletToJsp. You'll see in the logs/localhost.currentDate.log file that the filter prints the processing time and the jsp display its content.
I can't do anything more to convince you that this approach works and your problem (if you have one) is in other place.
Yes when we give the wild-card. It means that for any request the filter will
first intercept the request. You can practically imagine this scenario in a
full fledge web application where you need to introduce security. In most simplest
form you will write a Security filter which will authorized your user. So you can
give the mapping as generic so that for every request first your security filter is
invoked. You get IllegalState exception when you have already committed the response.
Is your code working fine? Please post your code if it is not working still.
HTH,
Ben
I wrote a filter that needs to be invoked every time a url on my site is accessed EXCEPT the CSS, JS, and IMAGE files. So in my definition I'd like to have something like:
<filter-mapping>
<filter-name>myAuthorizationFilter</filter-name>
<url-pattern>NOT /css && NOT /js && NOT /images</url-pattern>
</filter-mapping>
Is there anyway to do this? The only documentation I can find has only /*
UPDATE:
I ended up using something similar to an answer provided by Mr.J4mes:
private static Pattern excludeUrls = Pattern.compile("^.*/(css|js|images)/.*$", Pattern.CASE_INSENSITIVE);
private boolean isWorthyRequest(HttpServletRequest request) {
String url = request.getRequestURI().toString();
Matcher m = excludeUrls.matcher(url);
return (!m.matches());
}
I think you can try this one:
#WebFilter(filterName = "myFilter", urlPatterns = {"*.xhtml"})
public class MyFilter implements Filter {
#Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
String path = ((HttpServletRequest) request).getServletPath();
if (excludeFromFilter(path)) chain.doFilter(request, response);
else // do something
}
private boolean excludeFromFilter(String path) {
if (path.startsWith("/javax.faces.resource")) return true; // add more page to exclude here
else return false;
}
}
The URL pattern mapping does not support exclusions. This is a limitation of the Servlet specification. You can try the manual workaround posted by Mr.J4mes.
Probably you could declare another "blank" filter for css, js etc, and put it before others filter mapping.
I used the security-constraint to access control. See the code:
<security-constraint>
<web-resource-collection>
<web-resource-name>Unsecured resources</web-resource-name>
<url-pattern>/resources/*</url-pattern>
<url-pattern>/javax.faces.resource/*</url-pattern>
</web-resource-collection>
</security-constraint>
I follow this tutorial.
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>
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:
How to prevent static resources from being handled by front controller servlet which is mapped on /*
How to handle static content in Spring MVC?
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);
}
}
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.
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.
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 !
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.
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();
}
}
}
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);
}