flush() in rd.include vs rd.forward() - servlets

I have the following code snippet in my web app:
if (request.getParameter("user").equals("luke")||session == null && !(uri.endsWith("html") || uri.endsWith("LoginServlet"))) {
System.out.println("<<<----------denied------------->>>>");
pw.println("zzzzzzzzzz");
this.context.log("Unauthorized access request");
pw.flush();
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//res.sendRedirect("login.html");
req.getRequestDispatcher("login.html").include(request,response);
}
When I am using flush before Forward(), it's throwing IllegalStateException (since the response is sent the moment we call flush and later we are trying to resend the response using forward) but the code works fine even after I provided flush before the rd.include(). Why doesn't it throw the exception here?
TIA

This behavior is explained in the Servlet Specification for the forward method in chapter 9.4 and for the include method in chapter 9.3.
The javadoc also explains this in a little detail.
The javadoc entry of HttpServletResponse#getWriter() states
Calling flush() on the PrintWriter commits the response.
Committing the response means writing the status line and headers and flushing whatever part of the response body is in the buffer.
The javadoc of forward states
Forwards a request from a servlet to another resource (servlet, JSP
file, or HTML file) on the server. This method allows one servlet to
do preliminary processing of a request and another resource to
generate the response.
So the forward to resource must take care of generating and committing the response. It can't do that if the response has already been committed.
The javadoc of include states
The included servlet cannot change the response status code or set
headers; any attempt to make a change is ignored.
This method just takes the content of another resource and writes it to the response. It can't do anything to headers or the status code. As such, committing before or after makes no difference.

The forward and the include are different methods, the include method allows you to add content to the response, you have a include tag in jsp, the include method is the similar but in the server.
The forward method transfer the request processing to another process (servlet, jsp) and that process must change the response, that is why you get that exception, you can't change the response before forward it.
You could check the documentation for those methods here.

Related

Disable access to a Servlet

I'm developing a WebApp using JavaEE and I use a servlet to test some stuff.
Currently, my WebApp is set as when I go to my local url localhost:8080/myApp/test , I can run my test Servlet.
My plan is to deploy my project to a Web and I want to disable the Servlet, but not delete it. I mean, if in the future I visit my remote server via URL www.myNewWeb.com/test , I would like it throws an error od do nothing.
How could I do that?
There are many possible options here:
Option 1
Remove the mapping (annotation #WebServlet or url mapping entry in web.xml). In this case, any attempt to call this servlet will end with an error generated by the JEE container of your choice. It will try to map the servlet to URL, will obviously fail and throw an exception
The obvious drawback of this method is that you need to change the deployment configuration and if you'll want to run the same artifact in another envrironment where this servlet should work you won't be able to do so.
Option 2
Create some kind of configuration, load this configuration along with your application.
In the doGet (just for the sake of example) method do something like this:
public void doGet(request, response) {
if(config.isTestServletEnabled()) { // this is where the data gets read from configuration that I've talked about before
// do your regular processing here
}
else {
// this will happen when the servlet should not be activated
// throw an exception, return HTTP error code of your choice, etc
}
}
This way doesn't have a drawback of the first method that I've explained above, however involves some code to be written.

How to get the HTTP-Status from a webMethods com.wm.net.NetException?

How to get the HTTP-Status from a webMethods com.wm.net.NetException?
Is there a way to get the http status code from within the catch block of a java service after calling the pub.client:http service?
If you invoke the pub.client:http from within a flow service, you'll notice that it doesn't throw an exception. For example, a "403 Forbidden" error, will not throw an exception. Instead, it will output to the pipeline a header document.
Within the header document you will find the http status:
When you invoke pub.client:http from within a java service then the invocation is suppose to return an IData object. From that object you should be able to extract the status field using IDataUtil.
So, when you evaluate that the status is not OK, you can throw a ServiceException which will be caught by the flow try/catch.
Hope this helps!

Spring MVC Returns Response Before Completion of Controller Method

I have the following method which is returning an incorrect response to the browser before the method is even complete. This is in Spring 3.2.
#RequestMapping(value="/process1/createEditContract/validate", method=RequestMethod.POST)
public #ResponseBody StatusResponse validateProcess1(#ModelAttribute("contractEditForm") #Valid Process1CreateEditContractDTO dto, BindingResult bindingResult) {
StatusResponse response = new StatusResponse();
response.setSuccess(true);
if (bindingResult.hasErrors()) {
log.debug("Errors found. Processing status response");
response.setSuccess(false);
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
for (FieldError fe: fieldErrors) {
response.getMessages().add(messageSource.getMessage(fe, null));
}
}
return response;
}
StatusResponse is a simple object that a javascript function in the JSP reads to generate a Javascript alert stating whether the action was successful or errors occurred. The method makes it all the way through, but as soon as it tries to write the response, I get this:
java.net.SocketException: Software caused connection abort: socket write error
I've been stuck for a day now, any help would be appreciated.
UPDATE
I rolled back from Spring 3.2 to Spring 3.1, and the wording of the error message changed enough to give me more information.
Basically, I'm getting now seeing this:
IllegalStateException: Response already committed
What I don't see is what is causing the response to commit so quickly. Maybe a conflict with the OpenSessionInViewFilter?
This error can occur when the local network system aborts a connection, such as when WinSock closes an established connection after data retransmission fails (receiver never acknowledges data sent on a datastream socket).". See this MSDN article. See also Some information about 'Software caused connection abort.
To prove which component fails I would monitor the TCP/IP communication using wireshark and look who is actaully closing the port, also timeouts could be relevant.
The javascript runs in browser, and your controller runs on server. You cannot pass a complex object from the controller to the javascript without converting it to a textual format such as xml or json.
So you should :
choose a format (say json)
add a produces="application/json" in your RequestMapping annotation
do generate json in your controller method

IllegalStateException:STREAM when calling response.getWriter

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.

jetty webSocket : java.lang.IllegalStateException: Committed

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 !

Resources