]> WPIA git - gigi.git/blob - lib/jetty/org/eclipse/jetty/server/session/AbstractSessionIdManager.java
updating jetty to jetty-9.2.16.v2016040
[gigi.git] / lib / jetty / org / eclipse / jetty / server / session / AbstractSessionIdManager.java
1 //
2 //  ========================================================================
3 //  Copyright (c) 1995-2016 Mort Bay Consulting Pty. Ltd.
4 //  ------------------------------------------------------------------------
5 //  All rights reserved. This program and the accompanying materials
6 //  are made available under the terms of the Eclipse Public License v1.0
7 //  and Apache License v2.0 which accompanies this distribution.
8 //
9 //      The Eclipse Public License is available at
10 //      http://www.eclipse.org/legal/epl-v10.html
11 //
12 //      The Apache License v2.0 is available at
13 //      http://www.opensource.org/licenses/apache2.0.php
14 //
15 //  You may elect to redistribute this code under either of these licenses.
16 //  ========================================================================
17 //
18
19 package org.eclipse.jetty.server.session;
20
21 import java.security.SecureRandom;
22 import java.util.Random;
23
24 import javax.servlet.http.HttpServletRequest;
25
26 import org.eclipse.jetty.server.SessionIdManager;
27 import org.eclipse.jetty.util.component.AbstractLifeCycle;
28 import org.eclipse.jetty.util.log.Log;
29 import org.eclipse.jetty.util.log.Logger;
30
31 public abstract class AbstractSessionIdManager extends AbstractLifeCycle implements SessionIdManager
32 {
33     private static final Logger LOG = Log.getLogger(AbstractSessionIdManager.class);
34
35     private final static String __NEW_SESSION_ID="org.eclipse.jetty.server.newSessionId";
36
37     protected Random _random;
38     protected boolean _weakRandom;
39     protected String _workerName;
40     protected String _workerAttr;
41     protected long _reseed=100000L;
42
43     /* ------------------------------------------------------------ */
44     public AbstractSessionIdManager()
45     {
46     }
47
48     /* ------------------------------------------------------------ */
49     public AbstractSessionIdManager(Random random)
50     {
51         _random=random;
52     }
53
54
55     /* ------------------------------------------------------------ */
56     /**
57      * Get the workname. If set, the workername is dot appended to the session
58      * ID and can be used to assist session affinity in a load balancer.
59      *
60      * @return String or null
61      */
62     @Override
63     public String getWorkerName()
64     {
65         return _workerName;
66     }
67
68     /* ------------------------------------------------------------ */
69     /**
70      * Set the workname. If set, the workername is dot appended to the session
71      * ID and can be used to assist session affinity in a load balancer.
72      * A worker name starting with $ is used as a request attribute name to
73      * lookup the worker name that can be dynamically set by a request
74      * customiser.
75      *
76      * @param workerName
77      */
78     public void setWorkerName(String workerName)
79     {
80         if (isRunning())
81             throw new IllegalStateException(getState());
82         if (workerName.contains("."))
83             throw new IllegalArgumentException("Name cannot contain '.'");
84         _workerName=workerName;
85     }
86
87     /* ------------------------------------------------------------ */
88     public Random getRandom()
89     {
90         return _random;
91     }
92
93     /* ------------------------------------------------------------ */
94     public synchronized void setRandom(Random random)
95     {
96         _random=random;
97         _weakRandom=false;
98     }
99
100     /* ------------------------------------------------------------ */
101     /**
102      * @return the reseed probability
103      */
104     public long getReseed()
105     {
106         return _reseed;
107     }
108
109     /* ------------------------------------------------------------ */
110     /** Set the reseed probability.
111      * @param reseed  If non zero then when a random long modulo the reseed value == 1, the {@link SecureRandom} will be reseeded.
112      */
113     public void setReseed(long reseed)
114     {
115         _reseed = reseed;
116     }
117
118     /* ------------------------------------------------------------ */
119     /**
120      * Create a new session id if necessary.
121      *
122      * @see org.eclipse.jetty.server.SessionIdManager#newSessionId(javax.servlet.http.HttpServletRequest, long)
123      */
124     @Override
125     public String newSessionId(HttpServletRequest request, long created)
126     {
127         synchronized (this)
128         {
129             if (request==null)
130                 return newSessionId(created);
131
132             // A requested session ID can only be used if it is in use already.
133             String requested_id=request.getRequestedSessionId();
134             if (requested_id!=null)
135             {
136                 String cluster_id=getClusterId(requested_id);
137                 if (idInUse(cluster_id))
138                     return cluster_id;
139             }
140
141             // Else reuse any new session ID already defined for this request.
142             String new_id=(String)request.getAttribute(__NEW_SESSION_ID);
143             if (new_id!=null&&idInUse(new_id))
144                 return new_id;
145
146             // pick a new unique ID!
147             String id = newSessionId(request.hashCode());
148
149             request.setAttribute(__NEW_SESSION_ID,id);
150             return id;
151         }
152     }
153
154     /* ------------------------------------------------------------ */
155     public String newSessionId(long seedTerm)
156     {
157         // pick a new unique ID!
158         String id=null;
159         while (id==null||id.length()==0||idInUse(id))
160         {
161             long r0=_weakRandom
162                     ?(hashCode()^Runtime.getRuntime().freeMemory()^_random.nextInt()^((seedTerm)<<32))
163                     :_random.nextLong();
164             if (r0<0)
165                 r0=-r0;
166                     
167             // random chance to reseed
168             if (_reseed>0 && (r0%_reseed)== 1L)
169             {
170                 if (LOG.isDebugEnabled())
171                     LOG.debug("Reseeding {}",this);
172                 if (_random instanceof SecureRandom)
173                 {
174                     SecureRandom secure = (SecureRandom)_random;
175                     secure.setSeed(secure.generateSeed(8));
176                 }
177                 else
178                 {
179                     _random.setSeed(_random.nextLong()^System.currentTimeMillis()^seedTerm^Runtime.getRuntime().freeMemory());
180                 }
181             }
182             
183             long r1=_weakRandom
184                 ?(hashCode()^Runtime.getRuntime().freeMemory()^_random.nextInt()^((seedTerm)<<32))
185                 :_random.nextLong();
186             if (r1<0)
187                 r1=-r1;
188             
189             id=Long.toString(r0,36)+Long.toString(r1,36);
190
191             //add in the id of the node to ensure unique id across cluster
192             //NOTE this is different to the node suffix which denotes which node the request was received on
193             if (_workerName!=null)
194                 id=_workerName + id;
195     
196         }
197         return id;
198     }
199
200
201     /* ------------------------------------------------------------ */
202     @Override
203     public abstract void renewSessionId(String oldClusterId, String oldNodeId, HttpServletRequest request);
204
205     
206     /* ------------------------------------------------------------ */
207     @Override
208     protected void doStart() throws Exception
209     {
210        initRandom();
211        _workerAttr=(_workerName!=null && _workerName.startsWith("$"))?_workerName.substring(1):null;
212     }
213
214     /* ------------------------------------------------------------ */
215     @Override
216     protected void doStop() throws Exception
217     {
218     }
219
220     /* ------------------------------------------------------------ */
221     /**
222      * Set up a random number generator for the sessionids.
223      *
224      * By preference, use a SecureRandom but allow to be injected.
225      */
226     public void initRandom ()
227     {
228         if (_random==null)
229         {
230             try
231             {
232                 _random=new SecureRandom();
233             }
234             catch (Exception e)
235             {
236                 LOG.warn("Could not generate SecureRandom for session-id randomness",e);
237                 _random=new Random();
238                 _weakRandom=true;
239             }
240         }
241         else
242             _random.setSeed(_random.nextLong()^System.currentTimeMillis()^hashCode()^Runtime.getRuntime().freeMemory());
243     }
244
245     /** Get the session ID with any worker ID.
246      *
247      * @param clusterId
248      * @param request
249      * @return sessionId plus any worker ID.
250      */
251     @Override
252     public String getNodeId(String clusterId, HttpServletRequest request)
253     {
254         if (_workerName!=null)
255         {
256             if (_workerAttr==null)
257                 return clusterId+'.'+_workerName;
258
259             String worker=(String)request.getAttribute(_workerAttr);
260             if (worker!=null)
261                 return clusterId+'.'+worker;
262         }
263     
264         return clusterId;
265     }
266
267     /** Get the session ID without any worker ID.
268      *
269      * @param nodeId the node id
270      * @return sessionId without any worker ID.
271      */
272     @Override
273     public String getClusterId(String nodeId)
274     {
275         int dot=nodeId.lastIndexOf('.');
276         return (dot>0)?nodeId.substring(0,dot):nodeId;
277     }
278
279
280 }