Skip to content

Commit 3a50f8e

Browse files
committed
Fix leak of url sessions in GoogleUtilities
1 parent b661695 commit 3a50f8e

File tree

2 files changed

+38
-5
lines changed

2 files changed

+38
-5
lines changed

GoogleUtilities/Network/GULNetworkURLSession.m

Lines changed: 37 additions & 5 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:session 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:session 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
@@ -651,6 +660,28 @@ - (void)URLSession:(NSURLSession *)session
651660

652661
#pragma mark - Helper Methods
653662

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

703+
// Always use the request parameters even if the default session configuration is more restrictive.
672704
- (void)populateSessionConfig:(NSURLSessionConfiguration *)sessionConfig
673705
withRequest:(NSURLRequest *)request API_AVAILABLE(ios(7.0)) {
674706
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)