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 }