costin 00/11/21 16:10:00 Modified: src/share/org/apache/tomcat/modules/session SessionId.java SimpleSessionStore.java src/share/org/apache/tomcat/session ServerSession.java ServerSessionManager.java src/share/org/apache/tomcat/util/threads TimeStamp.java Log: Merged fixes from 3.2 - thanks pfrieden, hans, shai, craig. - fix for "load balancing" - check the session id, multiple cookies ( this will be enhanced as the session code is cleaned up/refactored ) - "no cookies" option Submitted by: [EMAIL PROTECTED], [EMAIL PROTECTED], [EMAIL PROTECTED] Revision Changes Path 1.2 +77 -46 jakarta-tomcat/src/share/org/apache/tomcat/modules/session/SessionId.java Index: SessionId.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/modules/session/SessionId.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- SessionId.java 2000/11/21 00:31:12 1.1 +++ SessionId.java 2000/11/22 00:09:59 1.2 @@ -62,6 +62,8 @@ import org.apache.tomcat.core.*; import org.apache.tomcat.util.*; import org.apache.tomcat.helper.*; +import org.apache.tomcat.session.ServerSessionManager; +import org.apache.tomcat.session.ServerSession; import java.io.*; import java.net.*; import java.util.*; @@ -80,15 +82,20 @@ * * This implementation only handles Cookies and URL rewriting sessions, * please extend or add new interceptors for other methods. - * + * + * You can set this interceptor to not use cookies, but only rewriting. * + * @author [EMAIL PROTECTED] + * @author Shai Fultheim [[EMAIL PROTECTED]] */ public class SessionId extends BaseInterceptor { - + private int manager_note; + // GS, separates the session id from the jvm route static final char SESSIONID_ROUTE_SEP = '.'; ContextManager cm; + boolean noCookies=false; public SessionId() { } @@ -97,6 +104,17 @@ this.cm=cm; } + public void setNoCookies(boolean noCookies) { + this.noCookies = noCookies; + } + + public void engineInit( ContextManager cm ) throws TomcatException { + // set-up a per/container note for StandardManager + // the standard manager is used to verify the session ID. + manager_note = cm.getNoteId( ContextManager.CONTAINER_NOTE, + "tomcat.standardManager"); + } + /** Extract the session id from the request. * SessionInterceptor will have to be called _before_ mapper, * to avoid coding session stuff inside the mapper. @@ -119,8 +137,8 @@ if ((foundAt=uri.indexOf(sig))!=-1){ sessionId=uri.substring(foundAt+sig.length()); - // I hope the optimizer does it's job:-) - sessionId = fixSessionId( request, sessionId ); + // FIX [EMAIL PROTECTED]: reloading + // sessionId = fixSessionId( request, sessionId ); // rewrite URL, do I need to do anything more? request.requestURI().setString(uri.substring(0, foundAt)); @@ -138,9 +156,16 @@ */ public int requestMap(Request request ) { String sessionId = null; + Context ctx=request.getContext(); + if( ctx==null ) { + log( "Configuration error in StandardSessionInterceptor " + + " - no context " + request ); + return 0; + } + int count=request.getCookieCount(); - + // Give priority to cookies. I don't know if that's part // of the spec - XXX for( int i=0; i<count; i++ ) { @@ -148,54 +173,55 @@ if (cookie.getName().equals("JSESSIONID")) { sessionId = cookie.getValue().toString(); - sessionId = fixSessionId( request, sessionId ); - - // XXX what if we have multiple session cookies ? - // right now only the first is used - request.setRequestedSessionId( sessionId ); - request.setSessionIdSource( Request.SESSIONID_FROM_COOKIE); - break; + if (debug > 0) log("Found session id cookie " + + sessionId); + // 3.2 - load balancing fix + // sessionId = fixSessionId( request, sessionId ); + // 3.2 - PF ( [EMAIL PROTECTED] ): check the session id from + // cookies for validity + + ServerSessionManager sM = getManager( ctx ); + ServerSession sess = sM.findSession(sessionId); + if (sess != null) { + request.setRequestedSessionId( sessionId ); + request.setSessionIdSource(Request.SESSIONID_FROM_COOKIE ); + // since we verified this sessionID, we can also set + // it and adjust the session + request.setSession( sess ); + request.setSessionId( sessionId ); + break; + } } } return 0; } - -// private void findSessionCookie( MimeHeaders headers ) { -// int pos=0; -// while( pos>=0 ) { -// pos=headers.findHeader( "Cookie", pos ); -// // no more cookie headers headers -// if( pos<0 ) break; -// MessageBytes cookieValue=getValue( pos ); - +// /** Fix the session id. If the session is not valid return null. +// * It will also clean up the session from load-balancing strings. +// * @return sessionId, or null if not valid +// */ +// private String fixSessionId(Request request, String sessionId){ +// // GS, We piggyback the JVM id on top of the session cookie +// // Separate them ... + +// if( debug>0 ) cm.log(" Orig sessionId " + sessionId ); +// if (null != sessionId) { +// int idex = sessionId.lastIndexOf(SESSIONID_ROUTE_SEP); +// if(idex > 0) { +// sessionId = sessionId.substring(0, idex); +// } // } +// return sessionId; // } - - /** Fix the session id. If the session is not valid return null. - * It will also clean up the session from load-balancing strings. - * @return sessionId, or null if not valid - */ - private String fixSessionId(Request request, String sessionId){ - // GS, We piggyback the JVM id on top of the session cookie - // Separate them ... - - if( debug>0 ) cm.log(" Orig sessionId " + sessionId ); - if (null != sessionId) { - int idex = sessionId.lastIndexOf(SESSIONID_ROUTE_SEP); - if(idex > 0) { - sessionId = sessionId.substring(0, idex); - } - } - return sessionId; - } public int beforeBody( Request rrequest, Response response ) { String reqSessionId = rrequest.getSessionId(); if( debug>0 ) cm.log("Before Body " + reqSessionId ); if( reqSessionId==null) return 0; + if (noCookies) + return 0; // GS, set the path attribute to the cookie. This way @@ -206,13 +232,13 @@ sessionPath = "/"; } - // GS, piggyback the jvm route on the session id. - if(!sessionPath.equals("/")) { - String jvmRoute = rrequest.getJvmRoute(); - if(null != jvmRoute) { - reqSessionId = reqSessionId + SESSIONID_ROUTE_SEP + jvmRoute; - } - } +// // GS, piggyback the jvm route on the session id. +// // if(!sessionPath.equals("/")) { +// String jvmRoute = rrequest.getJvmRoute(); +// if(null != jvmRoute) { +// reqSessionId = reqSessionId + SESSIONID_ROUTE_SEP + jvmRoute; +// } +// // } // we know reqSessionId doesn't need quoting ( we generate it ) StringBuffer buf = new StringBuffer(); @@ -234,6 +260,11 @@ buf.toString()); return 0; + } + + // -------------------- Internal methods -------------------- + private ServerSessionManager getManager( Context ctx ) { + return (ServerSessionManager)ctx.getContainer().getNote(manager_note); } 1.2 +22 -3 jakarta-tomcat/src/share/org/apache/tomcat/modules/session/SimpleSessionStore.java Index: SimpleSessionStore.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/modules/session/SimpleSessionStore.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- SimpleSessionStore.java 2000/11/21 00:31:13 1.1 +++ SimpleSessionStore.java 2000/11/22 00:09:59 1.2 @@ -84,6 +84,9 @@ * session stuff ( cookie, rewrite, etc) * * @author [EMAIL PROTECTED] + * @author [EMAIL PROTECTED] + * @author [EMAIL PROTECTED] + * @author Shai Fultheim [[EMAIL PROTECTED]] */ public final class SimpleSessionStore extends BaseInterceptor { int manager_note; @@ -144,10 +147,24 @@ // context and one for the real context... or old session // cookie. We must check for validity in the current context. ServerSessionManager sM = getManager( ctx ); - ServerSession sess= sM.findSession( sessionId ); - // log("Try to find: " + sessionId ); + ServerSession sess= request.getSession( false ); + + // if not set already, try to find it using the session id + if( sess==null ) + sess=sM.findSession( sessionId ); + + // 3.2 - Hans fix ( use the session id from URL ) - it's + // part of the current code + + // 3.2 - PF ( [EMAIL PROTECTED] ): fix moved to SessionId. + // ( check if the ID is valid before setting it, do that + // for cookies since we can have multiple cookies, some + // from old sessions ) + if(null != sess) { + // touch it sess.getTimeStamp().touch( System.currentTimeMillis() ); + //log("Session found " + sessionId ); // set it only if nobody else did ! if( null == request.getSession( false ) ) { @@ -207,7 +224,9 @@ if( request.getSession( false ) != null ) return 0; // somebody already set the session - ServerSession newS=sM.getNewSession(); + + // Fix from Shai Fultheim: load balancing needs jvmRoute + ServerSession newS=sM.getNewSession(request.getJvmRoute()); request.setSession( newS ); request.setSessionId( newS.getId().toString()); return 0; 1.8 +1 -1 jakarta-tomcat/src/share/org/apache/tomcat/session/ServerSession.java Index: ServerSession.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/session/ServerSession.java,v retrieving revision 1.7 retrieving revision 1.8 diff -u -r1.7 -r1.8 --- ServerSession.java 2000/11/21 00:31:14 1.7 +++ ServerSession.java 2000/11/22 00:09:59 1.8 @@ -75,7 +75,7 @@ * - serializable ( by external components ) * * Components: - * - timestamp ( expire ) + * - timestamp ( expire ) * - id * - name/value repository * 1.13 +5 -2 jakarta-tomcat/src/share/org/apache/tomcat/session/ServerSessionManager.java Index: ServerSessionManager.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/session/ServerSessionManager.java,v retrieving revision 1.12 retrieving revision 1.13 diff -u -r1.12 -r1.13 --- ServerSessionManager.java 2000/11/21 00:31:14 1.12 +++ ServerSessionManager.java 2000/11/22 00:09:59 1.13 @@ -100,7 +100,6 @@ long maxInactiveInterval; protected Reaper reaper; - Random randomSource=null; public ServerSessionManager() { @@ -168,6 +167,10 @@ } public ServerSession getNewSession() { + return getNewSession( null ) ; + } + + public ServerSession getNewSession(String jsIdent) { if ((maxActiveSessions >= 0) && (sessions.size() >= maxActiveSessions)) { loghelper.log( "Too many sessions " + maxActiveSessions ); @@ -184,7 +187,7 @@ // XXX can return MessageBytes !!! - String newId= SessionIdGenerator.generateId(randomSource); + String newId= SessionIdGenerator.getIdentifier(randomSource, jsIdent); // What if the newId belongs to an existing session ? // This shouldn't happen ( maybe we can try again ? ) 1.2 +33 -4 jakarta-tomcat/src/share/org/apache/tomcat/util/threads/TimeStamp.java Index: TimeStamp.java =================================================================== RCS file: /home/cvs/jakarta-tomcat/src/share/org/apache/tomcat/util/threads/TimeStamp.java,v retrieving revision 1.1 retrieving revision 1.2 diff -u -r1.1 -r1.2 --- TimeStamp.java 2000/09/25 06:10:53 1.1 +++ TimeStamp.java 2000/11/22 00:10:00 1.2 @@ -58,6 +58,7 @@ */ package org.apache.tomcat.util.threads; +import org.apache.tomcat.util.MessageBytes; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; @@ -68,10 +69,13 @@ /** - * Marks creation and access times, plus validity. + * Main tool for object expiry. + * Marks creation and access time of an "expirable" object, + * and extra properties like "id", "valid", etc. * * Used for objects that expire - originally Sessions, but - * soon Contexts and Servlets ( scalability issues, large server support ). + * also Contexts, Servlets, cache - or any other object that + * expires. * * @author Costin Manolache */ @@ -82,7 +86,9 @@ private boolean isNew = true; private long maxInactiveInterval = -1; private boolean isValid = false; - + MessageBytes name; + int id=-1; + Object parent; public TimeStamp() { @@ -103,8 +109,29 @@ // -------------------- Property access -------------------- + /** Return the "name" of the timestamp. This can be used + * to associate unique identifier with each timestamped object. + * The name is a MessageBytes - i.e. a modifiable byte[] or char[]. + */ + public MessageBytes getName() { + if( name==null ) name=new MessageBytes();//lazy + return name; + } + + /** Each object can have an unique id, similar with name but + * providing faster access ( array vs. hashtable lookup ) + */ + public int getId() { + return id; + } + + public void setId( int id ) { + this.id=id; + } + /** Returns the owner of this stamp ( the object that is - * time-stamped + * time-stamped ). + * For a */ public void setParent( Object o ) { parent=o; @@ -164,6 +191,8 @@ maxInactiveInterval = -1; isNew = true; isValid = false; + id=-1; + if( name!=null) name.recycle(); } }