分享

tomcat对sessionId的处理分析

 Tom.Lin 2012-07-30

tomcat 7对sessionId的处理:

首先解析request请求中的sessionID:

从AjpProcessor.java的process(SocketWrapper<Socket> socket)调用CoyoteAdapter.process里面有的postParseRequest(org.apache.coyote.Request req, Request request,org.apache.coyote.Response res,

  Response response) 就有解析获取sessionid的过程

 

 

Java代码  收藏代码
  1.  // Now we have the context, we can parse the session ID from the URL  
  2.            // (if any). Need to do this before we redirect in case we need to  
  3.            // include the session id in the redirect  
  4.            String sessionID = null;  
  5.            if (request.getServletContext().getEffectiveSessionTrackingModes()  
  6.                    .contains(SessionTrackingMode.URL)) {  
  7.   
  8.                // Get the session ID if there was one  
  9.                sessionID = request.getPathParameter(  
  10.                        SessionConfig.getSessionUriParamName(  
  11.                                request.getContext()));  
  12.                if (sessionID != null) {  
  13.                    request.setRequestedSessionId(sessionID);  
  14.                    request.setRequestedSessionURL(true);  
  15.                }  
  16.            }  
  17.   
  18.            // Look for session ID in cookies and SSL session  
  19.            parseSessionCookiesId(req, request);  
  20.            parseSessionSslId(request);  
  21.   
  22. /** 
  23.     * Look for SSL session ID if required. Only look for SSL Session ID if it 
  24.     * is the only tracking method enabled. 
  25.     */  
  26.    protected void parseSessionSslId(Request request) {  
  27.        if (request.getRequestedSessionId() == null &&  
  28.                SSL_ONLY.equals(request.getServletContext()  
  29.                        .getEffectiveSessionTrackingModes()) &&  
  30.                        request.connector.secure) {  
  31.            // TODO Is there a better way to map SSL sessions to our sesison ID?  
  32.            // TODO The request.getAttribute() will cause a number of other SSL  
  33.            //      attribute to be populated. Is this a performance concern?  
  34.            request.setRequestedSessionId(  
  35.                    request.getAttribute(SSLSupport.SESSION_ID_KEY).toString());  
  36.            request.setRequestedSessionSSL(true);  
  37.        }  
  38.    }  
  39.   
  40.   
  41.    /** 
  42.     * Parse session id in URL. 
  43.     */  
  44.    protected void parseSessionCookiesId(org.apache.coyote.Request req, Request request) {  
  45.   
  46.        // If session tracking via cookies has been disabled for the current  
  47.        // context, don't go looking for a session ID in a cookie as a cookie  
  48.        // from a parent context with a session ID may be present which would  
  49.        // overwrite the valid session ID encoded in the URL  
  50.        Context context = (Context) request.getMappingData().context;  
  51.        if (context != null && !context.getServletContext()  
  52.                .getEffectiveSessionTrackingModes().contains(  
  53.                        SessionTrackingMode.COOKIE)) {  
  54.            return;  
  55.        }  
  56.   
  57.        // Parse session id from cookies  
  58.        Cookies serverCookies = req.getCookies();  
  59.        int count = serverCookies.getCookieCount();  
  60.        if (count <= 0) {  
  61.            return;  
  62.        }  
  63.   
  64.        String sessionCookieName = SessionConfig.getSessionCookieName(context);  
  65.   
  66.        for (int i = 0; i < count; i++) {  
  67.            ServerCookie scookie = serverCookies.getCookie(i);  
  68.            if (scookie.getName().equals(sessionCookieName)) {  
  69.                // Override anything requested in the URL  
  70.                if (!request.isRequestedSessionIdFromCookie()) {  
  71.                    // Accept only the first session id cookie  
  72.                    convertMB(scookie.getValue());  
  73.                    request.setRequestedSessionId  
  74.                        (scookie.getValue().toString());  
  75.                    request.setRequestedSessionCookie(true);  
  76.                    request.setRequestedSessionURL(false);  
  77.                    if (log.isDebugEnabled()) {  
  78.                        log.debug(" Requested cookie session id is " +  
  79.                            request.getRequestedSessionId());  
  80.                    }  
  81.                } else {  
  82.                    if (!request.isRequestedSessionIdValid()) {  
  83.                        // Replace the session id until one is valid  
  84.                        convertMB(scookie.getValue());  
  85.                        request.setRequestedSessionId  
  86.                            (scookie.getValue().toString());  
  87.                    }  
  88.                }  
  89.            }  
  90.        }  
  91.   
  92.    }  

 

 

如果没有sessionId,则在request.getSession()的时候需要进行处理

 

 

