Authored by DreamPiggy

Use the correct way to specify cancel if the response status code is invalid.

@@ -182,7 +182,7 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary; @@ -182,7 +182,7 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
182 [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStartNotification object:weakSelf]; 182 [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStartNotification object:weakSelf];
183 }); 183 });
184 } else { 184 } else {
185 - [self callCompletionBlocksWithError:[NSError errorWithDomain:NSURLErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Connection can't be initialized"}]]; 185 + [self callCompletionBlocksWithError:[NSError errorWithDomain:NSURLErrorDomain code:0 userInfo:@{NSLocalizedDescriptionKey : @"Task can't be initialized"}]];
186 } 186 }
187 187
188 #if SD_UIKIT 188 #if SD_UIKIT
@@ -215,7 +215,7 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary; @@ -215,7 +215,7 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
215 [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:weakSelf]; 215 [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:weakSelf];
216 }); 216 });
217 217
218 - // As we cancelled the connection, its callback won't be called and thus won't 218 + // As we cancelled the task, its callback won't be called and thus won't
219 // maintain the isFinished and isExecuting flags. 219 // maintain the isFinished and isExecuting flags.
220 if (self.isExecuting) self.executing = NO; 220 if (self.isExecuting) self.executing = NO;
221 if (!self.isFinished) self.finished = YES; 221 if (!self.isFinished) self.finished = YES;
@@ -278,48 +278,36 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary; @@ -278,48 +278,36 @@ typedef NSMutableDictionary<NSString *, id> SDCallbacksDictionary;
278 dataTask:(NSURLSessionDataTask *)dataTask 278 dataTask:(NSURLSessionDataTask *)dataTask
279 didReceiveResponse:(NSURLResponse *)response 279 didReceiveResponse:(NSURLResponse *)response
280 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler { 280 completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler {
281 -  
282 - //'304 Not Modified' is an exceptional one  
283 - if (![response respondsToSelector:@selector(statusCode)] || (((NSHTTPURLResponse *)response).statusCode < 400 && ((NSHTTPURLResponse *)response).statusCode != 304)) { 281 + NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow;
284 NSInteger expected = (NSInteger)response.expectedContentLength; 282 NSInteger expected = (NSInteger)response.expectedContentLength;
285 expected = expected > 0 ? expected : 0; 283 expected = expected > 0 ? expected : 0;
286 self.expectedSize = expected; 284 self.expectedSize = expected;
  285 + self.response = response;
  286 +
  287 + //'304 Not Modified' is an exceptional one. It should be treated as cancelled.
  288 + if (![response respondsToSelector:@selector(statusCode)] || (((NSHTTPURLResponse *)response).statusCode < 400 && ((NSHTTPURLResponse *)response).statusCode != 304)) {
287 for (SDWebImageDownloaderProgressBlock progressBlock in [self callbacksForKey:kProgressCallbackKey]) { 289 for (SDWebImageDownloaderProgressBlock progressBlock in [self callbacksForKey:kProgressCallbackKey]) {
288 progressBlock(0, expected, self.request.URL); 290 progressBlock(0, expected, self.request.URL);
289 } 291 }
290 -  
291 - self.imageData = [[NSMutableData alloc] initWithCapacity:expected];  
292 - self.response = response;  
293 - __weak typeof(self) weakSelf = self;  
294 - dispatch_async(dispatch_get_main_queue(), ^{  
295 - [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadReceiveResponseNotification object:weakSelf];  
296 - });  
297 } else { 292 } else {
298 - NSUInteger code = ((NSHTTPURLResponse *)response).statusCode;  
299 -  
300 - //This is the case when server returns '304 Not Modified'. It means that remote image is not changed.  
301 - //In case of 304 we need just cancel the operation and return cached image from the cache.  
302 - if (code == 304) {  
303 - [self cancelInternal];  
304 - } else {  
305 - [self.dataTask cancel]; 293 + // Status code invalid and marked as cancelled. Do not call `[self.dataTask cancel]` which may mass up URLSession life cycle
  294 + disposition = NSURLSessionResponseCancel;
306 } 295 }
  296 +
307 __weak typeof(self) weakSelf = self; 297 __weak typeof(self) weakSelf = self;
308 dispatch_async(dispatch_get_main_queue(), ^{ 298 dispatch_async(dispatch_get_main_queue(), ^{
309 - [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadStopNotification object:weakSelf]; 299 + [[NSNotificationCenter defaultCenter] postNotificationName:SDWebImageDownloadReceiveResponseNotification object:weakSelf];
310 }); 300 });
311 301
312 - [self callCompletionBlocksWithError:[NSError errorWithDomain:NSURLErrorDomain code:((NSHTTPURLResponse *)response).statusCode userInfo:nil]];  
313 -  
314 - [self done];  
315 - }  
316 -  
317 if (completionHandler) { 302 if (completionHandler) {
318 - completionHandler(NSURLSessionResponseAllow); 303 + completionHandler(disposition);
319 } 304 }
320 } 305 }
321 306
322 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data { 307 - (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data {
  308 + if (!self.imageData) {
  309 + self.imageData = [[NSMutableData alloc] initWithCapacity:self.expectedSize];
  310 + }
323 [self.imageData appendData:data]; 311 [self.imageData appendData:data];
324 312
325 if ((self.options & SDWebImageDownloaderProgressiveDownload) && self.expectedSize > 0) { 313 if ((self.options & SDWebImageDownloaderProgressiveDownload) && self.expectedSize > 0) {