Skip to content

Commit 1dea38c

Browse files
committed
Lock reads and writes to session map
1 parent 737c5ac commit 1dea38c

File tree

1 file changed

+31
-14
lines changed

1 file changed

+31
-14
lines changed

GoogleUtilities/Network/GULNetworkURLSession.m

Lines changed: 31 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ - (NSString *)sessionIDFromAsyncPOSTRequest:(NSURLRequest *)request
158158
}
159159

160160
// Save the session into memory.
161-
[self setSessionInFetcherMap:self forSessionID:_sessionID];
161+
[[self class] setSessionInFetcherMap:self forSessionID:_sessionID];
162162

163163
_request = [request copy];
164164

@@ -200,7 +200,7 @@ - (NSString *)sessionIDFromAsyncGETRequest:(NSURLRequest *)request
200200
}
201201

202202
// Save the session into memory.
203-
[self setSessionInFetcherMap:self forSessionID:_sessionID];
203+
[[self class] setSessionInFetcherMap:self forSessionID:_sessionID];
204204

205205
_request = [request copy];
206206

@@ -291,7 +291,7 @@ - (void)URLSession:(NSURLSession *)session
291291
// Explicitly remove the session so it won't be reused. The weak map table should
292292
// remove the session on deallocation, but dealloc may not happen immediately after
293293
// calling `finishTasksAndInvalidate`.
294-
[self setSessionInFetcherMap:nil forSessionID:sessionID];
294+
[[self class] setSessionInFetcherMap:nil forSessionID:sessionID];
295295
}
296296
}
297297

@@ -540,18 +540,19 @@ - (void)removeTempItemAtURL:(NSURL *)fileURL {
540540

541541
/// Gets the fetcher with the session ID.
542542
+ (instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier {
543-
NSMapTable<NSString *, GULNetworkURLSession *> *sessionIdentifierToFetcherMap =
544-
[self sessionIDToFetcherMap];
545-
GULNetworkURLSession *session = [sessionIdentifierToFetcherMap objectForKey:sessionIdentifier];
543+
GULNetworkURLSession *session = [self sessionFromFetcherMapForSessionID:sessionIdentifier];
546544
if (!session && [sessionIdentifier hasPrefix:kGULNetworkBackgroundSessionConfigIDPrefix]) {
547545
session = [[GULNetworkURLSession alloc] initWithNetworkLoggerDelegate:nil];
548546
[session setSessionID:sessionIdentifier];
549-
[sessionIdentifierToFetcherMap setObject:session forKey:sessionIdentifier];
547+
[self setSessionInFetcherMap:session forSessionID:sessionIdentifier];
550548
}
551549
return session;
552550
}
553551

554552
/// Returns a map of the fetcher by session ID. Creates a map if it is not created.
553+
/// When reading and writing from/to the session map, don't use this method directly.
554+
/// To avoid thread safety issues, use one of the helper methods at the bottom of the
555+
/// file: setSessionInFetcherMap:forSessionID:, sessionFromFetcherMapForSessionID:
555556
+ (NSMapTable<NSString *, GULNetworkURLSession *> *)sessionIDToFetcherMap {
556557
static NSMapTable *sessionIDToFetcherMap;
557558

@@ -562,6 +563,16 @@ + (instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier {
562563
return sessionIDToFetcherMap;
563564
}
564565

566+
+ (NSLock *)sessionIDToFetcherMapReadWriteLock {
567+
static NSLock *lock;
568+
569+
static dispatch_once_t onceToken;
570+
dispatch_once(&onceToken, ^{
571+
lock = [[NSLock alloc] init];
572+
});
573+
return lock;
574+
}
575+
565576
/// Returns a map of system provided completion handler by session ID. Creates a map if it is not
566577
/// created.
567578
+ (GULMutableDictionary *)sessionIDToSystemCompletionHandlerDictionary {
@@ -661,26 +672,32 @@ - (void)URLSession:(NSURLSession *)session
661672

662673
#pragma mark - Helper Methods
663674

664-
- (void)setSessionInFetcherMap:(GULNetworkURLSession *)session forSessionID:(NSString *)sessionID {
665-
GULNetworkURLSession *existingSession = [self sessionFromFetcherMapForSessionID:sessionID];
675+
+ (void)setSessionInFetcherMap:(GULNetworkURLSession *)session forSessionID:(NSString *)sessionID {
676+
[[self sessionIDToFetcherMapReadWriteLock] lock];
677+
GULNetworkURLSession *existingSession =
678+
[[[self class] sessionIDToFetcherMap] objectForKey:sessionID];
666679
if (existingSession) {
667680
// Invalidating doesn't seem like the right thing to do here since it may cancel an active
668681
// background transfer if the background session is handling multiple requests. The old
669682
// session will be dropped from the map table, but still complete its request.
670683
NSString *message = [NSString stringWithFormat:@"Discarding session: %@", existingSession];
671-
[_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelInfo
672-
messageCode:kGULNetworkMessageCodeURLSession019
673-
message:message];
684+
[existingSession->_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelInfo
685+
messageCode:kGULNetworkMessageCodeURLSession019
686+
message:message];
674687
}
675688
if (session) {
676689
[[[self class] sessionIDToFetcherMap] setObject:session forKey:sessionID];
677690
} else {
678691
[[[self class] sessionIDToFetcherMap] removeObjectForKey:sessionID];
679692
}
693+
[[self sessionIDToFetcherMapReadWriteLock] unlock];
680694
}
681695

682-
- (nullable GULNetworkURLSession *)sessionFromFetcherMapForSessionID:(NSString *)sessionID {
683-
return [[[self class] sessionIDToFetcherMap] objectForKey:sessionID];
696+
+ (nullable GULNetworkURLSession *)sessionFromFetcherMapForSessionID:(NSString *)sessionID {
697+
[[self sessionIDToFetcherMapReadWriteLock] lock];
698+
GULNetworkURLSession *session = [[[self class] sessionIDToFetcherMap] objectForKey:sessionID];
699+
[[self sessionIDToFetcherMapReadWriteLock] unlock];
700+
return session;
684701
}
685702

686703
- (void)callCompletionHandler:(GULNetworkURLSessionCompletionHandler)handler

0 commit comments

Comments
 (0)