I have a very simple servlet, which contains the following code to build a response:
#Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
response.setContentType(CONTENT_TYPE);
final PrintWriter out = response.getWriter();
// ...
My Sonar raises a critical issue with the rule: "Exceptions should not be thrown from servlet methods". Sonar explains it's a bad idea to let such exceptions be thrown:
Failure to catch exceptions in a servlet could leave a system in a
vulnerable state, possibly resulting in denial-of-service attacks, or
the exposure of sensitive information because when a servlet throws an
exception, the servlet container typically sends debugging information
back to the user. And that information could be very valuable to an
attacker.
But if I understand their example, I cannot figure how to manage smartly the potential IOException on response.getWriter().
Some people can explain me when this statement can raise an exception, and how/why it's important to manage it by our-self?
EDIT:
I accepted the first answer despite that I was a little frustrated. I understand very well it's a bad practice to let the servlet container manages this exception as the default behavior expose the stacktrace and possible other sensitive information to the world.
In my case, the HTTP end-point was used for internal monitoring. So in my case, I wanted to expose (relevant) information and the question was HOW I can do that if I have no PrintWriter...
What I did: my program prints an error log and it returns an HTTP error code with no content. I don't know if it can really happen... but Sonar and me are happy.
By throwing an exception in a servlet you expose the stacktrace and possible other sensitive information to the world. You should catch the exception and print/show a nice error message.
It's simple: assume all the consumers your service has are idiots and need to be treated with kid gloves - that means sending them a nicely formatted error message with a description of your choosing instead of the whole Exception.
Related
I have implemented the following servlet post function on a jetty server. In the HttpServletResponse, it will just write some string.
protected void doPost(HttpServletRequest request, HttpServletResponse response) {
response.setHeader("Access-Control-Allow-Origin", "*");
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write("some json string");
response.getWriter().flush();
}
Everything was fine in the beginning. But after some time (a few days; i was not using it and just kept the jetty server running), the servlet starts to throw null pointer exception on the line response.getWriter().write("some json string");
java.lang.NullPointerException
at org.eclipse.jetty.server.ResponseWriter.write(ResponseWriter.java:246)
I don't know what went wrong. But after a restart of the jetty server, the problem was gone. Do you guys know why?
To answer the NullPointerException
java.lang.NullPointerException
at org.eclipse.jetty.server.ResponseWriter.write(ResponseWriter.java:246)
It seems that you gave the Writer a null String.
See: https://github.com/eclipse/jetty.project/blob/jetty-9.4.22.v20191022/jetty-server/src/main/java/org/eclipse/jetty/server/ResponseWriter.java#L246
The part where you say Jetty stops working after a few days is likely because you have a process on your machine that is periodically cleaning out the system temp directory, removing content out from underneath Jetty.
See: Jetty stops responding after some period of time
The NullPointerException is like is likely because the write failed and you didn't check for that fact.
HttpServletResponse.getWriter() returns a java.io.PrintWriter.
Using the various .write() methods will never throw an error or exception.
You need to use .checkError() method to know when the write has failed.
This is an old-school API decision on java.io.PrintWriter that is actually quite awkward.
See: PrintWriter and PrintStream never throw IOExceptions
I am trying to understand Spring security which involves method security and URL based security . URL based security is completely based on Servlet Filters. There are some scenarios when Spring security deals with exception thrown by filters chain to do its work.
I know how filters are executed by Servlet Container but I am particularly interested in how filterChain handle exceptions thrown by doFilter method in filter chain.
I am particularly interested in how filterChain handle exceptions thrown by doFilter method in filter chain.
It does nothing with them. In other words, it just lets them go and bubble up. They'll eventually end up in servletcontainer's builtin exception handler which already knows how to deal with them based on <error-page> configuration in web.xml.
You can however control it yourself by placing FilterChain#doFilter() call in a try-catch block like so:
try {
chain.doFilter(request, response) {
} catch (ServletException e) {
Throwable cause = e.getRootCause();
// ... (handle it)
}
If anything else down the chain (filter, servlet, jsp, etc) throws an uncaught exception, it'll end up there.
See also:
How does server prioritize which type of web.xml error page to use?
What is the good approach to forward the exception from servlets to a jsp page?
I don't think you are able to return anything meaningful in an errorMessage in the HttpServletResponse stream when trying/catching the doFilter method like that, unless you specifically intercept the HttpServletResponse stream and call something like sendError. And that has to be done even before the call to doFilter.
I am particularly interested in how filterChain handle exceptions
thrown by doFilter method in filter chain.
But I am interested in knowing how to send a meaningful response back into the stream when the exception happens within the filterChain. Because even if there is no Exception, how would you go about handling the success response if you have already called a method like sendError before the doFilter (?)
So when I'm writing to an HttpServletResponse's Writer, it can throw an IOException for any number of reasons. I mean, we're dealing with sockets here, and there's lots of things that could go wrong. Timeouts, aborts, velociraptors, etc.
I was always taught you should never catch an exception unless you can do something about it. But I'm not sure that really makes sense here. If I've already started writing, and something goes wrong, I can't really trust that anything is going to make it to my client. But I can't throw that exception to a higher level, because it's a checked exception.
What do I do if I actually get an IOException when writing my response in a servlet?
It is thrown for a reasone by Servlet service methods and its delegates. Developer is not supposed to handle those exception thrown by servlet APIs.
This exceptions are thrown when some thing is not right some where else and on your code.
You definitely need to handel IOException when you are doing some explecete IO Activity not related to servlet api.
so I will do it this way.
Servlet{
service throws ServletException, IOException {
do some styff...
do some styff...
try{
Doing some IO activity not related to Servlet api....
}catch(IoException iox){
}
do some styff...
}
}
Hope this helps.
This is a method that's used for handle ajax request. So the output is written to the response
public ModelAndView myAction(HttpServletRequest request, HttpServletResponse response, BindException errors) throws Exception
{
//call other methods and send the response as arg
//call getWriter on the response
}
According to this doc, I would definitely have an IllegalStateException if I call getWriter having already called getOutputStream(), so I suspect the methods I passed the response to did this although I don't really see them doing so...
The only thing for sure is that at some point, one of the methods may do response.sendError().
Does this some how call getOutputStream()?
HttpServletResponse#sendError() commits the response and send an error status code. The javadoc states
If the response has already been committed, this method throws an
IllegalStateException. After using this method, the response should be
considered to be committed and should not be written to.
In other words, after you call that method, the HTTP response has basically been sent. It makes no sense to call any of the getOutputStream() or getWriter() methods. Your Servlet container further makes it foolproof by throwing an Exception if you attempt to.
I had similar issues but I had not called sendError(), just setContentType() before that. As per this source, it can trigger the same behaviour:
I am guessing its because you have already opened the stream by
calling the resp.setContentType("text/plain"); method, and are then
trying to get a Writer object. You can either use Stream based
classes, or Writer based classes - not both.
Either remove the setContentType(), or send the response using
response.getOutputStream() method. That should solve the problem.
And indeed, it resolved the similar error for me.
I am using Jetty Websockets in my Web Application .
When i am trying to redirect to a logoff jsp , i am getting this error
oejs.ServletHandler:/test
java.lang.IllegalStateException: Committed
at org.eclipse.jetty.server.Response.resetBuffer(Response.java:1069)
at javax.servlet.ServletResponseWrapper.resetBuffer(ServletResponseWrapper.java:232)
at org.eclipse.jetty.http.gzip.GzipResponseWrapper.resetBuffer(GzipResponseWrapper.java:273)
at org.eclipse.jetty.server.Dispatcher.forward(Dispatcher.java:199)
at org.eclipse.jetty.server.Dispatcher.forward(Dispatcher.java:98)
This is the way i am redirecting
RequestDispatcher rd = request.getRequestDispatcher("logoff.jsp");
rd.forward(request, response);
This error is not reproduceble , but could you please tell me when it may occur??
java.lang.IllegalStateException: Committed
I thought I'd provide a more general explanation of what the exception means. First off, Jetty should be ashamed by the exception message. It provides little to no help to the developer unless they already know what it actually means. The exception should be something like:
java.lang.IllegalStateException: Response headers have already been sent. Are you trying to return a result after sending content?
Typically this exception happens when you go and call:
resp.getOutputStream(); // or getWriter()
and then later try to do a redirect or something:
resp.sendRedirect("/someOtherUrl");
// or
return new ModelAndView("redirect:/someOtherUrl");
Once you get the OutputStream or Writer so you can write body bytes to the client, Jetty has to commit the response and send the HTTP 200 and associated headers, so it can start returning the body bytes. Once that happens, you then can't do a redirect nor make any other changes to the status code or headers.
The proper thing to do, once you return body bytes, is to return null from the handler instead of a ModelAndView(...) or just change the handler to return void.
You also get this exception when you call the super method in your own method implementation.
Example:
#Override
protected void doPost(HttpServletRequest req, HttpServletResponse resp) {
super.doPost(req, resp); // <-- THIS IS THE PROBLEM
resp.sendRedirect("/someOtherUrl");
}
This occurs because your response has already processed a redirect request, you are trying to modify a committed response.
There are two general ways to solve this:
find out where the first redirect is and try to modify the logic to prevent the "two redirect" scenario from happening.
put a "return" after each of your redirect (personally I recommend this solution).
The reason on my side is using jetty with wrong url:
right: http://localhost:8080
wrong: http://localhost:8080/test
Consider you are running javax.servlet.Filter on Jetty server, and you face the same exception. The issue here can be described exactly as Gray's description (Thanks Gray). Typically this exception happens when you go and call:
resp.getOutputStream(); // or getWriter()
then
chain.doFilter(request, response);
If you called resp.getOutputStream();, make sure you are not using chain.doFilter(request, response); on the same request.
In my case I had some repository in my #Service and I declared it as RepositoryFoo repositoryFoo;, in the beginning of my class
I forgot to add #Autowired or even make it private, so it compiled fine and then when running I had this java.lang.IllegalStateException: Committed ... I wasted some time before figuring out the reason !