Skip to content

Commit 9d12c9e

Browse files
authored
Merge pull request #1174 from baranowb/UNDERTOW-1869_v2
[UNDERTOW-1869] fix concurrency on session creation
2 parents c6569f4 + 30c0dbb commit 9d12c9e

File tree

1 file changed

+35
-19
lines changed

1 file changed

+35
-19
lines changed

core/src/main/java/io/undertow/server/session/InMemorySessionManager.java

Lines changed: 35 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@
5252
*/
5353
public class InMemorySessionManager implements SessionManager, SessionManagerStatistics {
5454

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+
5558
private final AttachmentKey<SessionImpl> NEW_SESSION = AttachmentKey.create(SessionImpl.class);
5659

5760
private final SessionIdGenerator sessionIdGenerator;
@@ -145,6 +148,9 @@ public Session createSession(final HttpServerExchange serverExchange, final Sess
145148
while (sessions.size() >= maxSize && !evictionQueue.isEmpty()) {
146149

147150
String key = evictionQueue.poll();
151+
if(key == null) {
152+
break;
153+
}
148154
UndertowLogger.REQUEST_LOGGER.debugf("Removing session %s as max size has been hit", key);
149155
SessionImpl toRemove = sessions.get(key);
150156
if (toRemove != null) {
@@ -161,24 +167,14 @@ public Session createSession(final HttpServerExchange serverExchange, final Sess
161167
if (config == null) {
162168
throw UndertowMessages.MESSAGES.couldNotFindSessionCookieConfig();
163169
}
170+
164171
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))
180174
throw UndertowMessages.MESSAGES.sessionWithIdAlreadyExists(sessionID);
181-
}
175+
// else: succeeded to use requested session id
176+
} else {
177+
sessionID = createAndSaveNewID();
182178
}
183179
Object evictionToken;
184180
if (evictionQueue != null) {
@@ -189,7 +185,7 @@ public Session createSession(final HttpServerExchange serverExchange, final Sess
189185
final SessionImpl session = new SessionImpl(this, sessionID, config, serverExchange.getIoThread(), serverExchange.getConnection().getWorker(), evictionToken, defaultSessionTimeout);
190186

191187
UndertowLogger.SESSION_LOGGER.debugf("Created session with id %s for exchange %s", sessionID, serverExchange);
192-
sessions.put(sessionID, session);
188+
saveSession(sessionID, session);
193189
config.setSessionId(serverExchange, session.getId());
194190
session.bumpTimeout();
195191
sessionListeners.sessionCreated(session, serverExchange);
@@ -210,6 +206,26 @@ public Session createSession(final HttpServerExchange serverExchange, final Sess
210206
return session;
211207
}
212208

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+
213229
@Override
214230
public Session getSession(final HttpServerExchange serverExchange, final SessionConfig config) {
215231
if (serverExchange != null) {
@@ -620,10 +636,10 @@ public SessionManager getSessionManager() {
620636
@Override
621637
public String changeSessionId(final HttpServerExchange exchange, final SessionConfig config) {
622638
final String oldId = sessionId;
623-
String newId = sessionManager.sessionIdGenerator.createSessionId();
639+
String newId = sessionManager.createAndSaveNewID();
624640
this.sessionId = newId;
625641
if(!invalid) {
626-
sessionManager.sessions.put(newId, this);
642+
sessionManager.saveSession(newId, this);
627643
config.setSessionId(exchange, this.getId());
628644
}
629645
sessionManager.sessions.remove(oldId);

0 commit comments

Comments
 (0)