views:

874

answers:

5

Hi,

I am creating a CAPTCHA input using SimpleCaptcha, and did validation of the Captcha input. I am created a captcha input with the following codes.

HTML Code:

<form action="submit_proceed.do" method="post">
<img src="captchaImg" /><input type="text" name="captcha" value=""><br />
<input type="submit" value="Submit" name="submit" />
</form>

JavaServlet Code :

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.List;
import java.util.Iterator;
import nl.captcha.Captcha;

protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();

List errorMsgs = new LinkedList();
try{
    // Validate Captcha
    HttpSession session = request.getSession(true);
    String userCaptcha = request.getParameter("captcha");
    Captcha captcha = (Captcha) session.getAttribute(Captcha.NAME);
    if (!captcha.isCorrect(userCaptcha)) {
        errorMsgs.add("Please input the correct Captcha value.");
    }
} catch (RuntimeException e) {
    errorMsgs.add("An unexpected error: " + e.getMessage());
    RequestDispatcher view = request.getRequestDispatcher("/error.view");
    view.forward(request, response);
}

However I kept getting this error:

StandardWrapperValve[Captcha]: PWC1406: Servlet.service() for servlet Captcha threw exception
java.lang.IllegalStateException: PWC3999: Cannot create a session after the response has been committed

How do I create a session on my servlet? How can I resolve this issue?

Thank you very much.

A: 

Seems, that you already sent the header to the client before handling the post. If you create a session, the server needs to send the session ID to the client. This is usually done by sending a cookie. I suppose you check your code for whether you execute the action handling before you send anything back to the client.

oeogijjowefi
A: 

create session by adding this javax.servlet.http.HttpSession session = request.getSession();


try{ 
 javax.servlet.http.HttpSession session = request.getSession();
    // Validate Captcha 
    String userCaptcha = request.getParameter("captcha"); 
    Captcha captcha = (Captcha) session.getAttribute(Captcha.NAME); 
    if (!captcha.isCorrect(userCaptcha)) { 
        errorMsgs.add("Please input the correct Captcha value."); 
    } 
} catch (RuntimeException e) { 
    ... 
} 
valli
what value would we then expect session.getAttribute(Captcha.NAME); to return?
djna
A: 

This line

 (Captcha) session.getAttribute(Captcha.NAME);

implies that the session should already exist before this particular request is being processed, hence I wonder is there is some initialisation you are supposed to do before sending your original form. This should be specified by the framework your are using.

For example you might have an initial serlvet that

 creates the image, figures out the value of Capcha.Name
 creates the session 
 session.setAttribute(Capcha.NAME, theName)
 emit the html (or forward() to a JSP)

You could do that all in a JSP, or you could have your servlet forward to one.

Are there any examples of usage of this catcha library you could examine?

djna
@djna: How do I initialize before sending out the original form?
jl
@djna: i am using Simple Captcha, http://simplecaptcha.sourceforge.net/index.html, but they only state an example in jsp. I really need to convert it into servlet.
jl
+1  A: 

Move this line:

HttpSession session = request.getSession(true);

to be first statement in doPost method.

protected void doPost(HttpServletRequest request, HttpServletResponse response)
  throws ServletException, IOException {

  HttpSession session = request.getSession(true);

  response.setContentType("text/html;charset=UTF-8");

  //...
}

This should help.

WildWezyr
@WildWezyr: Shifted to the top, but the exception message still exists.
jl
@jl: are you sure you properly rebuild and redeployed your webapp before testing ;-) ? this is some times the case when testing fixes that should work but they seem not to...
WildWezyr
@WildWezyr: i rebuild and clean and load via netbeans.
jl
@jl: sometimes something in netbeans gets stuck and you must stop and restart servlet container (tomcat or something similar) to properly reload your changed webapp...
WildWezyr
+5  A: 

Cannot create a session after the response has been committed

The exception message is pretty clear. There's means of an illegal state. You cannot set/change the response headers anymore when the response is already been committed. A response is committed when the headers are already been sent to the client side. This is a point of no return.

The response will be committed whenever the outputstream has been flushed (in)directly. That can happen when you write more than 2K to the response (depends on server config however), or did flush() manually, or did a sendRedirect() call.

Whenever the session needs to be created, the server needs to set a cookie in the response header so that it can identify the particular client and associate it with a HttpSession instance in the server memory. But that's not possible if the response is already committed, hence this exception.

Back to the root cause of this problem:

Servlet.service() for servlet Captcha threw exception

It is the servlet with the servlet-name of Captcha which caused this problem. You need to check/debug the entire request-response chain to see which servlets/filters are all invoked and which of them might have committed the response before the Captcha servlet was able to create the session. I can't help you more further as this information is missing in your topicstart.

At least, in the as far given code example, I see that you're unnecessarily calling response.getWriter(). I am not sure how the real world code look like, maybe you've stripped some lines, but chances are that you're actually writing to it and that might be the root cause of the problem. If you write too much or did a flush on it, then the resopnse will be committed. Do not write to the response inside a Servlet which is supposed to be a controller. There you normally use the JSP for. Or if it is for debugging purposes, use the stdout (System.out.println()) or a Logger.

BalusC
@BalusC: yes you are right. it's perfectly the issue with session. And captcha is indeed creating the problem. Managed to resolve the issue by shifting the session setAttribute before the captcha image is generated. Thanks.
jl