52
52
*/
53
53
public class InMemorySessionManager implements SessionManager , SessionManagerStatistics {
54
54
55
+ // place holder for sessions during id creation, it prevents collision of session ids in race condition scenarios where two sessions are being created with the same id
56
+ private static final SessionImpl PLACE_HOLDER_SESSION = new SessionImpl (null , null , null , null , null , null , 0 );
57
+
55
58
private final AttachmentKey <SessionImpl > NEW_SESSION = AttachmentKey .create (SessionImpl .class );
56
59
57
60
private final SessionIdGenerator sessionIdGenerator ;
@@ -145,6 +148,9 @@ public Session createSession(final HttpServerExchange serverExchange, final Sess
145
148
while (sessions .size () >= maxSize && !evictionQueue .isEmpty ()) {
146
149
147
150
String key = evictionQueue .poll ();
151
+ if (key == null ) {
152
+ break ;
153
+ }
148
154
UndertowLogger .REQUEST_LOGGER .debugf ("Removing session %s as max size has been hit" , key );
149
155
SessionImpl toRemove = sessions .get (key );
150
156
if (toRemove != null ) {
@@ -161,24 +167,14 @@ public Session createSession(final HttpServerExchange serverExchange, final Sess
161
167
if (config == null ) {
162
168
throw UndertowMessages .MESSAGES .couldNotFindSessionCookieConfig ();
163
169
}
170
+
164
171
String sessionID = config .findSessionId (serverExchange );
165
- if (sessionID == null ) {
166
- int count = 0 ;
167
- while (sessionID == null ) {
168
- sessionID = sessionIdGenerator .createSessionId ();
169
- if (sessions .containsKey (sessionID )) {
170
- sessionID = null ;
171
- }
172
- if (count ++ == 100 ) {
173
- //this should never happen
174
- //but we guard against pathalogical session id generators to prevent an infinite loop
175
- throw UndertowMessages .MESSAGES .couldNotGenerateUniqueSessionId ();
176
- }
177
- }
178
- } else {
179
- if (sessions .containsKey (sessionID )) {
172
+ if (sessionID != null ) {
173
+ if (!saveSessionID (sessionID ))
180
174
throw UndertowMessages .MESSAGES .sessionWithIdAlreadyExists (sessionID );
181
- }
175
+ // else: succeeded to use requested session id
176
+ } else {
177
+ sessionID = createAndSaveNewID ();
182
178
}
183
179
Object evictionToken ;
184
180
if (evictionQueue != null ) {
@@ -189,7 +185,7 @@ public Session createSession(final HttpServerExchange serverExchange, final Sess
189
185
final SessionImpl session = new SessionImpl (this , sessionID , config , serverExchange .getIoThread (), serverExchange .getConnection ().getWorker (), evictionToken , defaultSessionTimeout );
190
186
191
187
UndertowLogger .SESSION_LOGGER .debugf ("Created session with id %s for exchange %s" , sessionID , serverExchange );
192
- sessions . put (sessionID , session );
188
+ saveSession (sessionID , session );
193
189
config .setSessionId (serverExchange , session .getId ());
194
190
session .bumpTimeout ();
195
191
sessionListeners .sessionCreated (session , serverExchange );
@@ -210,6 +206,26 @@ public Session createSession(final HttpServerExchange serverExchange, final Sess
210
206
return session ;
211
207
}
212
208
209
+ private boolean saveSessionID (String sessionID ) {
210
+ return this .sessions .putIfAbsent (sessionID , PLACE_HOLDER_SESSION ) == null ;
211
+ }
212
+
213
+ private String createAndSaveNewID () {
214
+ for (int i = 0 ; i < 100 ; i ++) {
215
+ final String sessionID = sessionIdGenerator .createSessionId ();
216
+ if (saveSessionID (sessionID ))
217
+ return sessionID ;
218
+ }
219
+ //this should 'never' happen
220
+ //but we guard against pathalogical session id generators to prevent an infinite loop
221
+ throw UndertowMessages .MESSAGES .couldNotGenerateUniqueSessionId ();
222
+ }
223
+
224
+ private void saveSession (String savedID , SessionImpl session ) {
225
+ final SessionImpl placeHolder = sessions .put (savedID , session );
226
+ assert (placeHolder == PLACE_HOLDER_SESSION );
227
+ }
228
+
213
229
@ Override
214
230
public Session getSession (final HttpServerExchange serverExchange , final SessionConfig config ) {
215
231
if (serverExchange != null ) {
@@ -620,10 +636,10 @@ public SessionManager getSessionManager() {
620
636
@ Override
621
637
public String changeSessionId (final HttpServerExchange exchange , final SessionConfig config ) {
622
638
final String oldId = sessionId ;
623
- String newId = sessionManager .sessionIdGenerator . createSessionId ();
639
+ String newId = sessionManager .createAndSaveNewID ();
624
640
this .sessionId = newId ;
625
641
if (!invalid ) {
626
- sessionManager .sessions . put (newId , this );
642
+ sessionManager .saveSession (newId , this );
627
643
config .setSessionId (exchange , this .getId ());
628
644
}
629
645
sessionManager .sessions .remove (oldId );
0 commit comments