I'm writing my first ever javax.servlet.Filter impl and am trying to write the portion of the doFilter method where I prevent the request from going any further in the chain:
#Override
public void doFilter(ServletRequest request, ServletResponse response)
FilterChain chain) throws IOException, ServletException {
// Check for some stuff in the request...
boolean passesInspection = inspect(request);
if(!passesInspection)
// How do I prevent the request from going any further?
// I don't want it even getting to the servlet at this point!
}
How do I "block" the request from even making it to the listening servlet? Thanks in advance.
Simply don't call chain.doFilter(). The doFilter() call is what progresses the call. Don't call this and the processing stalls. This is not a good design however. You need to at least inform the caller
Related
I'm trying some URL on browser, it works well on all browsers including IE 10 but when on Microsoft Edge, it fails at a point while doing HttpServletResponse sendRedirect, which expires HttpServletRequest session and the expected page does not appear.
Please help for how we can resolve this browser specific redirect-session issue.
Basic code:
public class MyServlet extends HttpServlet {
public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
// some code where values are set in session
session.setAttribute(myAttribute, value);
response.sendRedirect("https://qa.sys.com/MainPage.jsf");
}
public class MyFilter implements Filter {
#Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
// myAttribute below comes null as request.getSession() is null
Boolean myAttribute = request.getSession().getAttribute(myAttribute);
}
In logs, I got this Exception:-
java.lang.IllegalStateException: Response already committed
at weblogic.servlet.internal.ServletResponseImpl.objectIfCommitted(ServletResponseImpl.java:1861)
at weblogic.servlet.internal.ServletResponseImpl.sendRedirect(ServletResponseImpl.java:961)
at weblogic.servlet.internal.ServletResponseImpl.sendRedirect(ServletResponseImpl.java:956)
at weblogic.servlet.internal.FilterChainImpl.doFilter(FilterChainImpl.java:78)
Truncated. see log file for complete stacktrace
You could also use F12 dev tools to check the Network tab in Edge and see if there's any error in console. This error usually occurs when a java servlet is attempting to write to the output stream (response) after the response has been committed. You could refer to this thread to find out why the response will get committed.
In this blog, it gives the solution and you could also refer to the sample code in the post:
It is always better to ensure that no content is added to the response after the forward or redirect is done to avoid IllegalStateException. It can be done by including a ‘return’ statement immediately next to the forward or redirect statement.
I also find an answer with detailed information about this issue and you could check it.
I am actually pretty new to the Java EE specifications since I am kind of young. I never learned this things at school and I am facing a weird behaviour with the doFilter method.
Consider the following filter :
#WebFilter(filterName = "URLFilter", value = "/test")
public class URLFilter implements Filter {
public void destroy() {}
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException {
HttpServletResponse response = (HttpServletResponse) resp;
if (response.getStatus() == HttpServletResponse.SC_NOT_FOUND)
response.sendRedirect("/");
chain.doFilter(req, resp);
}
public void init(FilterConfig config) throws ServletException {}
}
There is no servlet or page present in /test and in my browser, the status is obviously a 404 not found error when accessing the URL and so should be the value returned to me by the getStatus() method which isn't. (actually having a 200 status code)
Why is my filter not redirecting me to / as requested ? Do I misunderstand the use of Filters in general ?
UPDATE:
My question was about redirecting the client (using the sendRedirect()) when a page is not found. I did not understand the filter part because I didn't know that resp and req are actually filled with the new data when chain.doFilter() is called. (which I actually found strange since the doFilter is calling the next Filter chained by the COR pattern)
I've made a class inheriting the HttpServletResponseWrapper, implemented it, passed it to the Filter and it's working fine now.
Your filter is invoked before trying to access the actual resource (servlet, page, file, whatever) located at /test. So the response status can't be 404 yet at this time.
Then your filter invokes chain.doFilter(), thus telling the container to actually serve the resource at /test. Since there is no such resource, you get a 404.
I use a 3rd party framework to process my requests by passing HttpServletRequest and HttpServletResponse into the framework. The database transaction handling is done separately from the framework like this:
public class MyServlet extends HttpServlet {
#Override
protected void service(HttpServletRequest req, HttpServletResponse resp)
throws ServletException, IOException {
startTransaction();
framework.process(req, resp);
commitTransaction();
}
}
As it turns out, the framework writes the full response back to the client before the call to commitTransaction() returns. This creates possible race-conditions: The client might issue a follow-up request that runs in a second new database transaction that can't access the data added or updated in the first transaction, because it is not committed yet.
What are best practices to work around those kind of issues? I can't modify the behavior of the framework I'm using.
I suggest to use a ServletFilter for such concerns. It would look like this:
public void doFilter(
ServletRequest request,
ServletResponse response,
FilterChain chain) throws IOException, ServletException {
startTransaction();
chain.doFilter(request, wrapper);
commitTransaction();
}
However, you should add exception handling to the filter.
I need to change the serverName of the ServletRequest object in my Grails controller. I'm having trouble figuring out how to do this since the serverName is a read-only property.
The most correct thing to do is probably to set up a clever filter or redirect which "fixes" your request URL before your servlet even gets involved. I know nothing about how to do that; you should ask on serverfault.com if you want to do that.
In java, you can fake it by creating your own subclass of HttpServletRequestWrapper which provides setServerName() and overrides getServerName() while delegating all other methods to the superclass. You can then provide a filter which creates an instance of your request and sends that one down the chain.
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain)
throws IOException, ServletException {
YourHttpServletRequest yourRequest =
new YourHttpServletRequest(request, newServerName);
chain.doFilter(yourRequest, response);
}
If I understand this correctly, CORS filter might help
I've used http://software.dzhuvinov.com/cors-filter.html in my previous project.
But you can also lookup on github for example https://github.com/eBay/cors-filter
I have two CNAME-s pointed to the same server. I want to assign one servlet to the first CNAME and another one to the second CNAME. Can I do it in web.xml (or somehow else without manual parsing of ServletRequest)?
One of the idea to have a filter, and in it have a condition based on ServletRequest#getServerName() and dispatch the request to appropriate servlet, will do.
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
...
[other processing/validations]
...
if(request.getServerName().equals("domain1.com"))
request.getRequestDispatcher("/servlet1").forward(request, response)
else
request.getRequestDispatcher("/servlet2").forward(request, response)
}
obviously, you could have <init-param> in your web.xml to dynamically set the domains, so that you could change these values based on your build profile.