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 ;
@@ -166,47 +169,27 @@ public Session createSession(final HttpServerExchange serverExchange, final Sess
166
169
}
167
170
168
171
String sessionID = config .findSessionId (serverExchange );
169
- boolean idRequested = false ;
170
- if (sessionID == null ) {
171
- sessionID = sessionIdGenerator .createSessionId ();
172
+ if (sessionID != null ) {
173
+ if (!saveSessionID (sessionID ))
174
+ throw UndertowMessages .MESSAGES .sessionWithIdAlreadyExists (sessionID );
175
+ // else: succeeded to use requested session id
172
176
} else {
173
- idRequested = true ;
174
- }
175
- SessionImpl session ;
176
- synchronized (this .sessions ) {
177
- if (this .sessions .containsKey (sessionID )) {
178
- if (idRequested ) {
179
- throw UndertowMessages .MESSAGES .sessionWithIdAlreadyExists (sessionID );
180
- } else {
181
- int count = 0 ;
182
- sessionID = null ;
183
- while (sessionID == null ) {
184
- sessionID = sessionIdGenerator .createSessionId ();
185
- if (sessions .containsKey (sessionID )) {
186
- sessionID = null ;
187
- }
188
- if (count ++ == 100 ) {
189
- //this should 'never' happen
190
- //but we guard against pathalogical session id generators to prevent an infinite loop
191
- throw UndertowMessages .MESSAGES .couldNotGenerateUniqueSessionId ();
192
- }
193
- }
194
- }
195
- }
196
- Object evictionToken ;
197
- if (evictionQueue != null ) {
198
- evictionToken = evictionQueue .offerLastAndReturnToken (sessionID );
199
- } else {
200
- evictionToken = null ;
201
- }
202
- session = new SessionImpl (this , sessionID , config , serverExchange .getIoThread (), serverExchange .getConnection ().getWorker (), evictionToken , defaultSessionTimeout );
203
- sessions .put (sessionID , session );
204
- config .setSessionId (serverExchange , session .getId ());
205
- serverExchange .putAttachment (NEW_SESSION , session );
177
+ sessionID = createAndSaveNewID ();
206
178
}
207
- session .bumpTimeout ();
179
+ Object evictionToken ;
180
+ if (evictionQueue != null ) {
181
+ evictionToken = evictionQueue .offerLastAndReturnToken (sessionID );
182
+ } else {
183
+ evictionToken = null ;
184
+ }
185
+ final SessionImpl session = new SessionImpl (this , sessionID , config , serverExchange .getIoThread (), serverExchange .getConnection ().getWorker (), evictionToken , defaultSessionTimeout );
186
+
208
187
UndertowLogger .SESSION_LOGGER .debugf ("Created session with id %s for exchange %s" , sessionID , serverExchange );
188
+ saveSession (sessionID , session );
189
+ config .setSessionId (serverExchange , session .getId ());
190
+ session .bumpTimeout ();
209
191
sessionListeners .sessionCreated (session , serverExchange );
192
+ serverExchange .putAttachment (NEW_SESSION , session );
210
193
211
194
if (statisticsEnabled ) {
212
195
createdSessionCount .incrementAndGet ();
@@ -223,6 +206,26 @@ public Session createSession(final HttpServerExchange serverExchange, final Sess
223
206
return session ;
224
207
}
225
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
+
226
229
@ Override
227
230
public Session getSession (final HttpServerExchange serverExchange , final SessionConfig config ) {
228
231
if (serverExchange != null ) {
@@ -633,16 +636,13 @@ public SessionManager getSessionManager() {
633
636
@ Override
634
637
public String changeSessionId (final HttpServerExchange exchange , final SessionConfig config ) {
635
638
final String oldId = sessionId ;
636
- String newId = null ;
637
- synchronized (sessionManager .sessions ) {
638
- newId = sessionManager .sessionIdGenerator .createSessionId ();
639
- this .sessionId = newId ;
640
- if (!invalid ) {
641
- sessionManager .sessions .put (newId , this );
642
- config .setSessionId (exchange , this .getId ());
643
- }
644
- sessionManager .sessions .remove (oldId );
639
+ String newId = sessionManager .createAndSaveNewID ();
640
+ this .sessionId = newId ;
641
+ if (!invalid ) {
642
+ sessionManager .saveSession (newId , this );
643
+ config .setSessionId (exchange , this .getId ());
645
644
}
645
+ sessionManager .sessions .remove (oldId );
646
646
sessionManager .sessionListeners .sessionIdChanged (this , oldId );
647
647
UndertowLogger .SESSION_LOGGER .debugf ("Changing session id %s to %s" , oldId , newId );
648
648
0 commit comments