You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by Mark Brouwer <ma...@virgil.nl> on 2000/05/15 16:07:15 UTC

Session cookie problem

Hi,

During some final testing of one of our applications we found some
strange behaviour with Tomcat 3.1 final. It looked like there were
multiple sessions created for actually one real session in some
circumstances.

After a lot of cursing and debugging (in that order :-) we were able to
track the problem down to incorrect session cookie behaviour, at least
that's what I think. As the bug database is down I will show the problem
here and the quick hack I made.

In case you start your browser and make a request to your webapp (lets
say testapp) Tomcat will create a session and put a JSESSIONID cookie
with maxAge = -1 in the response, assume this is ...123At . The browser
will use this session cookie for testapp as long as the webserver
doesn't override it or until it is closed, hence maxAge = -1.

If your webapp explicitly invalidates a session (logoff in application
testapp e.g.), or when a session timeout occurs, the session is
destroyed and Tomcat doesn't recognize your session cookie anymore.

In situations where a user doens't close all browser windows (browser
still active) and will make a JSP request to testapp again, the browser
will use the old JSESSIONID ...123At cookie. As Tomcat doesn't recognize
this session it will create a new one ...789At, providing a new session
cookie for the given domain/webapp. Everthing so far so good if you
don't use applets in your webapp, thats were things go wrong.

Assume testapp also consist of some applets (Java plugin) making calls
to JSP pages you want to be part of your session. The applet for some
reason maintains it own cookies and when it makes a request it will use
the JSESSIONID ...123At of the former session. Tomcat doesn't recognize
this cookie and will generate a new session ...456At. Now within one
browser you have 2 sessions to the webapp, ...789At and 456At (for the
applet). Well the result is that your application doesn't work the way
you designed it :-)

I had 2 options: change the behaviour of Tomcat or to advice the user to
kill the browser before using our application again. That latter is hard
to
explain to your customers, therefore it had to be the first one.

After I finally found the code responsible for the session I made a
quick hack that always return a session with an ID the same as the
browser requests for. The change that Tomcat is restarted and the
session ID has already been assigned to somebody else is so small I
don't think it is a problem. At least now the behaviour is the same as
it is in the JSWDK.

Below I will show the quick hack, it is too dirty to commit. I hope the
people doing the big overhaul will change this in a decent way, as a lot
of undocumented stuff is working together so it seems. Well at least I
could solve the problem and that's great.
-- 
Mark Brouwer
Virgil B.V.

Modifications in org.apache.tomcat.session.RequestImpl at the
getSession() method:

	public HttpSession getSession(boolean create) {

	// use the cached value, unless it is invalid
	if( serverSession!=null ) {
		// Detect "invalidity" by trying to access a property
		try {
		serverSession.getCreationTime();
		return (serverSession);
		} catch (IllegalStateException e) {
		// It's invalid, so pretend we never saw it
		serverSession = null;
		reqSessionId = null;
		}
	}

	SessionManager sM=context.getSessionManager();

++	// SOME QUICK HACK CODE
++	// check if there is session id in the request, the request
++	// ID is never set, this is only done once during the start
++	// of a session
++
++	if (reqSessionId == null) {
++
++		Cookie cookies[] = getCookies(); // assert !=null
++
++		for( int i=0; i<cookies.length; i++ ) {
++			if (cookies[i].getName().equals("JSESSIONID")) {
++			 reqSessionId = cookies[i].getValue();
++			 break;
++			}
++		}
++	}

	// if the interceptors found a request id, use it
	if( reqSessionId != null ) {
		// we have a session !
		serverSession=sM.findSession( context, reqSessionId );
		if( serverSession!=null) return serverSession;
	}

	if( ! create )
		return null;

	// no session exists, create flag
	serverSession =sM.createSession( context );

++	// SOME QUICK HACK CODE
++	// set the session id of the newly created session to the one
++	// in the request
++	if (reqSessionId != null) {
++		((StandardSession) serverSession).setId(reqSessionId);
++	}

	reqSessionId = serverSession.getId();

	// XXX XXX will be changed - post-request Interceptors
	// ( to be defined) will set the session id in response,
	// SessionManager is just a repository and doesn't deal with
	// request internals.
	// hardcoded - will change!
	response.setSessionId( reqSessionId );

	return serverSession;
    }

Also had to widen the class visibility of StandardSession to public to
be able to use the setID :-(