Skip to content

Commit 737c5ac

Browse files
committed
Fix leak of url sessions in GoogleUtilities
1 parent b661695 commit 737c5ac

File tree

2 files changed

+41
-7
lines changed

2 files changed

+41
-7
lines changed

GoogleUtilities/Network/GULNetworkURLSession.m

Lines changed: 40 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ @implementation GULNetworkURLSession {
3232
#pragma clang diagnostic ignored "-Wunguarded-availability"
3333
/// The session configuration. NSURLSessionConfiguration' is only available on iOS 7.0 or newer.
3434
NSURLSessionConfiguration *_sessionConfig;
35-
#pragma pop
35+
#pragma clang diagnostic pop
3636

3737
/// The path to the directory where all temporary files are stored before uploading.
3838
NSURL *_networkDirectoryURL;
@@ -158,8 +158,7 @@ - (NSString *)sessionIDFromAsyncPOSTRequest:(NSURLRequest *)request
158158
}
159159

160160
// Save the session into memory.
161-
NSMapTable *sessionIdentifierToFetcherMap = [[self class] sessionIDToFetcherMap];
162-
[sessionIdentifierToFetcherMap setObject:self forKey:_sessionID];
161+
[self setSessionInFetcherMap:self forSessionID:_sessionID];
163162

164163
_request = [request copy];
165164

@@ -201,8 +200,7 @@ - (NSString *)sessionIDFromAsyncGETRequest:(NSURLRequest *)request
201200
}
202201

203202
// Save the session into memory.
204-
NSMapTable *sessionIdentifierToFetcherMap = [[self class] sessionIDToFetcherMap];
205-
[sessionIdentifierToFetcherMap setObject:self forKey:_sessionID];
203+
[self setSessionInFetcherMap:self forSessionID:_sessionID];
206204

207205
_request = [request copy];
208206

@@ -284,6 +282,17 @@ - (void)URLSession:(NSURLSession *)session
284282
// Try to clean up stale files again.
285283
[self maybeRemoveTempFilesAtURL:_networkDirectoryURL
286284
expiringTime:kGULNetworkTempFolderExpireTime];
285+
286+
// Invalidate the session only if it's owned by this class.
287+
NSString *sessionID = session.configuration.identifier;
288+
if ([sessionID hasPrefix:kGULNetworkBackgroundSessionConfigIDPrefix]) {
289+
[session finishTasksAndInvalidate];
290+
291+
// Explicitly remove the session so it won't be reused. The weak map table should
292+
// remove the session on deallocation, but dealloc may not happen immediately after
293+
// calling `finishTasksAndInvalidate`.
294+
[self setSessionInFetcherMap:nil forSessionID:sessionID];
295+
}
287296
}
288297

289298
- (void)URLSession:(NSURLSession *)session
@@ -531,7 +540,8 @@ - (void)removeTempItemAtURL:(NSURL *)fileURL {
531540

532541
/// Gets the fetcher with the session ID.
533542
+ (instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier {
534-
NSMapTable *sessionIdentifierToFetcherMap = [self sessionIDToFetcherMap];
543+
NSMapTable<NSString *, GULNetworkURLSession *> *sessionIdentifierToFetcherMap =
544+
[self sessionIDToFetcherMap];
535545
GULNetworkURLSession *session = [sessionIdentifierToFetcherMap objectForKey:sessionIdentifier];
536546
if (!session && [sessionIdentifier hasPrefix:kGULNetworkBackgroundSessionConfigIDPrefix]) {
537547
session = [[GULNetworkURLSession alloc] initWithNetworkLoggerDelegate:nil];
@@ -542,7 +552,7 @@ + (instancetype)fetcherWithSessionIdentifier:(NSString *)sessionIdentifier {
542552
}
543553

544554
/// Returns a map of the fetcher by session ID. Creates a map if it is not created.
545-
+ (NSMapTable *)sessionIDToFetcherMap {
555+
+ (NSMapTable<NSString *, GULNetworkURLSession *> *)sessionIDToFetcherMap {
546556
static NSMapTable *sessionIDToFetcherMap;
547557

548558
static dispatch_once_t sessionMapOnceToken;
@@ -651,6 +661,28 @@ - (void)URLSession:(NSURLSession *)session
651661

652662
#pragma mark - Helper Methods
653663

664+
- (void)setSessionInFetcherMap:(GULNetworkURLSession *)session forSessionID:(NSString *)sessionID {
665+
GULNetworkURLSession *existingSession = [self sessionFromFetcherMapForSessionID:sessionID];
666+
if (existingSession) {
667+
// Invalidating doesn't seem like the right thing to do here since it may cancel an active
668+
// background transfer if the background session is handling multiple requests. The old
669+
// session will be dropped from the map table, but still complete its request.
670+
NSString *message = [NSString stringWithFormat:@"Discarding session: %@", existingSession];
671+
[_loggerDelegate GULNetwork_logWithLevel:kGULNetworkLogLevelInfo
672+
messageCode:kGULNetworkMessageCodeURLSession019
673+
message:message];
674+
}
675+
if (session) {
676+
[[[self class] sessionIDToFetcherMap] setObject:session forKey:sessionID];
677+
} else {
678+
[[[self class] sessionIDToFetcherMap] removeObjectForKey:sessionID];
679+
}
680+
}
681+
682+
- (nullable GULNetworkURLSession *)sessionFromFetcherMapForSessionID:(NSString *)sessionID {
683+
return [[[self class] sessionIDToFetcherMap] objectForKey:sessionID];
684+
}
685+
654686
- (void)callCompletionHandler:(GULNetworkURLSessionCompletionHandler)handler
655687
withResponse:(NSHTTPURLResponse *)response
656688
data:(NSData *)data
@@ -669,6 +701,7 @@ - (void)callCompletionHandler:(GULNetworkURLSessionCompletionHandler)handler
669701
}
670702
}
671703

704+
// Always use the request parameters even if the default session configuration is more restrictive.
672705
- (void)populateSessionConfig:(NSURLSessionConfiguration *)sessionConfig
673706
withRequest:(NSURLRequest *)request API_AVAILABLE(ios(7.0)) {
674707
sessionConfig.HTTPAdditionalHeaders = request.allHTTPHeaderFields;

GoogleUtilities/Network/Private/GULNetworkMessageCode.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,4 +41,5 @@ typedef NS_ENUM(NSInteger, GULNetworkMessageCode) {
4141
kGULNetworkMessageCodeURLSession016 = 901016, // I-NET901016
4242
kGULNetworkMessageCodeURLSession017 = 901017, // I-NET901017
4343
kGULNetworkMessageCodeURLSession018 = 901018, // I-NET901018
44+
kGULNetworkMessageCodeURLSession019 = 901019, // I-NET901019
4445
};

0 commit comments

Comments
 (0)