View Javadoc

1   // ========================================================================
2   // Copyright (c) 2004-2009 Mort Bay Consulting Pty. Ltd.
3   // ------------------------------------------------------------------------
4   // All rights reserved. This program and the accompanying materials
5   // are made available under the terms of the Eclipse Public License v1.0
6   // and Apache License v2.0 which accompanies this distribution.
7   // The Eclipse Public License is available at 
8   // http://www.eclipse.org/legal/epl-v10.html
9   // The Apache License v2.0 is available at
10  // http://www.opensource.org/licenses/apache2.0.php
11  // You may elect to redistribute this code under either of these licenses. 
12  // ========================================================================
13  
14  package org.eclipse.jetty.server.session;
15  
16  import java.security.SecureRandom;
17  import java.util.Random;
18  
19  import javax.servlet.http.HttpServletRequest;
20  
21  import org.eclipse.jetty.server.SessionIdManager;
22  import org.eclipse.jetty.util.component.AbstractLifeCycle;
23  import org.eclipse.jetty.util.log.Log;
24  
25  public abstract class AbstractSessionIdManager extends AbstractLifeCycle implements SessionIdManager
26  {
27      private final static String __NEW_SESSION_ID="org.eclipse.jetty.server.newSessionId";  
28      
29      protected Random _random;
30      protected boolean _weakRandom;
31      protected String _workerName;
32      
33      /* ------------------------------------------------------------ */
34      public AbstractSessionIdManager()
35      {
36      }
37      
38      /* ------------------------------------------------------------ */
39      public AbstractSessionIdManager(Random random)
40      {
41          _random=random;
42      }
43  
44  
45      /* ------------------------------------------------------------ */
46      /**
47       * Get the workname. If set, the workername is dot appended to the session
48       * ID and can be used to assist session affinity in a load balancer.
49       * 
50       * @return String or null
51       */
52      public String getWorkerName()
53      {
54          return _workerName;
55      }
56  
57      /* ------------------------------------------------------------ */
58      /**
59       * Set the workname. If set, the workername is dot appended to the session
60       * ID and can be used to assist session affinity in a load balancer.
61       * 
62       * @param workerName
63       */
64      public void setWorkerName(String workerName)
65      {
66          if (workerName.contains("."))
67              throw new IllegalArgumentException("Name cannot contain '.'");
68          _workerName=workerName;
69      }
70  
71      /* ------------------------------------------------------------ */
72      public Random getRandom()
73      {
74          return _random;
75      }
76  
77      /* ------------------------------------------------------------ */
78      public void setRandom(Random random)
79      {
80          _random=random;
81          _weakRandom=false;
82      }
83      
84      /* ------------------------------------------------------------ */
85      /** 
86       * Create a new session id if necessary.
87       * 
88       * @see org.eclipse.jetty.server.SessionIdManager#newSessionId(javax.servlet.http.HttpServletRequest, long)
89       */
90      public String newSessionId(HttpServletRequest request, long created)
91      {
92          synchronized (this)
93          {
94              if (request!=null)
95              {
96                  // A requested session ID can only be used if it is in use already.
97                  String requested_id=request.getRequestedSessionId();
98                  if (requested_id!=null)
99                  {
100                     String cluster_id=getClusterId(requested_id);
101                     if (idInUse(cluster_id))
102                         return cluster_id;
103                 }
104 
105                 // Else reuse any new session ID already defined for this request.
106                 String new_id=(String)request.getAttribute(__NEW_SESSION_ID);
107                 if (new_id!=null&&idInUse(new_id))
108                     return new_id;
109             }
110             
111             // pick a new unique ID!
112             String id=null;
113             while (id==null||id.length()==0||idInUse(id))
114             {
115                 long r0=_weakRandom
116                 ?(hashCode()^Runtime.getRuntime().freeMemory()^_random.nextInt()^(((long)request.hashCode())<<32))
117                 :_random.nextLong();
118                 if (r0<0)
119                     r0=-r0;
120                 long r1=_weakRandom
121                 ?(hashCode()^Runtime.getRuntime().freeMemory()^_random.nextInt()^(((long)request.hashCode())<<32))
122                 :_random.nextLong();
123                 if (r1<0)
124                     r1=-r1;
125                 id=Long.toString(r0,36)+Long.toString(r1,36);
126                 
127                 //add in the id of the node to ensure unique id across cluster
128                 //NOTE this is different to the node suffix which denotes which node the request was received on
129                 if (_workerName!=null)
130                     id=_workerName + id;
131             }
132 
133             request.setAttribute(__NEW_SESSION_ID,id);
134             return id;
135         }
136     }
137 
138     /* ------------------------------------------------------------ */
139     @Override
140     protected void doStart() throws Exception
141     {
142        initRandom();
143     }
144     
145     /* ------------------------------------------------------------ */
146     @Override
147     protected void doStop() throws Exception
148     {
149     }
150     
151     /* ------------------------------------------------------------ */
152     /**
153      * Set up a random number generator for the sessionids.
154      * 
155      * By preference, use a SecureRandom but allow to be injected.
156      */
157     public void initRandom ()
158     {
159         if (_random==null)
160         {
161             try
162             {
163                 _random=new SecureRandom();
164             }
165             catch (Exception e)
166             {
167                 Log.warn("Could not generate SecureRandom for session-id randomness",e);
168                 _random=new Random();
169                 _weakRandom=true;
170             }
171         }
172         else
173             _random.setSeed(_random.nextLong()^System.currentTimeMillis()^hashCode()^Runtime.getRuntime().freeMemory()); 
174     }
175     
176     
177 }