views:

677

answers:

3

I'm running into a problem with Apache Tomcat 6.0.20 where I can't change a cookie's value once it has been added to the response. Basically, I'm trying to replicate Session functionality using cookies. I have a custom "Session" object, which is backed by a cookie. When I create my Session, I pass it an HttpServletResponse, and it creates and adds a blank cookie to the response. Then, when my code calls the Session.put() method, I want to change the value of this cookie.

What I'm seeing is that once the cookie has been added to the response, any calls to Cookie.setValue() are basically useless. Using a debugger, I can see that the cookie itself is being modified but the Set-Cookie header in the response object remains unchanged (it contains the initial value of the cookie, usually just an empty string). I've even tried creating a new cookie and re-adding it to the response but this has no effect on the Set-Cookie header either.

The weird thing is I'm using a library written a few years ago by our own developers. In the past we used the JRun 3.1 web server, so I'm guessing maybe each web server handles these cookie operations differently.

Has anyone run into this problem before? The only solution I have now that's guaranteed to work is not adding the cookie to the response until I'm sure I'm done with my custom Session object. I can create a method called Session.saveTo(HttpServletResponse) which will add the cookie to the response. This works but some of our JSPs can be pretty complicated so I'd rather have the Session "auto-save" on every put in case I forget to call Session.saveTo().

To clarify, this is effectively what I'm doing:

Cookie cookie = new Cookie("custom-session", "initial");
response.addCookie(cookie); // Set-Cookie header has 'custom-session=initial'

cookie.setValue("new value"); // does not change Set-Cookie header
response.addCookie(cookie); // re-adding the same cookie, does not work either

After all of that, my browser creates a cookie where custom-session is "inital", not the last value that I set.

A: 

setMaxAge

mcookie.setMaxAge(0);  // to delete the cookie

Example,

<%
 String cmd=request.getParameter("cmd");
 String t1=request.getParameter("t1");

 if(cmd!=null){
  if(cmd.equals("Set")){
    Cookie c=new Cookie("no",t1);
    c.setMaxAge(10);  // 10 seconds
    response.addCookie(c);
    }
  else
  if(cmd.equals("Remove")){
     Cookie c1=new Cookie("no","");
     c1.setMaxAge(0);
     response.addCookie(c1);   
   }
 }
%>
<form method="post" action="sample1.jsp">
  <input type="text" name="t1"/>
  <input type="submit" name="cmd" value="Set"/>
  <input type="submit" name="cmd" value="Remove"/>
</form>
<A href="next.jsp">Next</a>

next.jsp - to list cookies

<%
  Cookie []c=request.getCookies();
  if(c!=null) {
    for(int i=0;i<c.length;i++){
      out.println("<br/>" + c[i].getName() + " " + c[i].getValue());
     }
  }
%>
adatapost
I think this will tell the browser to delete the cookie. Remember, in my case, I'm trying to modify the cookie multiple times for one request; the browser isn't involved yet. Now, if there was some way to get Tomcat to delete the cookie from the response...
Outlaw Programmer
Is it possible to create a cookie without so called **browser**? Please use server-side state - HttpSession.
adatapost
I'm explicitly trying to avoid HttpSession. We are reworking the code so that it is scalable to multiple servers and we don't want to mess with session clustering.
Outlaw Programmer
+1  A: 

It turns out to be a bug/design feature in Tomcat 6. Our old web server, JRun 3.1, did not create the Set-Cookie response headers until the response was commited. This meant you could modify the cookies all you wanted any time before that. However, looking at the source code, Tomcat creates the Set-Cookie header as soon as you add the cookie to the response. The Tomcat Response object keeps handles to the Cookie objects but does nothing with them.

With Tomcat, as soon as you add a Cookie to the response, there is no way to change it.

Outlaw Programmer
+1  A: 

Your custom Session should hold the cookie internally and only pass it to the response right before it's returned to Tomcat.

martin
Yep, this is the solution I'm going with for now. In the long run, I think a better solution might be sticking with the HttpSession and configuring Tomcat's session clustering so that our app can scale to multiple servers.
Outlaw Programmer