I have a simple (Servlet, JSP, and JSTL) web app whose main functionality is displaying images retrieved from a back-end server. The controller servlet forwards the user to a JSP that in turn uses another Servlet to display the resulting image on that same JSP. Further down, the JSP has a line similar to:
<img src="<c:out value='${imageURL}'/>" alt="image view" border="1">
which invokes a GET request on the image-generating servlet causing it to generate the image.
My question is: how do I handle Exceptions thrown by this image-generating servlet?
I already have an error page defined (in web.xml) to handle ServletException within my web app but this doesn't work for this image-generating Servlet, and results in the following errors showing up in my Tomcat server logs:
SEVERE: Exception Processing ErrorPage[exceptionType=javax.servlet.ServletException, location=/WEB-INF/ExceptionPage.jsp]
java.lang.IllegalStateException: Cannot reset buffer after response has been committed
What's my recourse in this situation?
I'd like to be able to handle Exceptions thrown from this image-generating Servlet, and display some error on the main UI or forward the user to another error page.
You can't change the response to redirect to an error page while sending the response. It's already too late to change the entire response then. You can't ask those already sent bytes back from the client side. That's what the IllegalStateException stands for here. It's a point of no return.
Best what you can do is to just log the exception, or to rewrite the code so that it doesn't write any bit to the response (also not setting the response headers) while the business logic hasn't finished its task yet. Once you've determined that the business logic didn't throw any exception, then start writing (and thus indirectly also committing) the response. If the business logic has thrown an exception while the response isn't touched yet, then you can just safely throw it through so that it ends up in an error page. Although in case of an image servlet, you may also want to stream some standard 404.gif to the response instead. This because you can't display another HTML (error) page in an <img> element and you also can't change the URL of the parent JSP/HTML page as well since that concerns a different request.
According to the servlet API no servlet should call the getWriter() and getOutputStream() on the same response object as it causes the IllegalStateException. Usually this is the source of this exception. If you're outputing binary data like and image file you should use getOutputStream().
Looks like the problem you have is within your ExceptionPage.jsp, not your servlet code.
And this
java.lang.IllegalStateException:
Cannot reset buffer after response has
been committed
Means that you've already have tried to send a response.
Probably you've opened an output stream directly and wrote some data to it. Once you've done it you cannot try to set headers and such on a response ( they are already on their way to the client ).
You need to do a better state management. Best way to do this is to separate request preprocessing from the response generation. Once you are writing response, you can only do or die. For this, check that you are not catching IOExceptions from the response output, wrapping them to ServletException and redirect them to your error page. You really cannot handle them in the context of the current request.
First, identify why the Illegal State exception is being thrown. Rather than dealing with a thrown exception, you probably just want to fix your code so that it goes away.
You should catch the exception and forward the request using RequestDispatcher to the required page:
public void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// The following piece of code results in NumberFormatException which will
// be detected by the container. The RequestDispatcher object will forward
// the same request to the other resource, here the file: forwardedJSP.jsp
try {
int test = Integer.parseInt("abc");
} catch (NumberFormatException nfe) {
RequestDispatcher rd = request.getRequestDispatcher("/forwardedJSP.jsp");
rd.forward(request, response);
}}
Related
One of our developers wrote a portlet that uses the doView method to render relevant content. However, we are receiving NPE's if the user goes to a page under a valid route of that portlet with no valid record.
An example is:
/<location>/<postcode>/<propertyname>
/london/w1/10-downing-street - VALID
/london/w1/sdsd-downing-streetsss - INVALID
The slug will pull the record from the db as it's unique but if it's invalid it throws an NPE on fillRenderRequestAttributes and we need it to throw a status 404.
Code
public void doView(RenderRequest renderRequest, RenderResponse renderResponse) throws IOException, PortletException {
fillRenderRequestAttributes(renderRequest, renderResponse);
if(_log.isDebugEnabled())
{
_log.debug("DoView");
}
try
{
super.doView(renderRequest, renderResponse);
}
catch(Exception e)
{
_log.debug("Broken");
e.printStackTrace();
}
}
I assume we need a try/catch around fillRenderRequestAttributes and in the catch we need to throw a 404? How can this be done? Any examples would be helpful.
doView is rendering a portlet's output, not a full page. Thus, it doesn't have a status code. The page is rendered elsewhere (e.g. decorated with the theme, and with any number of other portlets on the page that might still show relevant content).
In the portlet world you're not dealing with HttpServletRequest/Response pairs, but with PortletRequest/Response pairs (as seen here in the incarnation of RenderRequest/Response). Thinking in HTTP return codes is wrong: You can't even guarantee that the portlet is rendered before the response is already sent back to the browser: Once you determine that your portlet can't render appropriate output, the page might already be on its way, with status code 200. Or it might be rendered asynchronously and just injected into a page.
If the portlet can't render appropriate output in doView, you'll need to catch the exception and display a proper error message in the portlet.
Otherwise, consider implementing serveResource, where you have more control, or a REST endpoint. But note: 404 is a technical error, while you're handling a business layer error - both should be handled differently.
The problem is: I have a page1.jsp which is submitted and forwarded to page2.jsp. The problem is that the forwarded output should be only the content in page2.jsp, instead of that is showing me content from page1.jsp and immediately the content from page2.jsp
I'm using requestDispatcher.forward(String) but i don know why is this happening
PS: I'm using JE 1.4
Well it seems you have got the method signature incorrect . As per the javaee 1.4 API:
public void forward(ServletRequest request,ServletResponse response)
throws ServletException,
java.io.IOException
Hence your code should be :
RequestDispatcher dispatcher = request.getRequestDispatcher("page2.jsp);
dispatcher.forward( request, response );
Better , you can use the <jsp:forward> standard action.
The JSP that contains the action stops processing, clears its buffer, and forwards the request to the target resource. Note that the calling JSP should not write anything to the response prior to the action.
Suggested Reading:
How to avoid Java Code in JSP-Files?
Hi I am fairly new to Java Servlets. I want to ensure that the execution on the server side code is exception free i.e I want to check if there was any exception thrown on the server code. How can I determine that using the response that I get?
Thank you
Since, a Servlet executes server-side it's the server-side code that determines whether the client should be made aware of an exception or not. A client wouldn't come to know of it automatically unless the exception is not handled (within the servlet code) and no error pages were set for the web application (both of which aren't recommended).
Ideally, a client should never be made aware of the exact exception. Instead, the client should just receive a proper error message as to why the current request couldn't get processed successfully.
Error details should be shared on need to know basis. For example, if the input validation fails it makes sense to include the name of the field that was invalid in your error message. It isn't proper to show a NumberFormatException instead (say, because the client entered an age that was non-numeric).
EDIT:
There's no one single right approach here. There are various methods you can adopt based on how much descriptive your web application wants to be about the error to your client.
If you just require to let the client know that an error occurred with a brief error description you can use sendError() (which behind the scenes would automatically set the HTTP status header to an error code like 400 Bad Request below)
if (request.getParameter("id") == null)
response.sendError(response.SC_BAD_REQUEST, "ID parameter missing");
Other approaches include configuring <error-pages> in your web.xml for different error codes or exceptions. The container would take care of automatically forwarding to the .jsp files configured below.
<error-page>
<error-code>404</error-code>
<location>/error404.jsp</location>
</error-page>
<error-page>
<exception-type>java.lang.Exception</error-code>
<location>/errorPage.jsp</location>
</error-page>
The JSPs need to have their isErrorPage attribute set to true to receive an implicit exception object to get more information about the exception. For example, exception.getMessage() could be used (in some cases) to generate the error message to be shown to the user.
The client side
The client doesn't need to do anything special (like a getError()) to receive the error. The client would still be receiving HTML that gets rendered by the browser just like if the request had succeeded but since it didn't, the client would receive the error message formatted as HTML (can even view > source it).
The HTML sent depends on whether you used sendError() (which would send the standard error response from your web server like Tomcat) or your own configured <error-page> JSPs in which case you have complete control over your HTML error template.
If you get the content from the servlet, there where not unhandled exceptions. If you want to get info of handled exceptions, log them in their catch clause.
Use log4j to catch your exception (using try catch block) but if this is some kind of homework you are working then this might be one way you could check based on the http return code. you can use jquery http://jquery.com/. Here is sample code for 404 error.
Also this page has all the http error code and what they mean.
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
<script>
$(function() {
var urlPath = "some_url";
$.ajax(urlPath,
{
statusCode: {
404: function() {
alert('page not found');
}
}
});
});
</script>
Someone please HELP ME.
private void forward(String address,
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException{
getServletContext()
.getRequestDispatcher("/" + address)
.forward(request, response);
}
private void include(String address,
HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException{
getServletContext()
.getRequestDispatcher("/" + address)
.include(request, response);
}
These two functions have been written in every servlet in my project and the problem is that when I have used these two functions in a servlet at first include("servlet/abc",request.response); and after it have used forward("servlet/def",request.response); so using Netbeans 7 I have step by step watched that forward is not forwarding the control of servlet but when I don't use include before the forward its forwarding the control.
So I want to know that why it is happening and what's the reason and how can I do forward after include any servlet.
Please someone HELP ME ...it's an interesting question.
include("servlet/abc",request, response);
forward("servlet/def",request, response); //HERE IS PROBLEM NOT FORWRDING AFTER INCLUDE
Regardless of exactly why you seem to observe this behavior, what you're attempting will never work. Per the contract of RequestDispatcher.forward(), "If the response already has been committed, this method throws an IllegalStateException," and "Uncommitted output in the response buffer is automatically cleared before the forward."
Therefore, whether the forward succeeds or not, you'll never be able to successfully send content back to the user both before and after a forward. This is because the purpose of a forward is to allow "one servlet to do preliminary processing of a request and another resource to generate the response", not to let two different servlets generate different parts of the response. In the Servlet model, generating a response always belongs to exactly one servlet.
If you don't know what "committed" and "uncommitted" means, it's referring to whether the response status and headers have been sent to the user yet. When you're writing a response, you're actually writing into a local buffer. Nothing will necessarily be sent immediately. As long as everything you've written is still local, you're free to do whatever, including resetting the buffer and starting over, like a forward does, but as soon as something is sent off, you're committed and can no longer change what you were going to do. A response can become committed (i.e. be all or partly sent to the user) in a few ways, including filling up the buffer so that it has to be sent to make room for more content, flushing the buffer manually, or flushing the Writer or OutputStream of a response.
Ultimately, what's probably happening in your case is that you're writing some stuff using an include, and it's causing the response to be committed, either because you've filled the buffer or because I seem to recall that an include generally causes an automatic flush (not sure about documentation on this one). Then when you try to forward, it's throwing the required IllegalStateException, which you should probably see in your logs somewhere, but won't cause the typical 500 response status since, as I've discussed, you've already committed with some other status code.
You cannot change the response status or state once response is committed. When you include some page using request dispatcher you are actually committing response and data is starting to be sent to client. After that you are not allowed to make a change of response status to 302 which is required for redirect.
You will get an error java.lang.IllegalStateException: Cannot forward after response has been committed if you try that.
RequestDispatcher has only two methods:
public interface javax.servlet.RequestDispatcher {
public abstract void forward(javax.servlet.ServletRequest, javax.servlet.ServletResponse) throws javax.servlet.ServletException, java.io.IOException;
public abstract void include(javax.servlet.ServletRequest, javax.servlet.ServletResponse) throws javax.servlet.ServletException, java.io.IOException;
}
You are giving it as
include("servlet/abc",request, response);
forward("servlet/def",request, response);
but in the API it is mentioned only servlet request object and response object as parameters, so I guess you should remove your url from there. Correct me if I'm wrong, as I'm also learning.
there are a bunch of links accessing my servlet without https
As the servlet is a generic form and the http urls are generated with an random id it is difficult to use modrewrite or something like that.
Therefore I modified my servlet with code like that:
//redirect to https
String sec = servletRequest.getParameter("Sec");
String qString = servletRequest.getQueryString();
if (StringUtils.isEmpty(sec)){
try {
HttpServletResponse rsp = request.getServletResponse(true);
String PORTAL_URL = l_aliasHelper.getPath(request);
rsp.sendRedirect("https://"+servletRequest.getServerName() +PORTAL_URL+"?" +qString+"&Sec=yes");
} catch (Exception e) {
e.printStackTrace();
}
}
Now this works fine!
But, what if I want back to http because I want to avoid nagging warnings about insecure elements on other pages.
So how do I redirect to http again after the user has submitted the form?
If everything worked well the user gets displayed a response with a success message under the same URL he started.
So the cycle goes like this:
http://<somedomain>/<anypath>?<anyid>
https://<somedomain>/<anypath>?<anyid>&Sec=yes
and now it should go back maybe with a step inbetween to
http://<somedomain>/<anypath>?<anyid> <- the success message should be
displayed here
the last method before the message is displayed is
sucessmessage.render(request,response)
request and response are both appserver component specific views on all request / response related matters. They have methods like:
getServletResponse
public HttpServletResponse getServletResponse(boolean answering)
Gets the original servlet response. Note: This should be accessed
in extraordinary cases only. If the parameter is set to true all
further content procession of the runtime will be skipped. This is
only available, if the request was initiated from a servlet based
connection.
So how can the response be manipulated in a way that the form is submitted secure, but the user can go on with http on the rest of the site afterwards.
It seems like you are trying to do too much in one place. Maybe the following break down will be easier:
Specify https in the URL for the action parameter in HTML form.
Create a ServletFilter class that uses ServletRequest.isSecure() to
make sure that requests to your form action actually came in over
https. This could also be in your action servlet, but making it a filter means you can reuse it. Just make sure the secure servlets have this filter set.
In your form action servlet, simply send a redirect to the
success page over http