Java代码  收藏代码
  1. public class Request  
  2.     implements HttpServletRequest {  
  3.   
  4. ......  
  5.     /** 
  6.      * Return the session associated with this Request, creating one 
  7.      * if necessary. 
  8.      */  
  9.     @Override  
  10.     public HttpSession getSession() {  
  11.         Session session = doGetSession(true);  
  12.         if (session == null) {  
  13.             return null;  
  14.         }  
  15.   
  16.         return session.getSession();  
  17.     }  
  18.   
  19.   
  20.     /** 
  21.      * Return the session associated with this Request, creating one 
  22.      * if necessary and requested. 
  23.      * 
  24.      * @param create Create a new session if one does not exist 
  25.      */  
  26.     @Override  
  27.     public HttpSession getSession(boolean create) {  
  28.         Session session = doGetSession(create);  
  29.         if (session == null) {  
  30.             return null;  
  31.         }  
  32.   
  33.         return session.getSession();  
  34.     }  
  35.   
  36.   // ------------------------------------------------------ Protected Methods  
  37.   
  38.   
  39.     protected Session doGetSession(boolean create) {  
  40.   
  41.         // There cannot be a session if no context has been assigned yet  
  42.         if (context == null) {  
  43.             return (null);  
  44.         }  
  45.   
  46.         // Return the current session if it exists and is valid  
  47.         if ((session != null) && !session.isValid()) {  
  48.             session = null;  
  49.         }  
  50.         if (session != null) {  
  51.             return (session);  
  52.         }  
  53.   
  54.         // Return the requested session if it exists and is valid  
  55.         Manager manager = null;  
  56.         if (context != null) {  
  57.             manager = context.getManager();  
  58.         }  
  59.         if (manager == null)  
  60.          {  
  61.             return (null);      // Sessions are not supported  
  62.         }  
  63.         if (requestedSessionId != null) {  
  64.             try {  
  65.                 session = manager.findSession(requestedSessionId);  
  66.             } catch (IOException e) {  
  67.                 session = null;  
  68.             }  
  69.             if ((session != null) && !session.isValid()) {  
  70.                 session = null;  
  71.             }  
  72.             if (session != null) {  
  73.                 session.access();  
  74.                 return (session);  
  75.             }  
  76.         }  
  77.   
  78.         // Create a new session if requested and the response is not committed  
  79.         if (!create) {  
  80.             return (null);  
  81.         }  
  82.         if ((context != null) && (response != null) &&  
  83.             context.getServletContext().getEffectiveSessionTrackingModes().  
  84.                     contains(SessionTrackingMode.COOKIE) &&  
  85.             response.getResponse().isCommitted()) {  
  86.             throw new IllegalStateException  
  87.               (sm.getString("coyoteRequest.sessionCreateCommitted"));  
  88.         }  
  89.   
  90.         // Attempt to reuse session id if one was submitted in a cookie  
  91.         // Do not reuse the session id if it is from a URL, to prevent possible  
  92.         // phishing attacks  
  93.         // Use the SSL session ID if one is present.  
  94.         if (("/".equals(context.getSessionCookiePath())  
  95.                 && isRequestedSessionIdFromCookie()) || requestedSessionSSL ) {  
  96.             session = manager.createSession(getRequestedSessionId());  
  97.         } else {  
  98.             session = manager.createSession(null);  
  99.         }  
  100.   
  101.         // Creating a new session cookie based on that session  
  102.         if ((session != null) && (getContext() != null)  
  103.                && getContext().getServletContext().  
  104.                        getEffectiveSessionTrackingModes().contains(  
  105.                                SessionTrackingMode.COOKIE)) {  
  106.             Cookie cookie =  
  107.                 ApplicationSessionCookieConfig.createSessionCookie(  
  108.                         context, session.getIdInternal(), isSecure());  
  109.   
  110.             response.addSessionCookieInternal(cookie);  
  111.         }  
  112.   
  113.         if (session == null) {  
  114.             return null;  
  115.         }  
  116.   
  117.         session.access();  
  118.         return session;  
  119.     }  
  120.  ......  
  121. ......  

 

 上面会通过manager.createSession创建session,如果request请求带了sessionId,则传入该参数

,没有的话则会创建一个,并且会把sessionId放入response的cookie中

manager对应ManagerBase.java类,里面生成session的过程如下:

 

Java代码  收藏代码
  1. /** 
  2.  * Construct and return a new session object, based on the default 
  3.  * settings specified by this Manager's properties.  The session 
  4.  * id specified will be used as the session id.   
  5.  * If a new session cannot be created for any reason, return  
  6.  * <code>null</code>. 
  7.  *  
  8.  * @param sessionId The session id which should be used to create the 
  9.  *  new session; if <code>null</code>, a new session id will be 
  10.  *  generated 
  11.  * @exception IllegalStateException if a new session cannot be 
  12.  *  instantiated for any reason 
  13.  */  
  14. @Override  
  15. public Session createSession(String sessionId) {  
  16.       
  17.     if ((maxActiveSessions >= 0) &&  
  18.             (getActiveSessions() >= maxActiveSessions)) {  
  19.         rejectedSessions++;  
  20.         throw new IllegalStateException(  
  21.                 sm.getString("managerBase.createSession.ise"));  
  22.     }  
  23.       
  24.     // Recycle or create a Session instance  
  25.     Session session = createEmptySession();  
  26.   
  27.     // Initialize the properties of the new session and return it  
  28.     session.setNew(true);  
  29.     session.setValid(true);  
  30.     session.setCreationTime(System.currentTimeMillis());  
  31.     session.setMaxInactiveInterval(this.maxInactiveInterval);  
  32.     String id = sessionId;  
  33.     if (id == null) {  
  34.         id = generateSessionId();  
  35.     }  
  36.     session.setId(id);  
  37.     sessionCounter++;  
  38.   
  39.     SessionTiming timing = new SessionTiming(session.getCreationTime(), 0);  
  40.     synchronized (sessionCreationTiming) {  
  41.         sessionCreationTiming.add(timing);  
  42.         sessionCreationTiming.poll();  
  43.     }  
  44.     return (session);  
  45.   
  46. }  
  47. /** 
  48.  * Generate and return a new session identifier. 
  49.  */  
  50. protected String generateSessionId() {  
  51.   
  52.     String result = null;  
  53.   
  54.     do {  
  55.         if (result != null) {  
  56.             // Not thread-safe but if one of multiple increments is lost  
  57.             // that is not a big deal since the fact that there was any  
  58.             // duplicate is a much bigger issue.  
  59.             duplicates++;  
  60.         }  
  61.   
  62.         result = sessionIdGenerator.generateSessionId();  
  63.           
  64.     } while (sessions.containsKey(result));  
  65.       
  66.     return result;  
  67. }  
  68. ..  
 

 

sesseionIdGenerator生成sessionId的算法如下:

Java代码  收藏代码
  1. /** 
  2.    * Generate and return a new session identifier. 
  3.    */  
  4.   public String generateSessionId() {  
  5.   
  6.       byte random[] = new byte[16];  
  7.   
  8.       // Render the result as a String of hexadecimal digits  
  9.       StringBuilder buffer = new StringBuilder();  
  10.   
  11.       int resultLenBytes = 0;  
  12.   
  13.       while (resultLenBytes < sessionIdLength) {  
  14.           getRandomBytes(random);  
  15.           for (int j = 0;  
  16.           j < random.length && resultLenBytes < sessionIdLength;  
  17.           j++) {  
  18.               byte b1 = (byte) ((random[j] & 0xf0) >> 4);  
  19.               byte b2 = (byte) (random[j] & 0x0f);  
  20.               if (b1 < 10)  
  21.                   buffer.append((char) ('0' + b1));  
  22.               else  
  23.                   buffer.append((char) ('A' + (b1 - 10)));  
  24.               if (b2 < 10)  
  25.                   buffer.append((char) ('0' + b2));  
  26.               else  
  27.                   buffer.append((char) ('A' + (b2 - 10)));  
  28.               resultLenBytes++;  
  29.           }  
  30.       }  
  31.   
  32.       if (jvmRoute != null && jvmRoute.length() > 0) {  
  33.           buffer.append('.').append(jvmRoute);  
  34.       }  
  35.   
  36.       return buffer.toString();  
  37.   }  

 

其中jvmRoute是为了防止tomcat集群导致的sessionId冲突,getRandomBytes(random);会通过随机算法生成16byte的字节数组,最终sessionId默认是生成16byte的字符串。

 

上面说到会把生成的sessionId存入response的cookie域中

Java代码  收藏代码
  1. Cookie cookie =  
  2.                 ApplicationSessionCookieConfig.createSessionCookie(  
  3.                         context, session.getIdInternal(), isSecure());  
  4.   
  5.             response.addSessionCookieInternal(cookie);  

 

处理过程如下:

 

Java代码  收藏代码
  1. /** 
  2.    * Special method for adding a session cookie as we should be overriding 
  3.    * any previous 
  4.    * @param cookie 
  5.    */  
  6.   public void addSessionCookieInternal(final Cookie cookie) {  
  7.       if (isCommitted()) {  
  8.           return;  
  9.       }  
  10.   
  11.       String name = cookie.getName();  
  12.       final String headername = "Set-Cookie";  
  13.       final String startsWith = name + "=";  
  14.       final StringBuffer sb = generateCookieString(cookie);  
  15.       boolean set = false;  
  16.       MimeHeaders headers = coyoteResponse.getMimeHeaders();  
  17.       int n = headers.size();  
  18.       for (int i = 0; i < n; i++) {  
  19.           if (headers.getName(i).toString().equals(headername)) {  
  20.               if (headers.getValue(i).toString().startsWith(startsWith)) {  
  21.                   headers.getValue(i).setString(sb.toString());  
  22.                   set = true;  
  23.               }  
  24.           }  
  25.       }  
  26.       if (!set) {  
  27.           addHeader(headername, sb.toString());  
  28.       }  
  29.   
  30.   
  31.   }  

 

如果header已经有这个sessionId的cookie,则更新,否则设置到header中。

 

 

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多