TRAVIS_OS_NAME=osx default= <<<<<< ENV .codecov.yml AFNetworking.podspec AFNetworking.xcodeproj/project.pbxproj AFNetworking.xcodeproj/xcshareddata/xcschemes/AFNetworking iOS.xcscheme AFNetworking.xcodeproj/xcshareddata/xcschemes/AFNetworking macOS.xcscheme AFNetworking.xcodeproj/xcshareddata/xcschemes/AFNetworking tvOS.xcscheme AFNetworking.xcodeproj/xcshareddata/xcschemes/AFNetworking watchOS.xcscheme AFNetworking.xcworkspace/contents.xcworkspacedata AFNetworking/AFCompatibilityMacros.h AFNetworking/AFHTTPSessionManager.h AFNetworking/AFHTTPSessionManager.m AFNetworking/AFNetworkReachabilityManager.h AFNetworking/AFNetworkReachabilityManager.m AFNetworking/AFNetworking.h AFNetworking/AFSecurityPolicy.h AFNetworking/AFSecurityPolicy.m AFNetworking/AFURLRequestSerialization.h AFNetworking/AFURLRequestSerialization.m AFNetworking/AFURLResponseSerialization.h AFNetworking/AFURLResponseSerialization.m AFNetworking/AFURLSessionManager.h AFNetworking/AFURLSessionManager.m Example/AFNetworking Example.entitlements Example/AFNetworking Example.xcodeproj/project.pbxproj Example/AFNetworking Example.xcodeproj/xcshareddata/xcschemes/iOS Example.xcscheme Example/AFNetworking Example.xcodeproj/xcshareddata/xcschemes/iOS Today Extension Example.xcscheme Example/AFNetworking Example.xcodeproj/xcshareddata/xcschemes/macOS Example.xcscheme Example/AFNetworking Example.xcodeproj/xcshareddata/xcschemes/tvOS Example.xcscheme Example/AFNetworking Example.xcodeproj/xcshareddata/xcschemes/watchOS Example.xcscheme Example/AFNetworking tvOS Example.xcodeproj/project.pbxproj Example/AFNetworking watchOS/Assets.xcassets/AppIcon.appiconset/Contents.json Example/AFNetworking watchOS/Base.lproj/Interface.storyboard Example/AFNetworking watchOS/Info.plist Example/Assets.xcassets/AppIcon.appiconset/Contents.json Example/Assets.xcassets/Contents.json Example/Assets.xcassets/profile-image-placeholder.imageset/Contents.json Example/Certificates/adn.cer Example/Certificates/digicert_ca_3.cer Example/Certificates/root_ca.cer Example/Classes/Models/Post.h Example/Classes/Models/Post.m Example/Classes/Models/User.h Example/Classes/Models/User.m Example/Classes/Networking Extensions/AFAppDotNetAPIClient.h Example/Classes/Networking Extensions/AFAppDotNetAPIClient.m Example/Prefix.pch Example/Today Extension Example/Base.lproj/MainInterface.storyboard Example/Today Extension Example/Info.plist Example/Today Extension Example/TodayViewController.h Example/Today Extension Example/TodayViewController.m Example/en.lproj/MainMenu.xib Example/iOS Example/AppDelegate.h Example/iOS Example/AppDelegate.m Example/iOS Example/Controllers/GlobalTimelineViewController.h Example/iOS Example/Controllers/GlobalTimelineViewController.m Example/iOS Example/Info.plist Example/iOS Example/Launchscreen.storyboard Example/iOS Example/Views/PostTableViewCell.h Example/iOS Example/Views/PostTableViewCell.m Example/macOS Example/AppDelegate.h Example/macOS Example/AppDelegate.m Example/macOS Example/Assets.xcassets/AppIcon.appiconset/Contents.json Example/macOS Example/Info.plist Example/macOS Example/MainMenu.xib Example/macOS Example/main.m Example/main.m Example/tvOS Example/AFNetworking tvOS Example-Bridging-Header.h Example/tvOS Example/AppDelegate.swift Example/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Content.imageset/Contents.json Example/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Back.imagestacklayer/Contents.json Example/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Contents.json Example/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Content.imageset/Contents.json Example/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Front.imagestacklayer/Contents.json Example/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json Example/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Large.imagestack/Middle.imagestacklayer/Contents.json Example/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Content.imageset/Contents.json Example/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Back.imagestacklayer/Contents.json Example/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Contents.json Example/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Content.imageset/Contents.json Example/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Front.imagestacklayer/Contents.json Example/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Content.imageset/Contents.json Example/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/App Icon - Small.imagestack/Middle.imagestacklayer/Contents.json Example/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Contents.json Example/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image Wide.imageset/Contents.json Example/tvOS Example/Assets.xcassets/App Icon & Top Shelf Image.brandassets/Top Shelf Image.imageset/Contents.json Example/tvOS Example/Assets.xcassets/Contents.json Example/tvOS Example/Assets.xcassets/LaunchImage.launchimage/Contents.json Example/tvOS Example/Base.lproj/Main.storyboard Example/tvOS Example/Gravatar.swift Example/tvOS Example/Info.plist Example/tvOS Example/ViewController.swift Example/watchOS Example Extension/Assets.xcassets/README__ignoredByTemplate__ Example/watchOS Example Extension/ExtensionDelegate.h Example/watchOS Example Extension/ExtensionDelegate.m Example/watchOS Example Extension/Info.plist Example/watchOS Example Extension/InterfaceController.h Example/watchOS Example Extension/InterfaceController.m Example/watchOS Example/Assets.xcassets/AppIcon.appiconset/Contents.json Example/watchOS Example/Base.lproj/Interface.storyboard Example/watchOS Example/Info.plist Framework/AFNetworking.h Framework/Info.plist Framework/module.modulemap LICENSE Tests/Info.plist Tests/Resources/ADN.net/ADNNetServerTrustChain/adn_0.cer Tests/Resources/ADN.net/ADNNetServerTrustChain/adn_1.cer Tests/Resources/ADN.net/ADNNetServerTrustChain/adn_2.cer Tests/Resources/Google.com/Equifax_Secure_Certificate_Authority_Root.cer Tests/Resources/Google.com/GeoTrust_Global_CA-cross.cer Tests/Resources/Google.com/GeoTrust_Global_CA_Root.cer Tests/Resources/Google.com/GoogleComServerTrustChainPath1/googlecom_0.cer Tests/Resources/Google.com/GoogleComServerTrustChainPath1/googlecom_1.cer Tests/Resources/Google.com/GoogleComServerTrustChainPath2/googlecom_0.cer Tests/Resources/Google.com/GoogleComServerTrustChainPath2/googlecom_1.cer Tests/Resources/Google.com/GoogleComServerTrustChainPath2/googlecom_2.cer Tests/Resources/Google.com/GoogleInternetAuthorityG2.cer Tests/Resources/Google.com/google.com.cer Tests/Resources/HTTPBin.org/Amazon Root CA 1.cer Tests/Resources/HTTPBin.org/Amazon.cer Tests/Resources/HTTPBin.org/HTTPBinOrgServerTrustChain/httpbin_0.cer Tests/Resources/HTTPBin.org/HTTPBinOrgServerTrustChain/httpbin_1.cer Tests/Resources/HTTPBin.org/HTTPBinOrgServerTrustChain/httpbin_2.cer Tests/Resources/HTTPBin.org/HTTPBinOrgServerTrustChain/httpbin_3.cer Tests/Resources/HTTPBin.org/Starfield Services Root Certificate Authority - G2.cer Tests/Resources/HTTPBin.org/httpbinorg_03172020.cer Tests/Resources/SelfSigned/AltName.cer Tests/Resources/SelfSigned/NoDomains.cer Tests/Resources/SelfSigned/foobar.com.cer Tests/Tests-Prefix.pch Tests/Tests/AFAutoPurgingImageCacheTests.m Tests/Tests/AFCompoundResponseSerializerTests.m Tests/Tests/AFHTTPRequestSerializationTests.m Tests/Tests/AFHTTPResponseSerializationTests.m Tests/Tests/AFHTTPSessionManagerTests.m Tests/Tests/AFImageDownloaderTests.m Tests/Tests/AFImageResponseSerializerTests.m Tests/Tests/AFJSONSerializationTests.m Tests/Tests/AFNetworkActivityManagerTests.m Tests/Tests/AFNetworkReachabilityManagerTests.m Tests/Tests/AFPropertyListRequestSerializerTests.m Tests/Tests/AFPropertyListResponseSerializerTests.m Tests/Tests/AFSecurityPolicyTests.m Tests/Tests/AFTestCase.h Tests/Tests/AFTestCase.m Tests/Tests/AFUIActivityIndicatorViewTests.m Tests/Tests/AFUIButtonTests.m Tests/Tests/AFUIImageViewTests.m Tests/Tests/AFUIRefreshControlTests.m Tests/Tests/AFUIWebViewTests.m Tests/Tests/AFURLSessionManagerTests.m Tests/Tests/AFXMLDocumentResponseSerializerTests.m Tests/Tests/AFXMLParserResponseSerializerTests.m UIKit+AFNetworking/AFAutoPurgingImageCache.h UIKit+AFNetworking/AFAutoPurgingImageCache.m UIKit+AFNetworking/AFImageDownloader.h UIKit+AFNetworking/AFImageDownloader.m UIKit+AFNetworking/AFNetworkActivityIndicatorManager.h UIKit+AFNetworking/AFNetworkActivityIndicatorManager.m UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.h UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.m UIKit+AFNetworking/UIButton+AFNetworking.h UIKit+AFNetworking/UIButton+AFNetworking.m UIKit+AFNetworking/UIImage+AFNetworking.h UIKit+AFNetworking/UIImageView+AFNetworking.h UIKit+AFNetworking/UIImageView+AFNetworking.m UIKit+AFNetworking/UIKit+AFNetworking.h UIKit+AFNetworking/UIProgressView+AFNetworking.h UIKit+AFNetworking/UIProgressView+AFNetworking.m UIKit+AFNetworking/UIRefreshControl+AFNetworking.h UIKit+AFNetworking/UIRefreshControl+AFNetworking.m UIKit+AFNetworking/UIWebView+AFNetworking.h UIKit+AFNetworking/UIWebView+AFNetworking.m fastlane/.env fastlane/.env.default fastlane/.env.deploy fastlane/.env.ios11_xcode9 fastlane/.env.ios11_xcode91 fastlane/.env.ios11_xcode92 fastlane/.env.ios11_xcode93 fastlane/.env.ios11_xcode94 fastlane/.env.ios12_xcode10 fastlane/.env.ios13_xcode11 fastlane/.env.macos fastlane/.env.tvos13_xcode11 fastlane/Fastfile <<<<<< network # path=AFNetworkingiOSTests.xctest.coverage.txt /Users/travis/build/AFNetworking/AFNetworking/Tests/Tests/AFAutoPurgingImageCacheTests.m: 1| |// AFAutoPurgingImageCacheTests.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import 23| |#import "AFAutoPurgingImageCache.h" 24| | 25| |@interface AFAutoPurgingImageCacheTests : XCTestCase 26| |@property (nonatomic, strong) AFAutoPurgingImageCache *cache; 27| |@property (nonatomic, strong) UIImage *testImage; 28| |@end 29| | 30| |@implementation AFAutoPurgingImageCacheTests 31| | 32| 16|- (void)setUp { 33| 16| [super setUp]; 34| 16| self.cache = [[AFAutoPurgingImageCache alloc] initWithMemoryCapacity:100 * 1024 * 1024 35| 16| preferredMemoryCapacity:60 * 1024 * 1024]; 36| 16| 37| 16| NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"logo" ofType:@"png"]; 38| 16| self.testImage = [UIImage imageWithContentsOfFile:path]; 39| 16| 40| 16| 41| 16|} 42| | 43| 16|- (void)tearDown { 44| 16| [self.cache removeAllImages]; 45| 16| self.cache = nil; 46| 16| self.testImage = nil; 47| 16| [super tearDown]; 48| 16|} 49| | 50| |#pragma mark - Cache Return Images 51| | 52| 1|- (void)testImageIsReturnedFromCacheForIdentifier { 53| 1| NSString *identifier = @"logo"; 54| 1| [self.cache addImage:self.testImage withIdentifier:identifier]; 55| 1| 56| 1| UIImage *cachedImage = [self.cache imageWithIdentifier:identifier]; 57| 1| XCTAssertEqual(self.testImage, cachedImage, @"Cached image should equal original image"); 58| 1|} 59| | 60| 1|- (void)testImageIsReturnedFromCacheForURLRequest { 61| 1| NSURL *url = [NSURL URLWithString:@"http://test.com/image"]; 62| 1| NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url]; 63| 1| [self.cache addImage:self.testImage forRequest:request withAdditionalIdentifier:nil]; 64| 1| 65| 1| UIImage *cachedImage = [self.cache imageforRequest:request withAdditionalIdentifier:nil]; 66| 1| XCTAssertEqual(self.testImage, cachedImage, @"Cached image should equal original image"); 67| 1|} 68| | 69| 1|- (void)testImageIsReturnedFromCacheForURLRequestWithAdditionalIdentifier { 70| 1| NSURL *url = [NSURL URLWithString:@"http://test.com/image"]; 71| 1| NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url]; 72| 1| NSString *additionalIdentifier = @"filter"; 73| 1| [self.cache addImage:self.testImage forRequest:request withAdditionalIdentifier:additionalIdentifier]; 74| 1| 75| 1| UIImage *cachedImage = [self.cache imageforRequest:request withAdditionalIdentifier:additionalIdentifier]; 76| 1| XCTAssertEqual(self.testImage, cachedImage, @"Cached image should equal original image"); 77| 1|} 78| | 79| 1|- (void)testImageIsNotReturnedWhenAdditionalIdentifierIsNotSet { 80| 1| NSURL *url = [NSURL URLWithString:@"http://test.com/image"]; 81| 1| NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url]; 82| 1| NSString *additionalIdentifier = @"filter"; 83| 1| [self.cache addImage:self.testImage forRequest:request withAdditionalIdentifier:additionalIdentifier]; 84| 1| 85| 1| UIImage *cachedImage = [self.cache imageforRequest:request withAdditionalIdentifier:nil]; 86| 1| XCTAssertNil(cachedImage, @"cached image should be nil"); 87| 1|} 88| | 89| 1|- (void)testImageIsNotReturnedWhenURLDoesntMatch { 90| 1| NSURL *url = [NSURL URLWithString:@"http://test.com/image"]; 91| 1| NSURLRequest *originalRequest = [[NSURLRequest alloc] initWithURL:url]; 92| 1| [self.cache addImage:self.testImage forRequest:originalRequest withAdditionalIdentifier:nil]; 93| 1| 94| 1| NSURL *newURL = [NSURL URLWithString:@"http://test.com/differentImage"]; 95| 1| NSURLRequest *newRequest = [[NSURLRequest alloc] initWithURL:newURL]; 96| 1| UIImage *cachedImage = [self.cache imageforRequest:newRequest withAdditionalIdentifier:nil]; 97| 1| XCTAssertNil(cachedImage, @"cached image should be nil"); 98| 1|} 99| | 100| 1|- (void)testDuplicateImageAddedToCacheIsReturned { 101| 1| NSURL *url = [NSURL URLWithString:@"http://test.com/image"]; 102| 1| NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url]; 103| 1| [self.cache addImage:self.testImage forRequest:request withAdditionalIdentifier:nil]; 104| 1| 105| 1| NSString *path = [[NSBundle bundleForClass:[self class]] pathForResource:@"logo" ofType:@"png"]; 106| 1| UIImage *newImage = [UIImage imageWithContentsOfFile:path]; 107| 1| 108| 1| [self.cache addImage:newImage forRequest:request withAdditionalIdentifier:nil]; 109| 1| 110| 1| UIImage *cachedImage = [self.cache imageforRequest:request withAdditionalIdentifier:nil]; 111| 1| XCTAssertEqual(cachedImage, newImage); 112| 1| XCTAssertNotEqual(cachedImage, self.testImage); 113| 1|} 114| | 115| |#pragma mark - Remove Image Tests 116| | 117| 1|- (void)testImageIsRemovedWithIdentifier { 118| 1| NSString *identifier = @"logo"; 119| 1| [self.cache addImage:self.testImage withIdentifier:identifier]; 120| 1| XCTAssertTrue([self.cache removeImageWithIdentifier:identifier], @"image should be reported as removed"); 121| 1| XCTAssertFalse([self.cache removeImageWithIdentifier:identifier], @"image should be reported as removed the second time"); 122| 1| UIImage *cachedImage = [self.cache imageWithIdentifier:identifier]; 123| 1| XCTAssertNil(cachedImage, @"cached image should be nil"); 124| 1|} 125| | 126| 1|- (void)testImageIsRemovedWithURLRequest { 127| 1| NSURL *url = [NSURL URLWithString:@"http://test.com/image"]; 128| 1| NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url]; 129| 1| [self.cache addImage:self.testImage forRequest:request withAdditionalIdentifier:nil]; 130| 1| XCTAssertTrue([self.cache removeImageforRequest:request withAdditionalIdentifier:nil], @"image should be reported as removed"); 131| 1| XCTAssertFalse([self.cache removeImageforRequest:request withAdditionalIdentifier:nil], @"image should be reported as removed the second time"); 132| 1| UIImage *cachedImage = [self.cache imageforRequest:request withAdditionalIdentifier:nil]; 133| 1| XCTAssertNil(cachedImage, @"cached image should be nil"); 134| 1|} 135| | 136| 1|- (void)testImageIsRemovedWithURLRequestWithAdditionalIdentifier { 137| 1| NSURL *url = [NSURL URLWithString:@"http://test.com/image"]; 138| 1| NSString *identifier = @"filter"; 139| 1| NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url]; 140| 1| [self.cache addImage:self.testImage forRequest:request withAdditionalIdentifier:identifier]; 141| 1| XCTAssertTrue([self.cache removeImageforRequest:request withAdditionalIdentifier:identifier], @"image should be reported as removed"); 142| 1| XCTAssertFalse([self.cache removeImageforRequest:request withAdditionalIdentifier:identifier], @"image should be reported as removed the second time"); 143| 1| UIImage *cachedImage = [self.cache imageforRequest:request withAdditionalIdentifier:identifier]; 144| 1| XCTAssertNil(cachedImage, @"cached image should be nil"); 145| 1|} 146| | 147| 1|- (void)testImageIsNotRemovedWithURLRequestAndNilIdentifier { 148| 1| NSURL *url = [NSURL URLWithString:@"http://test.com/image"]; 149| 1| NSString *identifier = @"filter"; 150| 1| NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url]; 151| 1| [self.cache addImage:self.testImage forRequest:request withAdditionalIdentifier:identifier]; 152| 1| XCTAssertFalse([self.cache removeImageforRequest:request withAdditionalIdentifier:nil], @"image should not be reported as removed"); 153| 1| UIImage *cachedImage = [self.cache imageforRequest:request withAdditionalIdentifier:identifier]; 154| 1| XCTAssertNotNil(cachedImage, @"cached image should be nil"); 155| 1|} 156| | 157| 1|- (void)testImageIsNotRemovedWithURLRequestAndIncorrectIdentifier { 158| 1| NSURL *url = [NSURL URLWithString:@"http://test.com/image"]; 159| 1| NSString *identifier = @"filter"; 160| 1| NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url]; 161| 1| [self.cache addImage:self.testImage forRequest:request withAdditionalIdentifier:identifier]; 162| 1| NSString *differentIdentifier = @"nofilter"; 163| 1| XCTAssertFalse([self.cache removeImageforRequest:request withAdditionalIdentifier:differentIdentifier], @"image should not be reported as removed"); 164| 1| UIImage *cachedImage = [self.cache imageforRequest:request withAdditionalIdentifier:identifier]; 165| 1| XCTAssertNotNil(cachedImage, @"cached image should be nil"); 166| 1|} 167| | 168| |#pragma mark - Memory Usage 169| 1|- (void)testThatMemoryUsageIncreasesWhenAddingImage { 170| 1| NSString *identifier = @"logo"; 171| 1| XCTAssertTrue(self.cache.memoryUsage == 0); 172| 1| [self.cache addImage:self.testImage withIdentifier:identifier]; 173| 1| XCTAssertTrue(self.cache.memoryUsage == 1020000); 174| 1|} 175| | 176| 1|- (void)testThatMemoryUsageDecreasesWhenRemovingImage { 177| 1| NSString *identifier = @"logo"; 178| 1| [self.cache addImage:self.testImage withIdentifier:identifier]; 179| 1| UInt64 currentUsage = self.cache.memoryUsage; 180| 1| [self.cache removeImageWithIdentifier:identifier]; 181| 1| XCTAssertTrue(currentUsage > self.cache.memoryUsage); 182| 1|} 183| | 184| |#pragma mark - Purging 185| 1|- (void)testThatImagesArePurgedWhenCapcityIsReached { 186| 1| UInt64 imageSize = 1020000; 187| 1| UInt64 numberOfImages = 10; 188| 1| UInt64 numberOfImagesAfterPurge = 6; 189| 1| self.cache = [[AFAutoPurgingImageCache alloc] initWithMemoryCapacity:numberOfImages * imageSize preferredMemoryCapacity:numberOfImagesAfterPurge * imageSize]; 190| 1| NSUInteger index = 1; 191| 11| while (YES) { 192| 11| NSString * identifier = [NSString stringWithFormat:@"image-%ld",(long)index]; 193| 11| [self.cache addImage:self.testImage withIdentifier:identifier]; 194| 11| if (index <= numberOfImages) { 195| 10| XCTAssertTrue(self.cache.memoryUsage == index * imageSize); 196| 10| } else { 197| 1| XCTAssertTrue(self.cache.memoryUsage == numberOfImagesAfterPurge * imageSize); 198| 1| break; 199| 1| } 200| 10| index++; 201| 10| } 202| 1|} 203| | 204| 1|- (void)testThatPrioritizedImagesWithOldestLastAccessDatesAreRemovedDuringPurge { 205| 1| UInt64 imageSize = 1020000; 206| 1| UInt64 numberOfImages = 10; 207| 1| UInt64 numberOfImagesAfterPurge = 6; 208| 1| self.cache = [[AFAutoPurgingImageCache alloc] initWithMemoryCapacity:numberOfImages * imageSize preferredMemoryCapacity:numberOfImagesAfterPurge * imageSize]; 209| 11| for (NSUInteger index = 0; index < numberOfImages; index ++) { 210| 10| NSString * identifier = [NSString stringWithFormat:@"image-%ld",(long)index]; 211| 10| [self.cache addImage:self.testImage withIdentifier:identifier]; 212| 10| } 213| 1| 214| 1| NSString * firstIdentifier = [NSString stringWithFormat:@"image-%ld",(long)0]; 215| 1| UIImage *firstImage = [self.cache imageWithIdentifier:firstIdentifier]; 216| 1| XCTAssertNotNil(firstImage, @"first image should not be nil"); 217| 1| UInt64 prePurgeMemoryUsage = self.cache.memoryUsage; 218| 1| [self.cache addImage:self.testImage withIdentifier:[NSString stringWithFormat:@"image-%ld",(long)10]]; 219| 1| UInt64 postPurgeMemoryUsage = self.cache.memoryUsage; 220| 1| XCTAssertTrue(postPurgeMemoryUsage < prePurgeMemoryUsage); 221| 1| 222| 12| for (NSUInteger index = 0; index <= numberOfImages; index++) { 223| 11| NSString * identifier = [NSString stringWithFormat:@"image-%ld",(long)index]; 224| 11| UIImage *cachedImage = [self.cache imageWithIdentifier:identifier]; 225| 11| if (index == 0 || index >= 6) { 226| 6| XCTAssertNotNil(cachedImage, @"Image for %@ should be cached", identifier); 227| 6| } else { 228| 5| XCTAssertNil(cachedImage, @"Image for %@ should not be cached", identifier); 229| 5| } 230| 11| } 231| 1|} 232| | 233| |#pragma mark - Should Cache Image 234| 1|- (void)testThatShouldCacheIsYes { 235| 1| NSURL *url = [NSURL URLWithString:@"http://test.com/image"]; 236| 1| NSString *identifier = @"filter"; 237| 1| NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url]; 238| 1| BOOL result = [self.cache shouldCacheImage:self.testImage forRequest:request withAdditionalIdentifier:identifier]; 239| 1| XCTAssertTrue(result); 240| 1|} 241| |@end /Users/travis/build/AFNetworking/AFNetworking/Tests/Tests/AFCompoundResponseSerializerTests.m: 1| |// AFURLSessionManagerTests.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import 23| |#import "AFTestCase.h" 24| |#import "AFURLResponseSerialization.h" 25| | 26| |@interface AFCompoundResponseSerializerTests : AFTestCase 27| | 28| |@end 29| | 30| |@implementation AFCompoundResponseSerializerTests 31| | 32| 3|- (void)setUp { 33| 3| [super setUp]; 34| 3| // Put setup code here. This method is called before the invocation of each test method in the class. 35| 3|} 36| | 37| 3|- (void)tearDown { 38| 3| // Put teardown code here. This method is called after the invocation of each test method in the class. 39| 3| [super tearDown]; 40| 3|} 41| | 42| |#pragma mark - Compound Serializers 43| | 44| 1|- (void)testCompoundSerializerProperlySerializesResponse { 45| 1| 46| 1| AFImageResponseSerializer *imageSerializer = [AFImageResponseSerializer serializer]; 47| 1| AFJSONResponseSerializer *jsonSerializer = [AFJSONResponseSerializer serializer]; 48| 1| AFCompoundResponseSerializer *compoundSerializer = [AFCompoundResponseSerializer compoundSerializerWithResponseSerializers:@[imageSerializer, jsonSerializer]]; 49| 1| 50| 1| NSData *data = [NSJSONSerialization dataWithJSONObject:@{@"key":@"value"} options:(NSJSONWritingOptions)0 error:nil]; 51| 1| NSURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:[NSURL URLWithString:@"http://test.com"] 52| 1| statusCode:200 53| 1| HTTPVersion:@"1.1" 54| 1| headerFields:@{@"Content-Type":@"application/json"}]; 55| 1| 56| 1| NSError *error = nil; 57| 1| id responseObject = [compoundSerializer responseObjectForResponse:response data:data error:&error]; 58| 1| 59| 1| XCTAssertTrue([responseObject isKindOfClass:[NSDictionary class]]); 60| 1| XCTAssertNil(error); 61| 1|} 62| | 63| 1|- (void)testCompoundSerializerCanBeCopied { 64| 1| AFImageResponseSerializer *imageSerializer = [AFImageResponseSerializer serializer]; 65| 1| AFJSONResponseSerializer *jsonSerializer = [AFJSONResponseSerializer serializer]; 66| 1| AFCompoundResponseSerializer *compoundSerializer = [AFCompoundResponseSerializer compoundSerializerWithResponseSerializers:@[imageSerializer, jsonSerializer]]; 67| 1| [compoundSerializer setAcceptableStatusCodes:[NSIndexSet indexSetWithIndex:100]]; 68| 1| [compoundSerializer setAcceptableContentTypes:[NSSet setWithObject:@"test/type"]]; 69| 1| 70| 1| AFCompoundResponseSerializer *copiedSerializer = [compoundSerializer copy]; 71| 1| XCTAssertNotNil(copiedSerializer); 72| 1| XCTAssertNotEqual(compoundSerializer, copiedSerializer); 73| 1| XCTAssertTrue(compoundSerializer.responseSerializers.count == copiedSerializer.responseSerializers.count); 74| 1| XCTAssertTrue([NSStringFromClass([copiedSerializer.responseSerializers[0] class]) isEqualToString:NSStringFromClass([AFImageResponseSerializer class])]); 75| 1| XCTAssertTrue([NSStringFromClass([copiedSerializer.responseSerializers[1] class]) isEqualToString:NSStringFromClass([AFJSONResponseSerializer class])]); 76| 1| XCTAssertEqual(compoundSerializer.acceptableStatusCodes, copiedSerializer.acceptableStatusCodes); 77| 1| XCTAssertEqual(compoundSerializer.acceptableContentTypes, copiedSerializer.acceptableContentTypes); 78| 1|} 79| | 80| 1|- (void)testCompoundSerializerCanBeArchivedAndUnarchived { 81| 1| AFImageResponseSerializer *imageSerializer = [AFImageResponseSerializer serializer]; 82| 1| AFJSONResponseSerializer *jsonSerializer = [AFJSONResponseSerializer serializer]; 83| 1| AFCompoundResponseSerializer *compoundSerializer = [AFCompoundResponseSerializer compoundSerializerWithResponseSerializers:@[imageSerializer, jsonSerializer]]; 84| 1| NSData *data = [NSKeyedArchiver archivedDataWithRootObject:compoundSerializer]; 85| 1| XCTAssertNotNil(data); 86| 1| AFCompoundResponseSerializer *unarchivedSerializer = [NSKeyedUnarchiver unarchiveObjectWithData:data]; 87| 1| XCTAssertNotNil(unarchivedSerializer); 88| 1| XCTAssertNotEqual(unarchivedSerializer, compoundSerializer); 89| 1| XCTAssertTrue(compoundSerializer.responseSerializers.count == compoundSerializer.responseSerializers.count); 90| 1| XCTAssertTrue([NSStringFromClass([unarchivedSerializer.responseSerializers[0] class]) isEqualToString:NSStringFromClass([AFImageResponseSerializer class])]); 91| 1| XCTAssertTrue([NSStringFromClass([unarchivedSerializer.responseSerializers[1] class]) isEqualToString:NSStringFromClass([AFJSONResponseSerializer class])]); 92| 1|} 93| | 94| |@end /Users/travis/build/AFNetworking/AFNetworking/Tests/Tests/AFHTTPRequestSerializationTests.m: 1| |// AFHTTPRequestSerializationTests.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "AFTestCase.h" 23| | 24| |#import "AFURLRequestSerialization.h" 25| | 26| |@interface AFMultipartBodyStream : NSInputStream 27| |@property (readwrite, nonatomic, strong) NSMutableArray *HTTPBodyParts; 28| |@end 29| | 30| |@protocol AFMultipartFormDataTest 31| |@property (readwrite, nonatomic, strong) AFMultipartBodyStream *bodyStream; 32| | 33| |- (instancetype)initWithURLRequest:(NSMutableURLRequest *)urlRequest 34| | stringEncoding:(NSStringEncoding)encoding; 35| |@end 36| | 37| |@interface AFHTTPBodyPart : NSObject 38| |@property (nonatomic, assign) NSStringEncoding stringEncoding; 39| |@property (nonatomic, strong) NSDictionary *headers; 40| |@property (nonatomic, copy) NSString *boundary; 41| |@property (nonatomic, strong) id body; 42| |@property (nonatomic, assign) NSUInteger bodyContentLength; 43| |@property (nonatomic, strong) NSInputStream *inputStream; 44| |@property (nonatomic, assign) BOOL hasInitialBoundary; 45| |@property (nonatomic, assign) BOOL hasFinalBoundary; 46| |@property (readonly, nonatomic, assign, getter = hasBytesAvailable) BOOL bytesAvailable; 47| |@property (readonly, nonatomic, assign) NSUInteger contentLength; 48| | 49| |- (NSInteger)read:(uint8_t *)buffer 50| | maxLength:(NSUInteger)length; 51| |@end 52| | 53| |#pragma mark - 54| | 55| |@interface AFHTTPRequestSerializationTests : AFTestCase 56| |@property (nonatomic, strong) AFHTTPRequestSerializer *requestSerializer; 57| |@end 58| | 59| |@implementation AFHTTPRequestSerializationTests 60| | 61| 16|- (void)setUp { 62| 16| [super setUp]; 63| 16| self.requestSerializer = [AFHTTPRequestSerializer serializer]; 64| 16|} 65| | 66| |#pragma mark - 67| | 68| 1|- (void)testThatAFHTTPRequestSerializationSerializesPOSTRequestsProperly { 69| 1| NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://example.com"]]; 70| 1| request.HTTPMethod = @"POST"; 71| 1| 72| 1| NSURLRequest *serializedRequest = [self.requestSerializer requestBySerializingRequest:request withParameters:@{@"key":@"value"} error:nil]; 73| 1| NSString *contentType = serializedRequest.allHTTPHeaderFields[@"Content-Type"]; 74| 1| 75| 1| XCTAssertNotNil(contentType); 76| 1| XCTAssertEqualObjects(contentType, @"application/x-www-form-urlencoded"); 77| 1| 78| 1| XCTAssertNotNil(serializedRequest.HTTPBody); 79| 1| XCTAssertEqualObjects(serializedRequest.HTTPBody, [@"key=value" dataUsingEncoding:NSUTF8StringEncoding]); 80| 1|} 81| | 82| 1|- (void)testThatAFHTTPRequestSerializationSerializesPOSTRequestsProperlyWhenNoParameterIsProvided { 83| 1| NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://example.com"]]; 84| 1| request.HTTPMethod = @"POST"; 85| 1| 86| 1| NSURLRequest *serializedRequest = [self.requestSerializer requestBySerializingRequest:request withParameters:nil error:nil]; 87| 1| NSString *contentType = serializedRequest.allHTTPHeaderFields[@"Content-Type"]; 88| 1| 89| 1| XCTAssertNotNil(contentType); 90| 1| XCTAssertEqualObjects(contentType, @"application/x-www-form-urlencoded"); 91| 1| 92| 1| XCTAssertNotNil(serializedRequest.HTTPBody); 93| 1| XCTAssertEqualObjects(serializedRequest.HTTPBody, [NSData data]); 94| 1|} 95| | 96| 1|- (void)testThatAFHTTPRequestSerialiationSerializesQueryParametersCorrectly { 97| 1| NSURLRequest *originalRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://example.com"]]; 98| 1| NSURLRequest *serializedRequest = [self.requestSerializer requestBySerializingRequest:originalRequest withParameters:@{@"key":@"value"} error:nil]; 99| 1| 100| 1| XCTAssertTrue([[[serializedRequest URL] query] isEqualToString:@"key=value"], @"Query parameters have not been serialized correctly (%@)", [[serializedRequest URL] query]); 101| 1|} 102| | 103| 1|- (void)testThatEmptyDictionaryParametersAreProperlyEncoded { 104| 1| NSURLRequest *originalRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://example.com"]]; 105| 1| NSURLRequest *serializedRequest = [self.requestSerializer requestBySerializingRequest:originalRequest withParameters:@{} error:nil]; 106| 1| XCTAssertFalse([serializedRequest.URL.absoluteString hasSuffix:@"?"]); 107| 1|} 108| | 109| 1|- (void)testThatAFHTTPRequestSerialiationSerializesURLEncodableQueryParametersCorrectly { 110| 1| NSURLRequest *originalRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://example.com"]]; 111| 1| NSURLRequest *serializedRequest = [self.requestSerializer requestBySerializingRequest:originalRequest withParameters:@{@"key":@" :#[]@!$&'()*+,;=/?"} error:nil]; 112| 1| 113| 1| XCTAssertTrue([[[serializedRequest URL] query] isEqualToString:@"key=%20%3A%23%5B%5D%40%21%24%26%27%28%29%2A%2B%2C%3B%3D/?"], @"Query parameters have not been serialized correctly (%@)", [[serializedRequest URL] query]); 114| 1|} 115| | 116| 1|- (void)testThatAFHTTPRequestSerialiationSerializesURLEncodedQueryParametersCorrectly { 117| 1| NSURLRequest *originalRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://example.com"]]; 118| 1| NSURLRequest *serializedRequest = [self.requestSerializer requestBySerializingRequest:originalRequest withParameters:@{@"key":@"%20%21%22%23%24%25%26%27%28%29%2A%2B%2C%2F"} error:nil]; 119| 1| 120| 1| XCTAssertTrue([[[serializedRequest URL] query] isEqualToString:@"key=%2520%2521%2522%2523%2524%2525%2526%2527%2528%2529%252A%252B%252C%252F"], @"Query parameters have not been serialized correctly (%@)", [[serializedRequest URL] query]); 121| 1|} 122| | 123| 1|- (void)testThatAFHTTPRequestSerialiationSerializesQueryParametersCorrectlyFromQuerySerializationBlock { 124| 1| [self.requestSerializer setQueryStringSerializationWithBlock:^NSString *(NSURLRequest *request, NSDictionary *parameters, NSError *__autoreleasing *error) { 125| 1| __block NSMutableString *query = [NSMutableString stringWithString:@""]; 126| 1| [parameters enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop) { 127| 1| [query appendFormat:@"%@**%@",key,obj]; 128| 1| }]; 129| 1| 130| 1| return query; 131| 1| }]; 132| 1| 133| 1| NSURLRequest *originalRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:@"http://example.com"]]; 134| 1| NSURLRequest *serializedRequest = [self.requestSerializer requestBySerializingRequest:originalRequest withParameters:@{@"key":@"value"} error:nil]; 135| 1| 136| 1| XCTAssertTrue([[[serializedRequest URL] query] isEqualToString:@"key**value"], @"Custom Query parameters have not been serialized correctly (%@) by the query string block.", [[serializedRequest URL] query]); 137| 1|} 138| | 139| 1|- (void)testThatAFHTTPRequestSerialiationSerializesMIMETypeCorrectly { 140| 1| NSMutableURLRequest *originalRequest = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://example.com"]]; 141| 1| Class streamClass = NSClassFromString(@"AFStreamingMultipartFormData"); 142| 1| id formData = [[streamClass alloc] initWithURLRequest:originalRequest stringEncoding:NSUTF8StringEncoding]; 143| 1| 144| 1| NSURL *fileURL = [NSURL fileURLWithPath:[[NSBundle bundleForClass:[self class]] pathForResource:@"ADNNetServerTrustChain/adn_0" ofType:@"cer"]]; 145| 1| 146| 1| [formData appendPartWithFileURL:fileURL name:@"test" error:NULL]; 147| 1| 148| 1| AFHTTPBodyPart *part = [formData.bodyStream.HTTPBodyParts firstObject]; 149| 1| 150| 1| XCTAssertTrue([part.headers[@"Content-Type"] isEqualToString:@"application/x-x509-ca-cert"], @"MIME Type has not been obtained correctly (%@)", part.headers[@"Content-Type"]); 151| 1|} 152| | 153| |#pragma mark - 154| | 155| 1|- (void)testThatValueForHTTPHeaderFieldReturnsSetValue { 156| 1| [self.requestSerializer setValue:@"Actual Value" forHTTPHeaderField:@"Set-Header"]; 157| 1| NSString *value = [self.requestSerializer valueForHTTPHeaderField:@"Set-Header"]; 158| 1| XCTAssertTrue([value isEqualToString:@"Actual Value"]); 159| 1|} 160| | 161| 1|- (void)testThatValueForHTTPHeaderFieldReturnsNilForUnsetHeader { 162| 1| NSString *value = [self.requestSerializer valueForHTTPHeaderField:@"Unset-Header"]; 163| 1| XCTAssertNil(value); 164| 1|} 165| | 166| 1|- (void)testQueryStringSerializationCanFailWithError { 167| 1| AFHTTPRequestSerializer *serializer = [AFHTTPRequestSerializer serializer]; 168| 1| 169| 1| NSError *serializerError = [NSError errorWithDomain:@"TestDomain" code:0 userInfo:nil]; 170| 1| 171| 1| [serializer setQueryStringSerializationWithBlock:^NSString *(NSURLRequest *request, NSDictionary *parameters, NSError *__autoreleasing *error) { 172| 1| if (error != NULL) { 173| 1| *error = serializerError; 174| 1| } 175| 1| return nil; 176| 1| }]; 177| 1| 178| 1| NSError *error; 179| 1| NSURLRequest *request = [serializer requestWithMethod:@"GET" URLString:@"url" parameters:@{} error:&error]; 180| 1| XCTAssertNil(request); 181| 1| XCTAssertEqual(error, serializerError); 182| 1|} 183| | 184| 1|- (void)testThatHTTPHeaderValueCanBeRemoved { 185| 1| AFHTTPRequestSerializer *serializer = [AFHTTPRequestSerializer serializer]; 186| 1| NSString *headerField = @"TestHeader"; 187| 1| NSString *headerValue = @"test"; 188| 1| [serializer setValue:headerValue forHTTPHeaderField:headerField]; 189| 1| XCTAssertTrue([serializer.HTTPRequestHeaders[headerField] isEqualToString:headerValue]); 190| 1| [serializer setValue:nil forHTTPHeaderField:headerField]; 191| 1| XCTAssertFalse([serializer.HTTPRequestHeaders.allKeys containsObject:headerField]); 192| 1|} 193| | 194| 1|- (void)testThatHTTPHeaderValueCanBeSetToReferenceCountedStringFromMultipleThreadsWithoutCrashing { 195| 1| @autoreleasepool { 196| 1| int dispatchTarget = 1000; 197| 1| __block int completionCount = 0; 198| 1.00k| for(int i=0; i _Nonnull formData) { 285| 1| [formData appendPartWithFileData:[payload dataUsingEncoding:NSUTF8StringEncoding] name:@"AFNetworking" fileName:@"AFNetworking" mimeType:@"text/html"]; 286| 1| } 287| 1| progress:^(NSProgress * _Nonnull uploadProgress) { 288| 1| if (uploadProgress.fractionCompleted == 1.0) { 289| 1| [expectation fulfill]; 290| 1| } 291| 1| } 292| 1| success:nil 293| 1| failure:nil]; 294| 1| [self waitForExpectationsWithCommonTimeout]; 295| 1|} 296| | 297| |# pragma mark - Deprecated Progress 298| | 299| 1|- (void)testDownloadProgressIsReportedForDeprecatedGET { 300| 1| __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Progress Should equal 1.0"]; 301| 1|#pragma clang diagnostic push 302| 1|#pragma clang diagnostic ignored "-Wdeprecated-declarations" 303| 1| [self.sessionManager 304| 1| GET:@"image" 305| 1| parameters:nil 306| 1| progress:^(NSProgress * _Nonnull downloadProgress) { 307| 1| if (downloadProgress.fractionCompleted == 1.0) { 308| 1| [expectation fulfill]; 309| 1| } 310| 1| } 311| 1| success:nil 312| 1| failure:nil]; 313| 1|#pragma clang diagnostic pop 314| 1| [self waitForExpectationsWithCommonTimeout]; 315| 1|} 316| | 317| 1|- (void)testUploadProgressIsReportedForDeprecatedPOST { 318| 1| NSMutableString *payload = [NSMutableString stringWithString:@"AFNetworking"]; 319| 1.66k| while ([payload lengthOfBytesUsingEncoding:NSUTF8StringEncoding] < 20000) { 320| 1.66k| [payload appendString:@"AFNetworking"]; 321| 1.66k| } 322| 1| 323| 1| __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Progress Should equal 1.0"]; 324| 1|#pragma clang diagnostic push 325| 1|#pragma clang diagnostic ignored "-Wdeprecated-declarations" 326| 1| [self.sessionManager 327| 1| POST:@"post" 328| 1| parameters:payload 329| 1| progress:^(NSProgress * _Nonnull uploadProgress) { 330| 1| if (uploadProgress.fractionCompleted == 1.0) { 331| 1| [expectation fulfill]; 332| 1| } 333| 1| } 334| 1| success:nil 335| 1| failure:nil]; 336| 1|#pragma clang diagnostic pop 337| 1| [self waitForExpectationsWithCommonTimeout]; 338| 1|} 339| | 340| 1|- (void)testUploadProgressIsReportedForStreamingDeprecatedPost { 341| 1| NSMutableString *payload = [NSMutableString stringWithString:@"AFNetworking"]; 342| 1.66k| while ([payload lengthOfBytesUsingEncoding:NSUTF8StringEncoding] < 20000) { 343| 1.66k| [payload appendString:@"AFNetworking"]; 344| 1.66k| } 345| 1| 346| 1| __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Progress Should equal 1.0"]; 347| 1|#pragma clang diagnostic push 348| 1|#pragma clang diagnostic ignored "-Wdeprecated-declarations" 349| 1| [self.sessionManager 350| 1| POST:@"post" 351| 1| parameters:nil 352| 1| constructingBodyWithBlock:^(id _Nonnull formData) { 353| 1| [formData appendPartWithFileData:[payload dataUsingEncoding:NSUTF8StringEncoding] name:@"AFNetworking" fileName:@"AFNetworking" mimeType:@"text/html"]; 354| 1| } 355| 1| progress:^(NSProgress * _Nonnull uploadProgress) { 356| 1| if (uploadProgress.fractionCompleted == 1.0) { 357| 1| [expectation fulfill]; 358| 1| } 359| 1| } 360| 1| success:nil 361| 1| failure:nil]; 362| 1|#pragma clang diagnostic pop 363| 1| [self waitForExpectationsWithCommonTimeout]; 364| 1|} 365| | 366| |# pragma mark - HTTP Status Codes 367| | 368| 1|- (void)testThatSuccessBlockIsCalledFor200 { 369| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 370| 1| [self.sessionManager 371| 1| GET:@"status/200" 372| 1| parameters:nil 373| 1| headers:nil 374| 1| progress:nil 375| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 376| 1| [expectation fulfill]; 377| 1| } 378| 1| failure:nil]; 379| 1| [self waitForExpectationsWithCommonTimeout]; 380| 1|} 381| | 382| 1|- (void)testThatFailureBlockIsCalledFor404 { 383| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 384| 1| [self.sessionManager 385| 1| GET:@"status/404" 386| 1| parameters:nil 387| 1| headers:nil 388| 1| progress:nil 389| 1| success:nil 390| 1| failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nullable error) { 391| 1| [expectation fulfill]; 392| 1| }]; 393| 1| [self waitForExpectationsWithCommonTimeout]; 394| 1|} 395| | 396| 1|- (void)testThatResponseObjectIsEmptyFor204 { 397| 1| __block id urlResponseObject = nil; 398| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 399| 1| [self.sessionManager 400| 1| GET:@"status/204" 401| 1| parameters:nil 402| 1| headers:nil 403| 1| progress:nil 404| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 405| 1| urlResponseObject = responseObject; 406| 1| [expectation fulfill]; 407| 1| } 408| 1| failure:nil]; 409| 1| [self waitForExpectationsWithCommonTimeout]; 410| 1| XCTAssertNil(urlResponseObject); 411| 1|} 412| | 413| |#pragma mark - Rest Interface 414| | 415| 1|- (void)testGET { 416| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 417| 1| [self.sessionManager 418| 1| GET:@"get" 419| 1| parameters:nil 420| 1| headers:nil 421| 1| progress:nil 422| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 423| 1| XCTAssertNotNil(responseObject); 424| 1| [expectation fulfill]; 425| 1| } 426| 1| failure:nil]; 427| 1| [self waitForExpectationsWithCommonTimeout]; 428| 1|} 429| | 430| 1|- (void)testHEAD { 431| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 432| 1| [self.sessionManager 433| 1| HEAD:@"get" 434| 1| parameters:nil 435| 1| headers:nil 436| 1| success:^(NSURLSessionDataTask * _Nonnull task) { 437| 1| XCTAssertNotNil(task); 438| 1| [expectation fulfill]; 439| 1| } 440| 1| failure:nil]; 441| 1| [self waitForExpectationsWithCommonTimeout]; 442| 1|} 443| | 444| 1|- (void)testPOST { 445| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 446| 1| [self.sessionManager 447| 1| POST:@"post" 448| 1| parameters:@{@"key":@"value"} 449| 1| headers:@{@"field":@"value"} 450| 1| progress:nil 451| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 452| 1| XCTAssertTrue([task.originalRequest.allHTTPHeaderFields[@"field"] isEqualToString:@"value"]); 453| 1| XCTAssertTrue([responseObject[@"form"][@"key"] isEqualToString:@"value"]); 454| 1| [expectation fulfill]; 455| 1| } 456| 1| failure:nil]; 457| 1| [self waitForExpectationsWithCommonTimeout]; 458| 1|} 459| | 460| 1|- (void)testPOSTWithConstructingBody { 461| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 462| 1| [self.sessionManager 463| 1| POST:@"post" 464| 1| parameters:@{@"key":@"value"} 465| 1| headers:@{@"field":@"value"} 466| 1| constructingBodyWithBlock:^(id _Nonnull formData) { 467| 1| [formData appendPartWithFileData:[@"Data" dataUsingEncoding:NSUTF8StringEncoding] 468| 1| name:@"DataName" 469| 1| fileName:@"DataFileName" 470| 1| mimeType:@"data"]; 471| 1| } 472| 1| progress:nil 473| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 474| 1| XCTAssertTrue([task.originalRequest.allHTTPHeaderFields[@"field"] isEqualToString:@"value"]); 475| 1| XCTAssertTrue([responseObject[@"files"][@"DataName"] isEqualToString:@"Data"]); 476| 1| XCTAssertTrue([responseObject[@"form"][@"key"] isEqualToString:@"value"]); 477| 1| [expectation fulfill]; 478| 1| } 479| 1| failure:nil]; 480| 1| [self waitForExpectationsWithCommonTimeout]; 481| 1|} 482| | 483| 1|- (void)testPUT { 484| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 485| 1| [self.sessionManager 486| 1| PUT:@"put" 487| 1| parameters:@{@"key":@"value"} 488| 1| headers:@{@"field":@"value"} 489| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 490| 1| XCTAssertTrue([task.originalRequest.allHTTPHeaderFields[@"field"] isEqualToString:@"value"]); 491| 1| XCTAssertTrue([responseObject[@"form"][@"key"] isEqualToString:@"value"]); 492| 1| [expectation fulfill]; 493| 1| } 494| 1| failure:nil]; 495| 1| [self waitForExpectationsWithCommonTimeout]; 496| 1|} 497| | 498| 1|- (void)testDELETE { 499| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 500| 1| [self.sessionManager 501| 1| DELETE:@"delete" 502| 1| parameters:@{@"key":@"value"} 503| 1| headers:@{@"field":@"value"} 504| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 505| 1| XCTAssertTrue([task.originalRequest.allHTTPHeaderFields[@"field"] isEqualToString:@"value"]); 506| 1| XCTAssertTrue([responseObject[@"args"][@"key"] isEqualToString:@"value"]); 507| 1| [expectation fulfill]; 508| 1| } 509| 1| failure:nil]; 510| 1| [self waitForExpectationsWithCommonTimeout]; 511| 1|} 512| | 513| 1|- (void)testPATCH { 514| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 515| 1| [self.sessionManager 516| 1| PATCH:@"patch" 517| 1| parameters:@{@"key":@"value"} 518| 1| headers:@{@"field":@"value"} 519| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 520| 1| XCTAssertTrue([task.originalRequest.allHTTPHeaderFields[@"field"] isEqualToString:@"value"]); 521| 1| XCTAssertTrue([responseObject[@"form"][@"key"] isEqualToString:@"value"]); 522| 1| [expectation fulfill]; 523| 1| } 524| 1| failure:nil]; 525| 1| 526| 1| [self waitForExpectationsWithCommonTimeout]; 527| 1|} 528| | 529| |#pragma mark - Deprecated Rest Interface 530| | 531| 1|- (void)testDeprecatedGETWithoutProgress { 532| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 533| 1|#pragma clang diagnostic push 534| 1|#pragma clang diagnostic ignored "-Wdeprecated-declarations" 535| 1| [self.sessionManager 536| 1| GET:@"get" 537| 1| parameters:nil 538| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 539| 1| XCTAssertNotNil(responseObject); 540| 1| [expectation fulfill]; 541| 1| } 542| 1| failure:nil]; 543| 1|#pragma clang diagnostic pop 544| 1| [self waitForExpectationsWithCommonTimeout]; 545| 1|} 546| | 547| 1|- (void)testDeprecatedPOSTWithoutProgress { 548| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 549| 1|#pragma clang diagnostic push 550| 1|#pragma clang diagnostic ignored "-Wdeprecated-declarations" 551| 1| [self.sessionManager 552| 1| POST:@"post" 553| 1| parameters:@{@"key":@"value"} 554| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 555| 1| XCTAssertTrue([responseObject[@"form"][@"key"] isEqualToString:@"value"]); 556| 1| [expectation fulfill]; 557| 1| } 558| 1| failure:nil]; 559| 1|#pragma clang diagnostic pop 560| 1| [self waitForExpectationsWithCommonTimeout]; 561| 1|} 562| | 563| 1|- (void)testDeprecatedPOSTWithoutProgressWithConstructingBody { 564| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 565| 1|#pragma clang diagnostic push 566| 1|#pragma clang diagnostic ignored "-Wdeprecated-declarations" 567| 1| [self.sessionManager 568| 1| POST:@"post" 569| 1| parameters:@{@"key":@"value"} 570| 1| constructingBodyWithBlock:^(id _Nonnull formData) { 571| 1| [formData appendPartWithFileData:[@"Data" dataUsingEncoding:NSUTF8StringEncoding] 572| 1| name:@"DataName" 573| 1| fileName:@"DataFileName" 574| 1| mimeType:@"data"]; 575| 1| } 576| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 577| 1| XCTAssertTrue([responseObject[@"files"][@"DataName"] isEqualToString:@"Data"]); 578| 1| XCTAssertTrue([responseObject[@"form"][@"key"] isEqualToString:@"value"]); 579| 1| [expectation fulfill]; 580| 1| } 581| 1| failure:nil]; 582| 1|#pragma clang diagnostic pop 583| 1| [self waitForExpectationsWithCommonTimeout]; 584| 1|} 585| | 586| | 587| 1|- (void)testDeprecatedGETWithoutHeaders { 588| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 589| 1|#pragma clang diagnostic push 590| 1|#pragma clang diagnostic ignored "-Wdeprecated-declarations" 591| 1| [self.sessionManager 592| 1| GET:@"get" 593| 1| parameters:nil 594| 1| progress:nil 595| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 596| 1| XCTAssertNotNil(responseObject); 597| 1| [expectation fulfill]; 598| 1| } 599| 1| failure:nil]; 600| 1|#pragma clang diagnostic pop 601| 1| [self waitForExpectationsWithCommonTimeout]; 602| 1|} 603| | 604| 1|- (void)testDeprecatedHEADWithoutHeaders { 605| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 606| 1|#pragma clang diagnostic push 607| 1|#pragma clang diagnostic ignored "-Wdeprecated-declarations" 608| 1| [self.sessionManager 609| 1| HEAD:@"get" 610| 1| parameters:nil 611| 1| success:^(NSURLSessionDataTask * _Nonnull task) { 612| 1| XCTAssertNotNil(task); 613| 1| [expectation fulfill]; 614| 1| } 615| 1| failure:nil]; 616| 1|#pragma clang diagnostic pop 617| 1| [self waitForExpectationsWithCommonTimeout]; 618| 1|} 619| | 620| 1|- (void)testDeprecatedPOSTWithoutHeaders { 621| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 622| 1|#pragma clang diagnostic push 623| 1|#pragma clang diagnostic ignored "-Wdeprecated-declarations" 624| 1| [self.sessionManager 625| 1| POST:@"post" 626| 1| parameters:@{@"key":@"value"} 627| 1| progress:nil 628| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 629| 1| XCTAssertTrue([responseObject[@"form"][@"key"] isEqualToString:@"value"]); 630| 1| [expectation fulfill]; 631| 1| } 632| 1| failure:nil]; 633| 1|#pragma clang diagnostic pop 634| 1| [self waitForExpectationsWithCommonTimeout]; 635| 1|} 636| | 637| 1|- (void)testDeprecatedPOSTWithoutHeadersWithConstructingBody { 638| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 639| 1|#pragma clang diagnostic push 640| 1|#pragma clang diagnostic ignored "-Wdeprecated-declarations" 641| 1| [self.sessionManager 642| 1| POST:@"post" 643| 1| parameters:@{@"key":@"value"} 644| 1| constructingBodyWithBlock:^(id _Nonnull formData) { 645| 1| [formData appendPartWithFileData:[@"Data" dataUsingEncoding:NSUTF8StringEncoding] 646| 1| name:@"DataName" 647| 1| fileName:@"DataFileName" 648| 1| mimeType:@"data"]; 649| 1| } 650| 1| progress:nil 651| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 652| 1| XCTAssertTrue([responseObject[@"files"][@"DataName"] isEqualToString:@"Data"]); 653| 1| XCTAssertTrue([responseObject[@"form"][@"key"] isEqualToString:@"value"]); 654| 1| [expectation fulfill]; 655| 1| } 656| 1| failure:nil]; 657| 1|#pragma clang diagnostic pop 658| 1| [self waitForExpectationsWithCommonTimeout]; 659| 1|} 660| | 661| 1|- (void)testDeprecatedPUTWithoutHeaders { 662| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 663| 1|#pragma clang diagnostic push 664| 1|#pragma clang diagnostic ignored "-Wdeprecated-declarations" 665| 1| [self.sessionManager 666| 1| PUT:@"put" 667| 1| parameters:@{@"key":@"value"} 668| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 669| 1| XCTAssertTrue([responseObject[@"form"][@"key"] isEqualToString:@"value"]); 670| 1| [expectation fulfill]; 671| 1| } 672| 1| failure:nil]; 673| 1|#pragma clang diagnostic pop 674| 1| [self waitForExpectationsWithCommonTimeout]; 675| 1|} 676| | 677| 1|- (void)testDeprecatedDELETEWithoutHeaders { 678| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 679| 1|#pragma clang diagnostic push 680| 1|#pragma clang diagnostic ignored "-Wdeprecated-declarations" 681| 1| [self.sessionManager 682| 1| DELETE:@"delete" 683| 1| parameters:@{@"key":@"value"} 684| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 685| 1| XCTAssertTrue([responseObject[@"args"][@"key"] isEqualToString:@"value"]); 686| 1| [expectation fulfill]; 687| 1| } 688| 1| failure:nil]; 689| 1|#pragma clang diagnostic pop 690| 1| [self waitForExpectationsWithCommonTimeout]; 691| 1|} 692| | 693| 1|- (void)testDeprecatedPATCHWithoutHeaders { 694| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 695| 1|#pragma clang diagnostic push 696| 1|#pragma clang diagnostic ignored "-Wdeprecated-declarations" 697| 1| [self.sessionManager 698| 1| PATCH:@"patch" 699| 1| parameters:@{@"key":@"value"} 700| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 701| 1| XCTAssertTrue([responseObject[@"form"][@"key"] isEqualToString:@"value"]); 702| 1| [expectation fulfill]; 703| 1| } 704| 1| failure:nil]; 705| 1|#pragma clang diagnostic pop 706| 1| [self waitForExpectationsWithCommonTimeout]; 707| 1|} 708| | 709| |#pragma mark - Auth 710| | 711| 1|- (void)testHiddenBasicAuthentication { 712| 1| __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Request should finish"]; 713| 1| [self.sessionManager.requestSerializer setAuthorizationHeaderFieldWithUsername:@"user" password:@"password"]; 714| 1| [self.sessionManager 715| 1| GET:@"hidden-basic-auth/user/password" 716| 1| parameters:nil 717| 1| headers:nil 718| 1| progress:nil 719| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 720| 1| [expectation fulfill]; 721| 1| } failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { 722| 0| XCTFail(@"Request should succeed"); 723| 0| [expectation fulfill]; 724| 0| }]; 725| 1| [self waitForExpectationsWithCommonTimeout]; 726| 1|} 727| | 728| |# pragma mark - Security Policy 729| | 730| 1|- (void)testValidSecureNoPinningSecurityPolicy { 731| 1| AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"https://example.com"]]; 732| 1| AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone]; 733| 1| XCTAssertNoThrow(manager.securityPolicy = securityPolicy); 734| 1|} 735| | 736| 1|- (void)testValidInsecureNoPinningSecurityPolicy { 737| 1| AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"http://example.com"]]; 738| 1| AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone]; 739| 1| XCTAssertNoThrow(manager.securityPolicy = securityPolicy); 740| 1|} 741| | 742| 1|- (void)testValidCertificatePinningSecurityPolicy { 743| 1| AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"https://example.com"]]; 744| 1| AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; 745| 1| XCTAssertNoThrow(manager.securityPolicy = securityPolicy); 746| 1|} 747| | 748| 1|- (void)testInvalidCertificatePinningSecurityPolicy { 749| 1| AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"http://example.com"]]; 750| 1| AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; 751| 1| XCTAssertThrowsSpecificNamed(manager.securityPolicy = securityPolicy, NSException, @"Invalid Security Policy"); 752| 1|} 753| | 754| 1|- (void)testValidPublicKeyPinningSecurityPolicy { 755| 1| AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"https://example.com"]]; 756| 1| AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey]; 757| 1| XCTAssertNoThrow(manager.securityPolicy = securityPolicy); 758| 1|} 759| | 760| 1|- (void)testInvalidPublicKeyPinningSecurityPolicy { 761| 1| AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"http://example.com"]]; 762| 1| AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey]; 763| 1| XCTAssertThrowsSpecificNamed(manager.securityPolicy = securityPolicy, NSException, @"Invalid Security Policy"); 764| 1|} 765| | 766| 1|- (void)testInvalidCertificatePinningSecurityPolicyWithoutBaseURL { 767| 1| AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] init]; 768| 1| AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; 769| 1| XCTAssertThrowsSpecificNamed(manager.securityPolicy = securityPolicy, NSException, @"Invalid Security Policy"); 770| 1|} 771| | 772| 1|- (void)testInvalidPublicKeyPinningSecurityPolicyWithoutBaseURL { 773| 1| AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] init]; 774| 1| AFSecurityPolicy *securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey]; 775| 1| XCTAssertThrowsSpecificNamed(manager.securityPolicy = securityPolicy, NSException, @"Invalid Security Policy"); 776| 1|} 777| | 778| |# pragma mark - Server Trust 779| | 780| 1|- (void)testInvalidServerTrustProducesCorrectErrorForCertificatePinning { 781| 1| __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Request should fail"]; 782| 1| NSURL *googleCertificateURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"google.com" withExtension:@"cer"]; 783| 1| NSData *googleCertificateData = [NSData dataWithContentsOfURL:googleCertificateURL]; 784| 1| AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"https://apple.com/"]]; 785| 1| [manager setResponseSerializer:[AFHTTPResponseSerializer serializer]]; 786| 1| manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:[NSSet setWithObject:googleCertificateData]]; 787| 1| [manager 788| 1| GET:@"" 789| 1| parameters:nil 790| 1| headers:nil 791| 1| progress:nil 792| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 793| 0| XCTFail(@"Request should fail"); 794| 0| [expectation fulfill]; 795| 0| } 796| 1| failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { 797| 1| XCTAssertEqualObjects(error.domain, NSURLErrorDomain); 798| 1| XCTAssertEqual(error.code, NSURLErrorCancelled); 799| 1| [expectation fulfill]; 800| 1| }]; 801| 1| [self waitForExpectationsWithCommonTimeout]; 802| 1| [manager invalidateSessionCancelingTasks:YES resetSession:NO]; 803| 1|} 804| | 805| 1|- (void)testInvalidServerTrustProducesCorrectErrorForPublicKeyPinning { 806| 1| __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Request should fail"]; 807| 1| NSURL *googleCertificateURL = [[NSBundle bundleForClass:[self class]] URLForResource:@"google.com" withExtension:@"cer"]; 808| 1| NSData *googleCertificateData = [NSData dataWithContentsOfURL:googleCertificateURL]; 809| 1| AFHTTPSessionManager *manager = [[AFHTTPSessionManager alloc] initWithBaseURL:[NSURL URLWithString:@"https://apple.com/"]]; 810| 1| [manager setResponseSerializer:[AFHTTPResponseSerializer serializer]]; 811| 1| manager.securityPolicy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey withPinnedCertificates:[NSSet setWithObject:googleCertificateData]]; 812| 1| [manager 813| 1| GET:@"" 814| 1| parameters:nil 815| 1| headers:nil 816| 1| progress:nil 817| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) { 818| 0| XCTFail(@"Request should fail"); 819| 0| [expectation fulfill]; 820| 0| } 821| 1| failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { 822| 1| XCTAssertEqualObjects(error.domain, NSURLErrorDomain); 823| 1| XCTAssertEqual(error.code, NSURLErrorCancelled); 824| 1| [expectation fulfill]; 825| 1| }]; 826| 1| [self waitForExpectationsWithCommonTimeout]; 827| 1| [manager invalidateSessionCancelingTasks:YES resetSession:NO]; 828| 1|} 829| | 830| |@end /Users/travis/build/AFNetworking/AFNetworking/Tests/Tests/AFImageDownloaderTests.m: 1| |// AFImageDownloaderTests.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "AFTestCase.h" 23| |#import "AFImageDownloader.h" 24| | 25| |@interface MockAFAutoPurgingImageCache : AFAutoPurgingImageCache 26| |@property (nonatomic, strong) BOOL(^shouldCache)(UIImage*, NSURLRequest*, NSString*); 27| |@property (nonatomic, strong) void(^addCache)(UIImage*, NSString*); 28| |@end 29| | 30| |@interface AFImageDownloaderTests : AFTestCase 31| |@property (nonatomic, strong) NSURLRequest *pngRequest; 32| |@property (nonatomic, strong) NSURLRequest *jpegRequest; 33| |@property (nonatomic, strong) AFImageDownloader *downloader; 34| |@end 35| | 36| |@implementation AFImageDownloaderTests 37| | 38| 18|- (void)setUp { 39| 18| [super setUp]; 40| 18| self.downloader = [[AFImageDownloader alloc] init]; 41| 18| [[AFImageDownloader defaultURLCache] removeAllCachedResponses]; 42| 18| [[[AFImageDownloader defaultInstance] imageCache] removeAllImages]; 43| 18| self.pngRequest = [NSURLRequest requestWithURL:self.pngURL]; 44| 18| self.jpegRequest = [NSURLRequest requestWithURL:self.jpegURL]; 45| 18|} 46| | 47| 18|- (void)tearDown { 48| 18| [self.downloader.sessionManager invalidateSessionCancelingTasks:YES resetSession:NO]; 49| 18| self.downloader = nil; 50| 18| // Put teardown code here. This method is called after the invocation of each test method in the class. 51| 18| [super tearDown]; 52| 18| self.pngRequest = nil; 53| 18|} 54| | 55| |#pragma mark - Image Download 56| | 57| 1|- (void)testThatImageDownloaderSingletonCanBeInitialized { 58| 1| AFImageDownloader *downloader = [AFImageDownloader defaultInstance]; 59| 1| XCTAssertNotNil(downloader, @"Downloader should not be nil"); 60| 1|} 61| | 62| 1|- (void)testThatImageDownloaderCanBeInitializedAndDeinitializedWithActiveDownloads { 63| 1| [self.downloader downloadImageForURLRequest:self.pngRequest 64| 1| success:nil 65| 1| failure:nil]; 66| 1| self.downloader = nil; 67| 1| XCTAssertNil(self.downloader, @"Downloader should be nil"); 68| 1|} 69| | 70| |- (void)testThatImageDownloaderReturnsNilWithInvalidURL 71| 1|{ 72| 1| NSMutableURLRequest *mutableURLRequest = [NSMutableURLRequest requestWithURL:self.pngURL]; 73| 1| [mutableURLRequest setURL:nil]; 74| 1| /** NSURLRequest nor NSMutableURLRequest can be initialized with a nil URL, 75| 1| * but NSMutableURLRequest can have its URL set to nil 76| 1| **/ 77| 1| NSURLRequest *invalidRequest = [mutableURLRequest copy]; 78| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should fail"]; 79| 1| AFImageDownloadReceipt *downloadReceipt = [self.downloader 80| 1| downloadImageForURLRequest:invalidRequest 81| 1| success:nil 82| 1| failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) { 83| 1| XCTAssertNotNil(error); 84| 1| XCTAssertTrue([error.domain isEqualToString:NSURLErrorDomain]); 85| 1| XCTAssertTrue(error.code == NSURLErrorBadURL); 86| 1| [expectation fulfill]; 87| 1| }]; 88| 1| [self waitForExpectationsWithCommonTimeout]; 89| 1| XCTAssertNil(downloadReceipt, @"downloadReceipt should be nil"); 90| 1|} 91| | 92| 1|- (void)testThatImageDownloaderCanDownloadImage { 93| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"image download should succeed"]; 94| 1| 95| 1| __block NSHTTPURLResponse *urlResponse = nil; 96| 1| __block UIImage *responseImage = nil; 97| 1| 98| 1| [self.downloader 99| 1| downloadImageForURLRequest:self.pngRequest 100| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 101| 1| urlResponse = response; 102| 1| responseImage = responseObject; 103| 1| [expectation fulfill]; 104| 1| } 105| 1| failure:nil]; 106| 1| 107| 1| [self waitForExpectationsWithCommonTimeout]; 108| 1| 109| 1| XCTAssertNotNil(urlResponse, @"HTTPURLResponse should not be nil"); 110| 1| XCTAssertNotNil(responseImage, @"Response image should not be nil"); 111| 1|} 112| | 113| 1|- (void)testThatItCanDownloadMultipleImagesSimultaneously { 114| 1| XCTestExpectation *expectation1 = [self expectationWithDescription:@"image 1 download should succeed"]; 115| 1| __block NSHTTPURLResponse *urlResponse1 = nil; 116| 1| __block UIImage *responseImage1 = nil; 117| 1| 118| 1| [self.downloader 119| 1| downloadImageForURLRequest:self.pngRequest 120| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 121| 1| urlResponse1 = response; 122| 1| responseImage1 = responseObject; 123| 1| [expectation1 fulfill]; 124| 1| } 125| 1| failure:nil]; 126| 1| 127| 1| XCTestExpectation *expectation2 = [self expectationWithDescription:@"image 2 download should succeed"]; 128| 1| __block NSHTTPURLResponse *urlResponse2 = nil; 129| 1| __block UIImage *responseImage2 = nil; 130| 1| 131| 1| [self.downloader 132| 1| downloadImageForURLRequest:self.jpegRequest 133| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 134| 1| urlResponse2 = response; 135| 1| responseImage2 = responseObject; 136| 1| [expectation2 fulfill]; 137| 1| } 138| 1| failure:nil]; 139| 1| 140| 1| [self waitForExpectationsWithCommonTimeout]; 141| 1| 142| 1| XCTAssertNotNil(urlResponse1, @"HTTPURLResponse should not be nil"); 143| 1| XCTAssertNotNil(responseImage1, @"Respone image should not be nil"); 144| 1| 145| 1| XCTAssertNotNil(urlResponse2, @"HTTPURLResponse should not be nil"); 146| 1| XCTAssertNotNil(responseImage2, @"Respone image should not be nil"); 147| 1|} 148| | 149| 1|- (void)testThatSimultaneouslyRequestsForTheSameAssetReceiveSameResponse { 150| 1| XCTestExpectation *expectation1 = [self expectationWithDescription:@"image 1 download should succeed"]; 151| 1| __block NSHTTPURLResponse *urlResponse1 = nil; 152| 1| __block UIImage *responseImage1 = nil; 153| 1| 154| 1| [self.downloader 155| 1| downloadImageForURLRequest:self.pngRequest 156| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 157| 1| urlResponse1 = response; 158| 1| responseImage1 = responseObject; 159| 1| [expectation1 fulfill]; 160| 1| } 161| 1| failure:nil]; 162| 1| 163| 1| XCTestExpectation *expectation2 = [self expectationWithDescription:@"image 2 download should succeed"]; 164| 1| __block NSHTTPURLResponse *urlResponse2 = nil; 165| 1| __block UIImage *responseImage2 = nil; 166| 1| 167| 1| [self.downloader 168| 1| downloadImageForURLRequest:self.pngRequest 169| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 170| 1| urlResponse2 = response; 171| 1| responseImage2 = responseObject; 172| 1| [expectation2 fulfill]; 173| 1| } 174| 1| failure:nil]; 175| 1| 176| 1| [self waitForExpectationsWithCommonTimeout]; 177| 1| 178| 1| XCTAssertEqual(urlResponse1, urlResponse2, @"responses should be equal"); 179| 1| XCTAssertEqual(responseImage2, responseImage2, @"responses should be equal"); 180| 1|} 181| | 182| 1|- (void)testThatImageBehindRedirectCanBeDownloaded { 183| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"image download should succeed"]; 184| 1| NSURL *redirectURL = [self.jpegRequest URL]; 185| 1| NSURLRequest *downloadRequest = [NSURLRequest requestWithURL:redirectURL]; 186| 1| 187| 1| __block NSHTTPURLResponse *urlResponse = nil; 188| 1| __block UIImage *responseImage = nil; 189| 1| 190| 1| [self.downloader 191| 1| downloadImageForURLRequest:downloadRequest 192| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 193| 1| urlResponse = response; 194| 1| responseImage = responseObject; 195| 1| [expectation fulfill]; 196| 1| } 197| 1| failure:nil]; 198| 1| [self waitForExpectationsWithCommonTimeout]; 199| 1| XCTAssertNotNil(urlResponse); 200| 1| XCTAssertNotNil(responseImage); 201| 1| 202| 1|} 203| | 204| |#pragma mark - Caching 205| 1|- (void)testThatResponseIsNilWhenReturnedFromCache { 206| 1| XCTestExpectation *expectation1 = [self expectationWithDescription:@"image 1 download should succeed"]; 207| 1| __block NSHTTPURLResponse *urlResponse1 = nil; 208| 1| __block UIImage *responseImage1 = nil; 209| 1| 210| 1| [self.downloader 211| 1| downloadImageForURLRequest:self.pngRequest 212| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 213| 1| urlResponse1 = response; 214| 1| responseImage1 = responseObject; 215| 1| [expectation1 fulfill]; 216| 1| } 217| 1| failure:nil]; 218| 1| 219| 1| [self waitForExpectationsWithCommonTimeout]; 220| 1| 221| 1| XCTestExpectation *expectation2 = [self expectationWithDescription:@"image 2 download should succeed"]; 222| 1| __block NSHTTPURLResponse *urlResponse2 = nil; 223| 1| __block UIImage *responseImage2 = nil; 224| 1| 225| 1| [self.downloader 226| 1| downloadImageForURLRequest:self.pngRequest 227| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 228| 1| urlResponse2 = response; 229| 1| responseImage2 = responseObject; 230| 1| [expectation2 fulfill]; 231| 1| } 232| 1| failure:nil]; 233| 1| 234| 1| [self waitForExpectationsWithCommonTimeout]; 235| 1| 236| 1| XCTAssertNotNil(urlResponse1); 237| 1| XCTAssertNotNil(responseImage1); 238| 1| XCTAssertNil(urlResponse2); 239| 1| XCTAssertEqual(responseImage1, responseImage2); 240| 1|} 241| | 242| 1|- (void)testThatImageCacheIsPromptedShouldCache { 243| 1| XCTestExpectation *expectation3 = [self expectationWithDescription:@"image 1 shouldCache called"]; 244| 1| XCTestExpectation *expectation4 = [self expectationWithDescription:@"image 1 addCache called"]; 245| 1| 246| 1| MockAFAutoPurgingImageCache *mock = [[MockAFAutoPurgingImageCache alloc] init]; 247| 1| mock.shouldCache = ^BOOL(UIImage *img, NSURLRequest *req, NSString *iden) { 248| 1| [expectation3 fulfill]; 249| 1| return YES; 250| 1| }; 251| 1| mock.addCache = ^(UIImage *img, NSString *ident) { 252| 1| [expectation4 fulfill]; 253| 1| }; 254| 1| self.downloader.imageCache = mock; 255| 1| 256| 1| XCTestExpectation *expectation1 = [self expectationWithDescription:@"image 1 download should succeed"]; 257| 1| __block NSHTTPURLResponse *urlResponse1 = nil; 258| 1| __block UIImage *responseImage1 = nil; 259| 1| 260| 1| [self.downloader 261| 1| downloadImageForURLRequest:self.pngRequest 262| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 263| 1| urlResponse1 = response; 264| 1| responseImage1 = responseObject; 265| 1| [expectation1 fulfill]; 266| 1| } 267| 1| failure:nil]; 268| 1| 269| 1| [self waitForExpectationsWithCommonTimeout]; 270| 1| 271| 1| XCTestExpectation *expectation2 = [self expectationWithDescription:@"image 2 download should succeed"]; 272| 1| __block NSHTTPURLResponse *urlResponse2 = nil; 273| 1| __block UIImage *responseImage2 = nil; 274| 1| 275| 1| [self.downloader 276| 1| downloadImageForURLRequest:self.pngRequest 277| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 278| 1| urlResponse2 = response; 279| 1| responseImage2 = responseObject; 280| 1| [expectation2 fulfill]; 281| 1| } 282| 1| failure:nil]; 283| 1| 284| 1| [self waitForExpectationsWithCommonTimeout]; 285| 1| 286| 1| XCTAssertNotNil(urlResponse1); 287| 1| XCTAssertNotNil(responseImage1); 288| 1| XCTAssertNil(urlResponse2); 289| 1| XCTAssertEqual(responseImage1, responseImage2); 290| 1|} 291| | 292| 1|- (void)testThatImageCacheIsPromptedShouldCacheNot { 293| 1| XCTestExpectation *expectation3 = [self expectationWithDescription:@"image 1 shouldCache called"]; 294| 1| 295| 1| MockAFAutoPurgingImageCache *mock = [[MockAFAutoPurgingImageCache alloc] init]; 296| 1| mock.shouldCache = ^BOOL(UIImage *img, NSURLRequest *req, NSString *iden) { 297| 1| [expectation3 fulfill]; 298| 1| return NO; 299| 1| }; 300| 1| mock.addCache = ^(UIImage *img, NSString *ident) { 301| 0| XCTFail(@"Not expected"); 302| 0| }; 303| 1| self.downloader.imageCache = mock; 304| 1| 305| 1| XCTestExpectation *expectation1 = [self expectationWithDescription:@"image 1 download should succeed"]; 306| 1| __block NSHTTPURLResponse *urlResponse1 = nil; 307| 1| __block UIImage *responseImage1 = nil; 308| 1| 309| 1| [self.downloader 310| 1| downloadImageForURLRequest:self.pngRequest 311| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 312| 1| urlResponse1 = response; 313| 1| responseImage1 = responseObject; 314| 1| [expectation1 fulfill]; 315| 1| } 316| 1| failure:nil]; 317| 1| 318| 1| [self waitForExpectationsWithCommonTimeout]; 319| 1| 320| 1| XCTestExpectation *expectation2 = [self expectationWithDescription:@"image 2 download should succeed"]; 321| 1| __block NSHTTPURLResponse *urlResponse2 = nil; 322| 1| __block UIImage *responseImage2 = nil; 323| 1| 324| 1| XCTestExpectation *expectation5 = [self expectationWithDescription:@"image 2 shouldCache called"]; 325| 1| 326| 1| mock.shouldCache = ^BOOL(UIImage *img, NSURLRequest *req, NSString *iden) { 327| 1| [expectation5 fulfill]; 328| 1| return NO; 329| 1| }; 330| 1| 331| 1| [self.downloader 332| 1| downloadImageForURLRequest:self.pngRequest 333| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 334| 1| urlResponse2 = response; 335| 1| responseImage2 = responseObject; 336| 1| [expectation2 fulfill]; 337| 1| } 338| 1| failure:nil]; 339| 1| 340| 1| [self waitForExpectationsWithCommonTimeout]; 341| 1| 342| 1| XCTAssertNotNil(urlResponse1); 343| 1| XCTAssertNotNil(responseImage1); 344| 1| XCTAssertNotNil(urlResponse2); 345| 1| XCTAssertNotEqual(responseImage1, responseImage2); 346| 1|} 347| | 348| 1|- (void)testThatImageDownloadReceiptIsNilForCachedImage { 349| 1| XCTestExpectation *expectation1 = [self expectationWithDescription:@"image 1 download should succeed"]; 350| 1| AFImageDownloadReceipt *receipt1; 351| 1| receipt1 = [self.downloader 352| 1| downloadImageForURLRequest:self.pngRequest 353| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 354| 1| [expectation1 fulfill]; 355| 1| } 356| 1| failure:nil]; 357| 1| 358| 1| [self waitForExpectationsWithCommonTimeout]; 359| 1| 360| 1| XCTestExpectation *expectation2 = [self expectationWithDescription:@"image 2 download should succeed"]; 361| 1| 362| 1| AFImageDownloadReceipt *receipt2; 363| 1| receipt2 = [self.downloader 364| 1| downloadImageForURLRequest:self.pngRequest 365| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 366| 1| [expectation2 fulfill]; 367| 1| } 368| 1| failure:nil]; 369| 1| 370| 1| [self waitForExpectationsWithCommonTimeout]; 371| 1| 372| 1| XCTAssertNotNil(receipt1); 373| 1| XCTAssertNil(receipt2); 374| 1|} 375| | 376| 1|- (void)testThatCacheIsIgnoredIfCacheIgnoredInRequest { 377| 1| XCTestExpectation *expectation1 = [self expectationWithDescription:@"image 1 download should succeed"]; 378| 1| 379| 1| __block NSHTTPURLResponse *urlResponse1 = nil; 380| 1| __block UIImage *responseImage1 = nil; 381| 1| AFImageDownloadReceipt *receipt1; 382| 1| receipt1 = [self.downloader 383| 1| downloadImageForURLRequest:self.pngRequest 384| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 385| 1| urlResponse1 = response; 386| 1| responseImage1 = responseObject; 387| 1| [expectation1 fulfill]; 388| 1| } 389| 1| failure:nil]; 390| 1| 391| 1| [self waitForExpectationsWithCommonTimeout]; 392| 1| 393| 1| XCTestExpectation *expectation2 = [self expectationWithDescription:@"image 2 download should succeed"]; 394| 1| NSMutableURLRequest *alteredRequest = [self.pngRequest mutableCopy]; 395| 1| alteredRequest.cachePolicy = NSURLRequestReloadIgnoringLocalCacheData; 396| 1| 397| 1| AFImageDownloadReceipt *receipt2; 398| 1| __block NSHTTPURLResponse *urlResponse2 = nil; 399| 1| __block UIImage *responseImage2 = nil; 400| 1| receipt2 = [self.downloader 401| 1| downloadImageForURLRequest:alteredRequest 402| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 403| 1| urlResponse2 = response; 404| 1| responseImage2 = responseObject; 405| 1| [expectation2 fulfill]; 406| 1| } 407| 1| failure:nil]; 408| 1| 409| 1| [self waitForExpectationsWithCommonTimeout]; 410| 1| 411| 1| XCTAssertNotNil(receipt1); 412| 1| XCTAssertNotNil(receipt2); 413| 1| XCTAssertNotEqual(receipt1, receipt2); 414| 1| 415| 1| XCTAssertNotNil(urlResponse1); 416| 1| XCTAssertNotNil(responseImage1); 417| 1| 418| 1| XCTAssertNotNil(urlResponse2); 419| 1| XCTAssertNotNil(responseImage2); 420| 1| 421| 1| XCTAssertNotEqual(responseImage1, responseImage2); 422| 1|} 423| | 424| |#pragma mark - Cancellation 425| | 426| 1|- (void)testThatCancellingDownloadCallsCompletionWithCancellationError { 427| 1| AFImageDownloadReceipt *receipt; 428| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"image download should fail"]; 429| 1| __block NSError *responseError = nil; 430| 1| receipt = [self.downloader 431| 1| downloadImageForURLRequest:self.pngRequest 432| 1| success:nil 433| 1| failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) { 434| 1| responseError = error; 435| 1| [expectation fulfill]; 436| 1| }]; 437| 1| [self.downloader cancelTaskForImageDownloadReceipt:receipt]; 438| 1| [self waitForExpectationsWithCommonTimeout]; 439| 1| 440| 1| XCTAssertTrue(responseError.code == NSURLErrorCancelled); 441| 1| XCTAssertTrue([responseError.domain isEqualToString:NSURLErrorDomain]); 442| 1|} 443| | 444| 1|- (void)testThatCancellingDownloadWithMultipleResponseHandlersCancelsFirstYetAllowsSecondToComplete { 445| 1| XCTestExpectation *expectation1 = [self expectationWithDescription:@"image 1 download should succeed"]; 446| 1| __block NSHTTPURLResponse *urlResponse = nil; 447| 1| __block UIImage *responseImage = nil; 448| 1| 449| 1| [self.downloader 450| 1| downloadImageForURLRequest:self.pngRequest 451| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 452| 1| urlResponse = response; 453| 1| responseImage = responseObject; 454| 1| [expectation1 fulfill]; 455| 1| } 456| 1| failure:nil]; 457| 1| 458| 1| XCTestExpectation *expectation2 = [self expectationWithDescription:@"image 2 download should fail"]; 459| 1| __block NSError *responseError = nil; 460| 1| AFImageDownloadReceipt *receipt; 461| 1| receipt = [self.downloader 462| 1| downloadImageForURLRequest:self.pngRequest 463| 1| success:nil 464| 1| failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) { 465| 1| responseError = error; 466| 1| [expectation2 fulfill]; 467| 1| }]; 468| 1| [self.downloader cancelTaskForImageDownloadReceipt:receipt]; 469| 1| [self waitForExpectationsWithCommonTimeout]; 470| 1| 471| 1| XCTAssertTrue(responseError.code == NSURLErrorCancelled); 472| 1| XCTAssertTrue([responseError.domain isEqualToString:NSURLErrorDomain]); 473| 1| XCTAssertNotNil(urlResponse); 474| 1| XCTAssertNotNil(responseImage); 475| 1|} 476| | 477| 1|- (void)testThatItCanDownloadAndCancelAndDownloadAgain { 478| 1| NSArray *imageURLStrings = @[ 479| 1| @"https://secure.gravatar.com/avatar/5a105e8b9d40e1329780d62ea2265d8a?d=identicon", 480| 1| @"https://secure.gravatar.com/avatar/6a105e8b9d40e1329780d62ea2265d8a?d=identicon", 481| 1| @"https://secure.gravatar.com/avatar/7a105e8b9d40e1329780d62ea2265d8a?d=identicon", 482| 1| @"https://secure.gravatar.com/avatar/8a105e8b9d40e1329780d62ea2265d8a?d=identicon", 483| 1| @"https://secure.gravatar.com/avatar/9a105e8b9d40e1329780d62ea2265d8a?d=identicon" 484| 1| ]; 485| 1| 486| 5| for (NSString *imageURLString in imageURLStrings) { 487| 5| XCTestExpectation *expectation = [self expectationWithDescription:[NSString stringWithFormat:@"Request %@ should be cancelled", imageURLString]]; 488| 5| AFImageDownloadReceipt *receipt = [self.downloader 489| 5| downloadImageForURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:imageURLString]] 490| 5| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 491| 0| XCTFail(@"Request %@ succeeded when it should have failed", request); 492| 0| } 493| 5| failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) { 494| 5| XCTAssertTrue([error.domain isEqualToString:NSURLErrorDomain]); 495| 5| XCTAssertTrue([error code] == NSURLErrorCancelled); 496| 5| [expectation fulfill]; 497| 5| }]; 498| 5| [self.downloader cancelTaskForImageDownloadReceipt:receipt]; 499| 5| } 500| 1| 501| 5| for (NSString *imageURLString in imageURLStrings) { 502| 5| XCTestExpectation *expectation = [self expectationWithDescription:[NSString stringWithFormat:@"Request %@ should succeed", imageURLString]]; 503| 5| [self.downloader 504| 5| downloadImageForURLRequest:[NSURLRequest requestWithURL:[NSURL URLWithString:imageURLString]] 505| 5| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 506| 5| [expectation fulfill]; 507| 5| } failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) { 508| 0| XCTFail(@"Request %@ failed with error %@", request, error); 509| 0| }]; 510| 5| } 511| 1| 512| 1| [self waitForExpectationsWithCommonTimeout]; 513| 1|} 514| | 515| |#pragma mark - Threading 516| 1|- (void)testThatItAlwaysCallsTheSuccessHandlerOnTheMainQueue { 517| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"image download should succeed"]; 518| 1| __block BOOL successIsOnMainThread = false; 519| 1| [self.downloader 520| 1| downloadImageForURLRequest:self.pngRequest 521| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 522| 1| successIsOnMainThread = [[NSThread currentThread] isMainThread]; 523| 1| [expectation fulfill]; 524| 1| } 525| 1| failure:nil]; 526| 1| [self waitForExpectationsWithCommonTimeout]; 527| 1| XCTAssertTrue(successIsOnMainThread); 528| 1|} 529| | 530| 1|- (void)testThatItAlwaysCallsTheFailureHandlerOnTheMainQueue { 531| 1| NSURLRequest *notFoundRequest = [NSURLRequest requestWithURL:[self URLWithStatusCode:404]]; 532| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"image download should fail"]; 533| 1| __block BOOL failureIsOnMainThread = false; 534| 1| [self.downloader 535| 1| downloadImageForURLRequest:notFoundRequest 536| 1| success:nil 537| 1| failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) { 538| 1| failureIsOnMainThread = [[NSThread currentThread] isMainThread]; 539| 1| [expectation fulfill]; 540| 1| }]; 541| 1| [self waitForExpectationsWithCommonTimeout]; 542| 1| XCTAssertTrue(failureIsOnMainThread); 543| 1|} 544| | 545| |#pragma mark - misc 546| | 547| 1|- (void)testThatReceiptIDMatchesReturnedID { 548| 1| NSUUID *receiptId = [NSUUID UUID]; 549| 1| AFImageDownloadReceipt *receipt = [self.downloader 550| 1| downloadImageForURLRequest:self.jpegRequest 551| 1| withReceiptID:receiptId 552| 1| success:nil 553| 1| failure:nil]; 554| 1| XCTAssertEqual(receiptId, receipt.receiptID); 555| 1| [self.downloader cancelTaskForImageDownloadReceipt:receipt]; 556| 1|} 557| | 558| |@end 559| | 560| |#pragma mark - 561| | 562| |@implementation MockAFAutoPurgingImageCache 563| | 564| 3|- (BOOL)shouldCacheImage:(UIImage *)image forRequest:(NSURLRequest *)request withAdditionalIdentifier:(NSString *)identifier { 565| 3| if (self.shouldCache) { 566| 3| return self.shouldCache(image, request, identifier); 567| 3| } 568| 0| else { 569| 0| return [super shouldCacheImage:image forRequest:request withAdditionalIdentifier:identifier]; 570| 0| } 571| 3|} 572| | 573| 1|- (void)addImage:(UIImage *)image withIdentifier:(NSString *)identifier{ 574| 1| [super addImage:image withIdentifier:identifier]; 575| 1| if (self.addCache) { 576| 1| self.addCache(image, identifier); 577| 1| } 578| 1|} 579| |@end /Users/travis/build/AFNetworking/AFNetworking/Tests/Tests/AFImageResponseSerializerTests.m: 1| |// AFImageResponseSerializerTests.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation (http://alamofire.org/) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import 23| |#import "AFTestCase.h" 24| |#import "AFURLResponseSerialization.h" 25| | 26| |@interface AFImageResponseSerializerTests : AFTestCase 27| | 28| |@end 29| | 30| |@implementation AFImageResponseSerializerTests 31| | 32| |#pragma mark NSCopying 33| | 34| 1|- (void)testImageSerializerCanBeCopied { 35| 1| AFImageResponseSerializer *responseSerializer = [AFImageResponseSerializer serializer]; 36| 1| [responseSerializer setAcceptableContentTypes:[NSSet setWithObject:@"test/type"]]; 37| 1| [responseSerializer setAcceptableStatusCodes:[NSIndexSet indexSetWithIndex:100]]; 38| 1| 39| 1| AFImageResponseSerializer *copiedSerializer = [responseSerializer copy]; 40| 1| XCTAssertNotNil(copiedSerializer); 41| 1| XCTAssertNotEqual(copiedSerializer, responseSerializer); 42| 1| XCTAssertEqual(copiedSerializer.acceptableContentTypes, responseSerializer.acceptableContentTypes); 43| 1| XCTAssertEqual(copiedSerializer.acceptableStatusCodes, responseSerializer.acceptableStatusCodes); 44| 1|#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH 45| 1| XCTAssertTrue(copiedSerializer.automaticallyInflatesResponseImage == responseSerializer.automaticallyInflatesResponseImage); 46| 1| XCTAssertTrue(fabs(copiedSerializer.imageScale - responseSerializer.imageScale) <= 0.001); 47| 1|#endif 48| 1| 49| 1|} 50| | 51| |#pragma mark NSSecureCoding 52| | 53| 1|- (void)testImageSerializerSupportsSecureCoding { 54| 1| XCTAssertTrue([AFImageResponseSerializer supportsSecureCoding]); 55| 1|} 56| | 57| 1|- (void)testImageSerializerCanBeArchivedAndUnarchived { 58| 1| AFImageResponseSerializer *responseSerializer = [AFImageResponseSerializer serializer]; 59| 1| NSData *archive = nil; 60| 1| 61| 1| archive = [NSKeyedArchiver archivedDataWithRootObject:responseSerializer]; 62| 1| XCTAssertNotNil(archive); 63| 1| AFImageResponseSerializer *unarchivedSerializer = [NSKeyedUnarchiver unarchiveObjectWithData:archive]; 64| 1| XCTAssertNotNil(unarchivedSerializer); 65| 1| XCTAssertNotEqual(unarchivedSerializer, responseSerializer); 66| 1| XCTAssertTrue([unarchivedSerializer.acceptableContentTypes isEqualToSet:responseSerializer.acceptableContentTypes]); 67| 1| XCTAssertTrue([unarchivedSerializer.acceptableStatusCodes isEqualToIndexSet:responseSerializer.acceptableStatusCodes]); 68| 1| 69| 1|#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH 70| 1| XCTAssertTrue(unarchivedSerializer.automaticallyInflatesResponseImage == responseSerializer.automaticallyInflatesResponseImage); 71| 1| XCTAssertTrue(fabs(unarchivedSerializer.imageScale - responseSerializer.imageScale) <= 0.001); 72| 1|#endif 73| 1| 74| 1|} 75| | 76| 1|- (void)testImageSerializerCanBeArchivedAndUnarchivedWithNonDefaultPropertyValues { 77| 1| AFImageResponseSerializer *responseSerializer = [AFImageResponseSerializer serializer]; 78| 1| NSData *archive = nil; 79| 1| 80| 1| // Customize the default property values 81| 1|#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH 82| 1| responseSerializer.automaticallyInflatesResponseImage = !responseSerializer.automaticallyInflatesResponseImage; 83| 1| responseSerializer.imageScale = responseSerializer.imageScale * 2.0f; 84| 1|#endif 85| 1| 86| 1| archive = [NSKeyedArchiver archivedDataWithRootObject:responseSerializer]; 87| 1| XCTAssertNotNil(archive); 88| 1| AFImageResponseSerializer *unarchivedSerializer = [NSKeyedUnarchiver unarchiveObjectWithData:archive]; 89| 1| XCTAssertNotNil(unarchivedSerializer); 90| 1| XCTAssertNotEqual(unarchivedSerializer, responseSerializer); 91| 1| 92| 1|#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH 93| 1| XCTAssertTrue(unarchivedSerializer.automaticallyInflatesResponseImage == responseSerializer.automaticallyInflatesResponseImage); 94| 1| XCTAssertTrue(fabs(unarchivedSerializer.imageScale - responseSerializer.imageScale) <= 0.001); 95| 1|#endif 96| 1|} 97| | 98| |@end /Users/travis/build/AFNetworking/AFNetworking/Tests/Tests/AFJSONSerializationTests.m: 1| |// AFJSONSerializationTests.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "AFTestCase.h" 23| | 24| |#import "AFURLRequestSerialization.h" 25| |#import "AFURLResponseSerialization.h" 26| | 27| 5|static NSData * AFJSONTestData() { 28| 5| return [NSJSONSerialization dataWithJSONObject:@{@"foo": @"bar"} options:(NSJSONWritingOptions)0 error:nil]; 29| 5|} 30| | 31| |#pragma mark - 32| | 33| |@interface AFJSONRequestSerializationTests : AFTestCase 34| |@property (nonatomic, strong) AFJSONRequestSerializer *requestSerializer; 35| |@end 36| | 37| |@implementation AFJSONRequestSerializationTests 38| | 39| 4|- (void)setUp { 40| 4| self.requestSerializer = [[AFJSONRequestSerializer alloc] init]; 41| 4|} 42| | 43| |#pragma mark - 44| | 45| 1|- (void)testThatJSONRequestSerializationHandlesParametersDictionary { 46| 1| NSDictionary *parameters = @{@"key":@"value"}; 47| 1| NSError *error = nil; 48| 1| NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"POST" URLString:self.baseURL.absoluteString parameters:parameters error:&error]; 49| 1| 50| 1| XCTAssertNil(error, @"Serialization error should be nil"); 51| 1| 52| 1| NSString *body = [[NSString alloc] initWithData:[request HTTPBody] encoding:NSUTF8StringEncoding]; 53| 1| 54| 1| XCTAssertTrue([@"{\"key\":\"value\"}" isEqualToString:body], @"Parameters were not encoded correctly"); 55| 1|} 56| | 57| 1|- (void)testThatJSONRequestSerializationHandlesParametersArray { 58| 1| NSArray *parameters = @[@{@"key":@"value"}]; 59| 1| NSError *error = nil; 60| 1| NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"POST" URLString:self.baseURL.absoluteString parameters:parameters error:&error]; 61| 1| 62| 1| XCTAssertNil(error, @"Serialization error should be nil"); 63| 1| 64| 1| NSString *body = [[NSString alloc] initWithData:[request HTTPBody] encoding:NSUTF8StringEncoding]; 65| 1| 66| 1| XCTAssertTrue([@"[{\"key\":\"value\"}]" isEqualToString:body], @"Parameters were not encoded correctly"); 67| 1|} 68| | 69| 1|- (void)testThatJSONRequestSerializationHandlesInvalidParameters { 70| 1| NSString *string = [[NSString alloc] initWithBytes:"\xd8\x00" length:2 encoding:NSUTF16StringEncoding]; 71| 1| 72| 1| NSDictionary *parameters = @{@"key":string}; 73| 1| NSError *error = nil; 74| 1| NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"POST" URLString:self.baseURL.absoluteString parameters:parameters error:&error]; 75| 1| 76| 1| XCTAssertNil(request, @"Expected nil request."); 77| 1| XCTAssertNotNil(error, @"Expected non-nil error."); 78| 1|} 79| | 80| 1|- (void)testThatJSONRequestSerializationErrorsWithInvalidJSON { 81| 1| NSDictionary *parameters = @{@"key":[NSSet setWithObject:@"value"]}; 82| 1| NSError *error = nil; 83| 1| NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"POST" URLString:self.baseURL.absoluteString parameters:parameters error:&error]; 84| 1| 85| 1| XCTAssertNil(request, @"Request should be nil"); 86| 1| XCTAssertNotNil(error, @"Serialization error should be not nil"); 87| 1| XCTAssertEqualObjects(error.domain, AFURLRequestSerializationErrorDomain); 88| 1| XCTAssertEqual(error.code, NSURLErrorCannotDecodeContentData); 89| 1| XCTAssertEqualObjects(error.localizedFailureReason, @"The `parameters` argument is not valid JSON."); 90| 1|} 91| | 92| |@end 93| | 94| |#pragma mark - 95| | 96| |@interface AFJSONResponseSerializationTests : AFTestCase 97| |@property (nonatomic, strong) AFJSONResponseSerializer *responseSerializer; 98| |@end 99| | 100| |@implementation AFJSONResponseSerializationTests 101| | 102| 10|- (void)setUp { 103| 10| [super setUp]; 104| 10| self.responseSerializer = [AFJSONResponseSerializer serializer]; 105| 10|} 106| | 107| |#pragma mark - 108| | 109| 1|- (void)testThatJSONResponseSerializerAcceptsApplicationJSONMimeType { 110| 1| NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.baseURL statusCode:200 HTTPVersion:@"1.1" headerFields:@{@"Content-Type": @"application/json"}]; 111| 1| 112| 1| NSError *error = nil; 113| 1| [self.responseSerializer validateResponse:response data:AFJSONTestData() error:&error]; 114| 1| 115| 1| XCTAssertNil(error, @"Error handling application/json"); 116| 1|} 117| | 118| 1|- (void)testThatJSONResponseSerializerAcceptsTextJSONMimeType { 119| 1| NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.baseURL statusCode:200 HTTPVersion:@"1.1" headerFields:@{@"Content-Type": @"text/json"}]; 120| 1| NSError *error = nil; 121| 1| [self.responseSerializer validateResponse:response data:AFJSONTestData()error:&error]; 122| 1| 123| 1| XCTAssertNil(error, @"Error handling text/json"); 124| 1|} 125| | 126| 1|- (void)testThatJSONResponseSerializerAcceptsTextJavaScriptMimeType { 127| 1| NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.baseURL statusCode:200 HTTPVersion:@"1.1" headerFields:@{@"Content-Type": @"text/javascript"}]; 128| 1| NSError *error = nil; 129| 1| [self.responseSerializer validateResponse:response data:AFJSONTestData() error:&error]; 130| 1| 131| 1| XCTAssertNil(error, @"Error handling text/javascript"); 132| 1|} 133| | 134| 1|- (void)testThatJSONResponseSerializerDoesNotAcceptNonStandardJSONMimeType { 135| 1| NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.baseURL statusCode:200 HTTPVersion:@"1.1" headerFields:@{@"Content-Type": @"nonstandard/json"}]; 136| 1| NSError *error = nil; 137| 1| [self.responseSerializer validateResponse:response data:AFJSONTestData() error:&error]; 138| 1| 139| 1| XCTAssertNotNil(error, @"Error should have been thrown for nonstandard/json"); 140| 1|} 141| | 142| 1|- (void)testThatJSONResponseSerializerReturnsDictionaryForValidJSONDictionary { 143| 1| NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.baseURL statusCode:200 HTTPVersion:@"1.1" headerFields:@{@"Content-Type": @"text/json"}]; 144| 1| NSError *error = nil; 145| 1| id responseObject = [self.responseSerializer responseObjectForResponse:response data:AFJSONTestData() error:&error]; 146| 1| 147| 1| XCTAssertNil(error, @"Serialization error should be nil"); 148| 1| XCTAssert([responseObject isKindOfClass:[NSDictionary class]], @"Expected response to be a NSDictionary"); 149| 1|} 150| | 151| 1|- (void)testThatJSONResponseSerializerReturnsErrorForInvalidJSON { 152| 1| NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.baseURL statusCode:200 HTTPVersion:@"1.1" headerFields:@{@"Content-Type":@"text/json"}]; 153| 1| NSError *error = nil; 154| 1| [self.responseSerializer responseObjectForResponse:response data:[@"{invalid}" dataUsingEncoding:NSUTF8StringEncoding] error:&error]; 155| 1| 156| 1| XCTAssertNotNil(error, @"Serialization error should not be nil"); 157| 1|} 158| | 159| 1|- (void)testThatJSONResponseSerializerReturnsNilObjectAndNilErrorForEmptyData { 160| 1| NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.baseURL statusCode:200 HTTPVersion:@"1.1" headerFields:@{@"Content-Type":@"text/json"}]; 161| 1| NSData *data = [NSData data]; 162| 1| NSError *error = nil; 163| 1| id responseObject = [self.responseSerializer responseObjectForResponse:response data:data error:&error]; 164| 1| XCTAssertNil(responseObject); 165| 1| XCTAssertNil(error); 166| 1|} 167| | 168| 1|- (void)testThatJSONResponseSerializerReturnsNilObjectAndNilErrorForSingleSpace { 169| 1| NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.baseURL statusCode:200 HTTPVersion:@"1.1" headerFields:@{@"Content-Type":@"text/json"}]; 170| 1| NSData *data = [@" " dataUsingEncoding:NSUTF8StringEncoding]; 171| 1| NSError *error = nil; 172| 1| id responseObject = [self.responseSerializer responseObjectForResponse:response data:data error:&error]; 173| 1| XCTAssertNil(responseObject); 174| 1| XCTAssertNil(error); 175| 1|} 176| | 177| 1|- (void)testThatJSONRemovesKeysWithNullValues { 178| 1| self.responseSerializer.removesKeysWithNullValues = YES; 179| 1| NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.baseURL statusCode:200 HTTPVersion:@"1.1" headerFields:@{@"Content-Type":@"text/json"}]; 180| 1| NSData *data = [NSJSONSerialization dataWithJSONObject:@{@"key":@"value",@"nullkey":[NSNull null],@"array":@[@{@"subnullkey":[NSNull null]}], @"arrayWithNulls": @[[NSNull null]]} 181| 1| options:(NSJSONWritingOptions)0 182| 1| error:nil]; 183| 1| 184| 1| NSError *error = nil; 185| 1| NSDictionary *responseObject = [self.responseSerializer responseObjectForResponse:response 186| 1| data:data 187| 1| error:&error]; 188| 1| XCTAssertNil(error); 189| 1| XCTAssertNotNil(responseObject[@"key"]); 190| 1| XCTAssertNil(responseObject[@"nullkey"]); 191| 1| XCTAssertNil(responseObject[@"array"][0][@"subnullkey"]); 192| 1| XCTAssertEqualObjects(responseObject[@"arrayWithNulls"], @[]); 193| 1|} 194| | 195| 1|- (void)testThatJSONResponseSerializerCanBeCopied { 196| 1| [self.responseSerializer setAcceptableStatusCodes:[NSIndexSet indexSetWithIndex:100]]; 197| 1| [self.responseSerializer setAcceptableContentTypes:[NSSet setWithObject:@"test/type"]]; 198| 1| [self.responseSerializer setReadingOptions:NSJSONReadingMutableLeaves]; 199| 1| [self.responseSerializer setRemovesKeysWithNullValues:YES]; 200| 1| 201| 1| AFJSONResponseSerializer *copiedSerializer = [self.responseSerializer copy]; 202| 1| XCTAssertNotEqual(copiedSerializer, self.responseSerializer); 203| 1| XCTAssertEqual(copiedSerializer.acceptableStatusCodes, self.responseSerializer.acceptableStatusCodes); 204| 1| XCTAssertEqual(copiedSerializer.acceptableContentTypes, self.responseSerializer.acceptableContentTypes); 205| 1| XCTAssertEqual(copiedSerializer.readingOptions, self.responseSerializer.readingOptions); 206| 1| XCTAssertEqual(copiedSerializer.removesKeysWithNullValues, self.responseSerializer.removesKeysWithNullValues); 207| 1|} 208| | 209| |@end /Users/travis/build/AFNetworking/AFNetworking/Tests/Tests/AFNetworkActivityManagerTests.m: 1| |// AFNetworkActivityManagerTests.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "AFTestCase.h" 23| | 24| |#import "AFNetworkActivityIndicatorManager.h" 25| |#import "AFHTTPSessionManager.h" 26| | 27| |@interface AFNetworkActivityManagerTests : AFTestCase 28| |@property (nonatomic, strong) AFNetworkActivityIndicatorManager *networkActivityIndicatorManager; 29| |@property (nonatomic, strong) AFHTTPSessionManager *sessionManager; 30| |@end 31| | 32| |#pragma mark - 33| | 34| |@implementation AFNetworkActivityManagerTests 35| | 36| 4|- (void)setUp { 37| 4| [super setUp]; 38| 4| 39| 4| self.sessionManager = [[AFHTTPSessionManager alloc] initWithBaseURL:self.baseURL sessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; 40| 4| 41| 4| self.networkActivityIndicatorManager = [[AFNetworkActivityIndicatorManager alloc] init]; 42| 4| self.networkActivityIndicatorManager.enabled = YES; 43| 4|} 44| | 45| 4|- (void)tearDown { 46| 4| [super tearDown]; 47| 4| self.networkActivityIndicatorManager = nil; 48| 4| 49| 4| [self.sessionManager invalidateSessionCancelingTasks:YES resetSession:NO]; 50| 4| self.sessionManager = nil; 51| 4|} 52| | 53| |#pragma mark - 54| | 55| 1|- (void)testThatNetworkActivityIndicatorTurnsOnAndOffIndicatorWhenRequestSucceeds { 56| 1| self.networkActivityIndicatorManager.activationDelay = 0.0; 57| 1| self.networkActivityIndicatorManager.completionDelay = 0.0; 58| 1| 59| 1| XCTestExpectation *startExpectation = [self expectationWithDescription:@"Indicator Visible"]; 60| 1| XCTestExpectation *endExpectation = [self expectationWithDescription:@"Indicator Hidden"]; 61| 2| [self.networkActivityIndicatorManager setNetworkingActivityActionWithBlock:^(BOOL networkActivityIndicatorVisible) { 62| 2| if (networkActivityIndicatorVisible) { 63| 1| [startExpectation fulfill]; 64| 1| } else { 65| 1| [endExpectation fulfill]; 66| 1| } 67| 2| }]; 68| 1| 69| 1| XCTestExpectation *requestExpectation = [self expectationWithDescription:@"Request should succeed"]; 70| 1| [self.sessionManager 71| 1| GET:@"/delay/1" 72| 1| parameters:nil 73| 1| headers:nil 74| 1| progress:nil 75| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) { 76| 1| [requestExpectation fulfill]; 77| 1| } 78| 1| failure:nil]; 79| 1| [self waitForExpectationsWithCommonTimeout]; 80| 1|} 81| | 82| 1|- (void)testThatNetworkActivityIndicatorTurnsOnAndOffIndicatorWhenRequestFails { 83| 1| self.networkActivityIndicatorManager.activationDelay = 0.0; 84| 1| self.networkActivityIndicatorManager.completionDelay = 0.0; 85| 1| 86| 1| XCTestExpectation *startExpectation = [self expectationWithDescription:@"Indicator Visible"]; 87| 1| XCTestExpectation *endExpectation = [self expectationWithDescription:@"Indicator Hidden"]; 88| 2| [self.networkActivityIndicatorManager setNetworkingActivityActionWithBlock:^(BOOL networkActivityIndicatorVisible) { 89| 2| if (networkActivityIndicatorVisible) { 90| 1| [startExpectation fulfill]; 91| 1| } else { 92| 1| [endExpectation fulfill]; 93| 1| } 94| 2| }]; 95| 1| 96| 1| XCTestExpectation *requestExpectation = [self expectationWithDescription:@"Request should fail"]; 97| 1| [self.sessionManager 98| 1| GET:@"/status/404" 99| 1| parameters:nil 100| 1| headers:nil 101| 1| progress:nil 102| 1| success:nil 103| 1| failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) { 104| 1| [requestExpectation fulfill]; 105| 1| }]; 106| 1| [self waitForExpectationsWithCommonTimeout]; 107| 1|} 108| | 109| 1|- (void)testThatVisibilityDelaysAreApplied { 110| 1| 111| 1| self.networkActivityIndicatorManager.activationDelay = 1.0; 112| 1| self.networkActivityIndicatorManager.completionDelay = 1.0; 113| 1| 114| 1| CFTimeInterval requestStartTime = CACurrentMediaTime(); 115| 1| __block CFTimeInterval requestEndTime; 116| 1| __block CFTimeInterval indicatorVisbleTime; 117| 1| __block CFTimeInterval indicatorHiddenTime; 118| 1| XCTestExpectation *startExpectation = [self expectationWithDescription:@"Indicator Visible"]; 119| 1| XCTestExpectation *endExpectation = [self expectationWithDescription:@"Indicator Hidden"]; 120| 2| [self.networkActivityIndicatorManager setNetworkingActivityActionWithBlock:^(BOOL networkActivityIndicatorVisible) { 121| 2| if (networkActivityIndicatorVisible) { 122| 1| indicatorVisbleTime = CACurrentMediaTime(); 123| 1| [startExpectation fulfill]; 124| 1| } else { 125| 1| indicatorHiddenTime = CACurrentMediaTime(); 126| 1| [endExpectation fulfill]; 127| 1| } 128| 2| }]; 129| 1| 130| 1| XCTestExpectation *requestExpectation = [self expectationWithDescription:@"Request should succeed"]; 131| 1| [self.sessionManager 132| 1| GET:@"/delay/2" 133| 1| parameters:nil 134| 1| headers:nil 135| 1| progress:nil 136| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) { 137| 1| requestEndTime = CACurrentMediaTime(); 138| 1| [requestExpectation fulfill]; 139| 1| } 140| 1| failure:nil]; 141| 1| [self waitForExpectationsWithCommonTimeout]; 142| 1| XCTAssertTrue((indicatorVisbleTime - requestStartTime) > self.networkActivityIndicatorManager.activationDelay); 143| 1| XCTAssertTrue((indicatorHiddenTime - requestEndTime) > self.networkActivityIndicatorManager.completionDelay); 144| 1|} 145| | 146| 1|- (void)testThatIndicatorBlockIsOnlyCalledOnceEachForStartAndEndForMultipleRequests { 147| 1| self.networkActivityIndicatorManager.activationDelay = 1.0; 148| 1| self.networkActivityIndicatorManager.completionDelay = 1.0; 149| 1| 150| 1| XCTestExpectation *startExpectation = [self expectationWithDescription:@"Indicator Visible"]; 151| 1| XCTestExpectation *endExpectation = [self expectationWithDescription:@"Indicator Hidden"]; 152| 2| [self.networkActivityIndicatorManager setNetworkingActivityActionWithBlock:^(BOOL networkActivityIndicatorVisible) { 153| 2| if (networkActivityIndicatorVisible) { 154| 1| [startExpectation fulfill]; 155| 1| } else { 156| 1| [endExpectation fulfill]; 157| 1| } 158| 2| }]; 159| 1| 160| 1| XCTestExpectation *requestExpectation = [self expectationWithDescription:@"Request should succeed"]; 161| 1| [self.sessionManager 162| 1| GET:@"/delay/4" 163| 1| parameters:nil 164| 1| headers:nil 165| 1| progress:nil 166| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) { 167| 1| [requestExpectation fulfill]; 168| 1| } 169| 1| failure:nil]; 170| 1| 171| 1| XCTestExpectation *secondRequestExpectation = [self expectationWithDescription:@"Request should succeed"]; 172| 1| [self.sessionManager 173| 1| GET:@"/delay/2" 174| 1| parameters:nil 175| 1| headers:nil 176| 1| progress:nil 177| 1| success:^(NSURLSessionDataTask * _Nonnull task, id _Nonnull responseObject) { 178| 1| 179| 1| [secondRequestExpectation fulfill]; 180| 1| } 181| 1| failure:nil]; 182| 1| 183| 1| [self waitForExpectationsWithCommonTimeout]; 184| 1| 185| 1|} 186| | 187| |@end /Users/travis/build/AFNetworking/AFNetworking/Tests/Tests/AFNetworkReachabilityManagerTests.m: 1| |// AFNetworkReachabilityManagerTests.h 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "AFTestCase.h" 23| | 24| |#import "AFNetworkReachabilityManager.h" 25| |#import 26| |#import 27| | 28| |@interface AFNetworkReachabilityManagerTests : AFTestCase 29| |@property (nonatomic, strong) AFNetworkReachabilityManager *addressReachability; 30| |@property (nonatomic, strong) AFNetworkReachabilityManager *domainReachability; 31| |@end 32| | 33| |@implementation AFNetworkReachabilityManagerTests 34| | 35| 9|- (void)setUp { 36| 9| [super setUp]; 37| 9| 38| 9| //both of these manager objects should always be reachable when the tests are run 39| 9| self.domainReachability = [AFNetworkReachabilityManager managerForDomain:@"localhost"]; 40| 9| self.addressReachability = [AFNetworkReachabilityManager manager]; 41| 9|} 42| | 43| |- (void)tearDown 44| 9|{ 45| 9| [self.addressReachability stopMonitoring]; 46| 9| [self.domainReachability stopMonitoring]; 47| 9| 48| 9| [super tearDown]; 49| 9|} 50| | 51| 1|- (void)testInitializerThrowsExceptionWhenCalled { 52| 1| AFNetworkReachabilityManager *manager = [AFNetworkReachabilityManager alloc]; 53| 1| id (*custom_msgSend)(id, SEL) = (id(*)(id, SEL))objc_msgSend; 54| 1| 55| 1| XCTAssertThrows(custom_msgSend(manager, @selector(init))); 56| 1|} 57| | 58| 1|- (void)testNewThrowsExceptionWhenCalled { 59| 1| id (*custom_msgSend)(id, SEL) = (id(*)(id, SEL))objc_msgSend; 60| 1| 61| 1| XCTAssertThrows(custom_msgSend([AFNetworkReachabilityManager class], 62| 1| @selector(new))); 63| 1|} 64| | 65| 1|- (void)testAddressReachabilityStartsInUnknownState { 66| 1| XCTAssertEqual(self.addressReachability.networkReachabilityStatus, AFNetworkReachabilityStatusUnknown, 67| 1| @"Reachability should start in an unknown state"); 68| 1|} 69| | 70| 1|- (void)testDomainReachabilityStartsInUnknownState { 71| 1| XCTAssertEqual(self.domainReachability.networkReachabilityStatus, AFNetworkReachabilityStatusUnknown, 72| 1| @"Reachability should start in an unknown state"); 73| 1|} 74| | 75| |- (void)verifyReachabilityNotificationGetsPostedWithManager:(AFNetworkReachabilityManager *)manager 76| 2|{ 77| 2| [self expectationForNotification:AFNetworkingReachabilityDidChangeNotification 78| 2| object:nil 79| 2| handler:^BOOL(NSNotification *note) { 80| 2| AFNetworkReachabilityStatus status; 81| 2| status = [note.userInfo[AFNetworkingReachabilityNotificationStatusItem] integerValue]; 82| 2| BOOL isReachable = (status == AFNetworkReachabilityStatusReachableViaWiFi 83| 2| || status == AFNetworkReachabilityStatusReachableViaWWAN); 84| 2| return isReachable; 85| 2| }]; 86| 2| 87| 2| [manager startMonitoring]; 88| 2| 89| 2| [self waitForExpectationsWithCommonTimeout]; 90| 2|} 91| | 92| 1|- (void)testAddressReachabilityNotification { 93| 1| [self verifyReachabilityNotificationGetsPostedWithManager:self.addressReachability]; 94| 1|} 95| | 96| 1|- (void)testDomainReachabilityNotification { 97| 1| [self verifyReachabilityNotificationGetsPostedWithManager:self.domainReachability]; 98| 1|} 99| | 100| |- (void)verifyReachabilityStatusBlockGetsCalledWithManager:(AFNetworkReachabilityManager *)manager 101| 2|{ 102| 2| __weak __block XCTestExpectation *expectation = [self expectationWithDescription:@"reachability status change block gets called"]; 103| 2| 104| 2| [manager setReachabilityStatusChangeBlock:^(AFNetworkReachabilityStatus status) { 105| 2| BOOL isReachable = (status == AFNetworkReachabilityStatusReachableViaWiFi 106| 2| || status == AFNetworkReachabilityStatusReachableViaWWAN); 107| 2| if (isReachable) { 108| 2| [expectation fulfill]; 109| 2| expectation = nil; 110| 2| } 111| 2| }]; 112| 2| 113| 2| [manager startMonitoring]; 114| 2| 115| 2| [self waitForExpectationsWithCommonTimeout]; 116| 2| [manager setReachabilityStatusChangeBlock:nil]; 117| 2| 118| 2|} 119| | 120| 1|- (void)testAddressReachabilityBlock { 121| 1| [self verifyReachabilityStatusBlockGetsCalledWithManager:self.addressReachability]; 122| 1|} 123| | 124| 1|- (void)testDomainReachabilityBlock { 125| 1| [self verifyReachabilityStatusBlockGetsCalledWithManager:self.domainReachability]; 126| 1|} 127| | 128| 1|- (void)testObjectPostingReachabilityManagerNotification { 129| 1| [self expectationForNotification:AFNetworkingReachabilityDidChangeNotification 130| 1| object:self.domainReachability 131| 1| handler:^BOOL(NSNotification *notification) { 132| 1| BOOL isObjectPostingNotification = [notification.object isEqual:self.domainReachability]; 133| 1| return isObjectPostingNotification; 134| 1| }]; 135| 1| 136| 1| [self.domainReachability startMonitoring]; 137| 1| 138| 1| [self waitForExpectationsWithCommonTimeout]; 139| 1|} 140| | 141| |@end /Users/travis/build/AFNetworking/AFNetworking/Tests/Tests/AFPropertyListRequestSerializerTests.m: 1| |// AFPropertyListRequestSerializerTests.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "AFTestCase.h" 23| | 24| |#import "AFURLRequestSerialization.h" 25| | 26| |@interface AFPropertyListRequestSerializerTests : AFTestCase 27| |@property (nonatomic, strong) AFPropertyListRequestSerializer *requestSerializer; 28| |@end 29| | 30| |@implementation AFPropertyListRequestSerializerTests 31| | 32| 2|- (void)setUp { 33| 2| [super setUp]; 34| 2| self.requestSerializer = [AFPropertyListRequestSerializer serializer]; 35| 2|} 36| | 37| |#pragma mark - 38| | 39| 1|- (void)testThatPropertyListRequestSerializerAcceptsPlist { 40| 1| NSDictionary *parameters = @{@"key":@"value"}; 41| 1| NSError *error = nil; 42| 1| NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"POST" URLString:self.baseURL.absoluteString parameters:parameters error:&error]; 43| 1| 44| 1| XCTAssertNotNil(request, @"Expected non-nil request."); 45| 1|} 46| | 47| 1|- (void)testThatPropertyListRequestSerializerHandlesInvalidPlist { 48| 1| NSDictionary *parameters = @{@42:@"value"}; 49| 1| NSError *error = nil; 50| 1| NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"POST" URLString:self.baseURL.absoluteString parameters:parameters error:&error]; 51| 1| 52| 1| XCTAssertNil(request, @"Expected nil request."); 53| 1| XCTAssertNotNil(error, @"Expected non-nil error."); 54| 1|} 55| | 56| |@end /Users/travis/build/AFNetworking/AFNetworking/Tests/Tests/AFPropertyListResponseSerializerTests.m: 1| |// AFPropertyListResponseSerializerTests.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "AFTestCase.h" 23| | 24| |#import "AFURLResponseSerialization.h" 25| | 26| |@interface AFPropertyListResponseSerializerTests : AFTestCase 27| |@property (nonatomic, strong) AFPropertyListResponseSerializer *responseSerializer; 28| |@end 29| | 30| |@implementation AFPropertyListResponseSerializerTests 31| | 32| 5|- (void)setUp { 33| 5| [super setUp]; 34| 5| self.responseSerializer = [AFPropertyListResponseSerializer serializer]; 35| 5|} 36| | 37| |#pragma mark - 38| | 39| 1|- (void)testThatPropertyListResponseSerializerAcceptsPlistData { 40| 1| NSData *data = [NSPropertyListSerialization dataWithPropertyList:@{@"foo": @"bar"} format:NSPropertyListXMLFormat_v1_0 options:0 error:NULL]; 41| 1| 42| 1| NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.baseURL statusCode:200 HTTPVersion:@"1.1" headerFields:@{@"Content-Type": @"application/x-plist"}]; 43| 1| NSError *error = nil; 44| 1| id responseObject = [self.responseSerializer responseObjectForResponse:response data:data error:&error]; 45| 1| 46| 1| XCTAssertTrue([responseObject isKindOfClass:[NSDictionary class]], @"Expected valid dictionary."); 47| 1|} 48| | 49| 1|- (void)testThatPropertyListResponseSerializerHandlesInvalidPlistData { 50| 1| NSData *data = [NSJSONSerialization dataWithJSONObject:@{@"foo": @"bar"} options:(NSJSONWritingOptions)0 error:nil]; 51| 1| 52| 1| NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.baseURL statusCode:200 HTTPVersion:@"1.1" headerFields:@{@"Content-Type": @"application/x-plist"}]; 53| 1| NSError *error = nil; 54| 1| id responseObject = [self.responseSerializer responseObjectForResponse:response data:data error:&error]; 55| 1| 56| 1| XCTAssertNil(responseObject, @"Expected nil responseObject."); 57| 1| XCTAssertNotNil(error, @"Expected non-nil error."); 58| 1|} 59| | 60| 1|- (void)testThatPropertyListResponseSerializerHandles204 { 61| 1| NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.baseURL statusCode:204 HTTPVersion:@"1.1" headerFields:@{@"Content-Type": @"application/x-plist"}]; 62| 1| NSError *error; 63| 1| id responseObject = [self.responseSerializer responseObjectForResponse:response data:nil error:&error]; 64| 1| 65| 1| XCTAssertNil(responseObject, @"Response should be nil when handling 204 with application/x-plist"); 66| 1| XCTAssertNil(error, @"Error handling application/x-plist"); 67| 1|} 68| | 69| 1|- (void)testResponseSerializerCanBeCopied { 70| 1| [self.responseSerializer setAcceptableContentTypes:[NSSet setWithObject:@"test/type"]]; 71| 1| [self.responseSerializer setAcceptableStatusCodes:[NSIndexSet indexSetWithIndex:100]]; 72| 1| [self.responseSerializer setFormat:NSPropertyListXMLFormat_v1_0]; 73| 1| [self.responseSerializer setReadOptions:NSPropertyListMutableContainers]; 74| 1| 75| 1| AFPropertyListResponseSerializer *copiedSerializer = [self.responseSerializer copy]; 76| 1| XCTAssertNotNil(copiedSerializer); 77| 1| XCTAssertNotEqual(copiedSerializer, self.responseSerializer); 78| 1| XCTAssertEqual(copiedSerializer.format, self.responseSerializer.format); 79| 1| XCTAssertEqual(copiedSerializer.readOptions, self.responseSerializer.readOptions); 80| 1| XCTAssertEqual(copiedSerializer.acceptableContentTypes, self.responseSerializer.acceptableContentTypes); 81| 1| XCTAssertEqual(copiedSerializer.acceptableStatusCodes, self.responseSerializer.acceptableStatusCodes); 82| 1|} 83| | 84| 1|- (void)testResponseSerializerCanBeArchivedAndUnarchived { 85| 1| NSData *archive = [NSKeyedArchiver archivedDataWithRootObject:self.responseSerializer]; 86| 1| XCTAssertNotNil(archive); 87| 1| AFPropertyListResponseSerializer *unarchivedSerializer = [NSKeyedUnarchiver unarchiveObjectWithData:archive]; 88| 1| XCTAssertNotNil(unarchivedSerializer); 89| 1| XCTAssertNotEqual(unarchivedSerializer, self.responseSerializer); 90| 1| XCTAssertTrue(unarchivedSerializer.format == self.responseSerializer.format); 91| 1| XCTAssertTrue(unarchivedSerializer.readOptions == self.responseSerializer.readOptions); 92| 1|} 93| | 94| |@end /Users/travis/build/AFNetworking/AFNetworking/Tests/Tests/AFSecurityPolicyTests.m: 1| |// AFSecurityPolicyTests.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "AFTestCase.h" 23| |#import "AFSecurityPolicy.h" 24| | 25| |@interface AFSecurityPolicyTests : AFTestCase 26| | 27| |@end 28| | 29| 25|static SecTrustRef AFUTTrustChainForCertsInDirectory(NSString *directoryPath) { 30| 25| NSArray *certFileNames = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:directoryPath error:nil]; 31| 25| NSMutableArray *certs = [NSMutableArray arrayWithCapacity:[certFileNames count]]; 32| 96| for (NSString *path in certFileNames) { 33| 96| NSData *certData = [NSData dataWithContentsOfFile:[directoryPath stringByAppendingPathComponent:path]]; 34| 96| SecCertificateRef cert = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(certData)); 35| 96| [certs addObject:(__bridge_transfer id)(cert)]; 36| 96| } 37| 25| 38| 25| SecPolicyRef policy = SecPolicyCreateBasicX509(); 39| 25| SecTrustRef trust = NULL; 40| 25| SecTrustCreateWithCertificates((__bridge CFTypeRef)(certs), policy, &trust); 41| 25| CFRelease(policy); 42| 25| 43| 25| return trust; 44| 25|} 45| | 46| 21|static SecTrustRef AFUTHTTPBinOrgServerTrust() { 47| 21| NSString *bundlePath = [[NSBundle bundleForClass:[AFSecurityPolicyTests class]] resourcePath]; 48| 21| NSString *serverCertDirectoryPath = [bundlePath stringByAppendingPathComponent:@"HTTPBinOrgServerTrustChain"]; 49| 21| 50| 21| return AFUTTrustChainForCertsInDirectory(serverCertDirectoryPath); 51| 21|} 52| | 53| 4|static SecTrustRef AFUTADNNetServerTrust() { 54| 4| NSString *bundlePath = [[NSBundle bundleForClass:[AFSecurityPolicyTests class]] resourcePath]; 55| 4| NSString *serverCertDirectoryPath = [bundlePath stringByAppendingPathComponent:@"ADNNetServerTrustChain"]; 56| 4| 57| 4| return AFUTTrustChainForCertsInDirectory(serverCertDirectoryPath); 58| 4|} 59| | 60| 18|static SecCertificateRef AFUTHTTPBinOrgCertificate() { 61| 18| NSString *certPath = [[NSBundle bundleForClass:[AFSecurityPolicyTests class]] pathForResource:@"httpbinorg_03172020" ofType:@"cer"]; 62| 18| NSCAssert(certPath != nil, @"Path for certificate should not be nil"); 63| 18| NSData *certData = [NSData dataWithContentsOfFile:certPath]; 64| 18| 65| 18| return SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(certData)); 66| 18|} 67| | 68| 4|static SecCertificateRef AFUTAmazonAuthorityCertificate() { 69| 4| NSString *certPath = [[NSBundle bundleForClass:NSClassFromString(@"AFSecurityPolicyTests")] pathForResource:@"Amazon" ofType:@"cer"]; 70| 4| NSCAssert(certPath != nil, @"Path for certificate should not be nil"); 71| 4| NSData *certData = [NSData dataWithContentsOfFile:certPath]; 72| 4| 73| 4| return SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(certData)); 74| 4|} 75| | 76| 4|static SecCertificateRef AFUTAmazonRootAuthorityCertificate() { 77| 4| NSString *certPath = [[NSBundle bundleForClass:NSClassFromString(@"AFSecurityPolicyTests")] pathForResource:@"Amazon Root CA 1" ofType:@"cer"]; 78| 4| NSCAssert(certPath != nil, @"Path for certificate should not be nil"); 79| 4| NSData *certData = [NSData dataWithContentsOfFile:certPath]; 80| 4| 81| 4| return SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(certData)); 82| 4|} 83| | 84| 2|static SecCertificateRef AFUTStarfieldServicesRootCertificate() { 85| 2| NSString *certPath = [[NSBundle bundleForClass:NSClassFromString(@"AFSecurityPolicyTests")] pathForResource:@"Starfield Services Root Certificate Authority - G2" ofType:@"cer"]; 86| 2| NSCAssert(certPath != nil, @"Path for certificate should not be nil"); 87| 2| NSData *certData = [NSData dataWithContentsOfFile:certPath]; 88| 2| 89| 2| return SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(certData)); 90| 2|} 91| | 92| 2|static SecCertificateRef AFUTSelfSignedCertificateWithoutDomain() { 93| 2| NSString *certPath = [[NSBundle bundleForClass:[AFSecurityPolicyTests class]] pathForResource:@"NoDomains" ofType:@"cer"]; 94| 2| NSCAssert(certPath != nil, @"Path for certificate should not be nil"); 95| 2| NSData *certData = [NSData dataWithContentsOfFile:certPath]; 96| 2| 97| 2| return SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(certData)); 98| 2|} 99| | 100| 5|static SecCertificateRef AFUTSelfSignedCertificateWithCommonNameDomain() { 101| 5| NSString *certPath = [[NSBundle bundleForClass:[AFSecurityPolicyTests class]] pathForResource:@"foobar.com" ofType:@"cer"]; 102| 5| NSCAssert(certPath != nil, @"Path for certificate should not be nil"); 103| 5| NSData *certData = [NSData dataWithContentsOfFile:certPath]; 104| 5| 105| 5| return SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(certData)); 106| 5|} 107| | 108| 8|static SecCertificateRef AFUTSelfSignedCertificateWithDNSNameDomain() { 109| 8| NSString *certPath = [[NSBundle bundleForClass:[AFSecurityPolicyTests class]] pathForResource:@"AltName" ofType:@"cer"]; 110| 8| NSCAssert(certPath != nil, @"Path for certificate should not be nil"); 111| 8| NSData *certData = [NSData dataWithContentsOfFile:certPath]; 112| 8| 113| 8| return SecCertificateCreateWithData(NULL, (__bridge CFDataRef)(certData)); 114| 8|} 115| | 116| 11|static SecTrustRef AFUTTrustWithCertificate(SecCertificateRef certificate) { 117| 11| NSArray *certs = @[(__bridge id)(certificate)]; 118| 11| 119| 11| SecPolicyRef policy = SecPolicyCreateBasicX509(); 120| 11| SecTrustRef trust = NULL; 121| 11| SecTrustCreateWithCertificates((__bridge CFTypeRef)(certs), policy, &trust); 122| 11| CFRelease(policy); 123| 11| 124| 11| return trust; 125| 11|} 126| | 127| |@implementation AFSecurityPolicyTests 128| | 129| |#pragma mark - Default Policy Tests 130| |#pragma mark Default Values Test 131| | 132| 1|- (void)testDefaultPolicyPinningModeIsSetToNone { 133| 1| AFSecurityPolicy *policy = [AFSecurityPolicy defaultPolicy]; 134| 1| XCTAssertTrue(policy.SSLPinningMode == AFSSLPinningModeNone, @"Pinning Mode should be set to by default"); 135| 1|} 136| | 137| 1|- (void)testDefaultPolicyHasInvalidCertificatesAreDisabledByDefault { 138| 1| AFSecurityPolicy *policy = [AFSecurityPolicy defaultPolicy]; 139| 1| XCTAssertFalse(policy.allowInvalidCertificates, @"Invalid Certificates Should Be Disabled by Default"); 140| 1|} 141| | 142| 1|- (void)testDefaultPolicyHasDomainNamesAreValidatedByDefault { 143| 1| AFSecurityPolicy *policy = [AFSecurityPolicy defaultPolicy]; 144| 1| XCTAssertTrue(policy.validatesDomainName, @"Domain names should be validated by default"); 145| 1|} 146| | 147| 1|- (void)testDefaultPolicyHasNoPinnedCertificates { 148| 1| AFSecurityPolicy *policy = [AFSecurityPolicy defaultPolicy]; 149| 1| XCTAssertTrue(policy.pinnedCertificates.count == 0, @"The default policy should not have any pinned certificates"); 150| 1|} 151| | 152| |#pragma mark Positive Server Trust Evaluation Tests 153| | 154| 1|- (void)testDefaultPolicyDoesAllowHTTPBinOrgCertificate { 155| 1| AFSecurityPolicy *policy = [AFSecurityPolicy defaultPolicy]; 156| 1| SecTrustRef trust = AFUTHTTPBinOrgServerTrust(); 157| 1| XCTAssertTrue([policy evaluateServerTrust:trust forDomain:nil], @"Valid Certificate should be allowed by default."); 158| 1|} 159| | 160| 1|- (void)testDefaultPolicyDoesAllowHTTPBinOrgCertificateForValidDomainName { 161| 1| AFSecurityPolicy *policy = [AFSecurityPolicy defaultPolicy]; 162| 1| SecTrustRef trust = AFUTHTTPBinOrgServerTrust(); 163| 1| XCTAssertTrue([policy evaluateServerTrust:trust forDomain:@"httpbin.org"], @"Valid Certificate should be allowed by default."); 164| 1|} 165| | 166| |#pragma mark Negative Server Trust Evaluation Tests 167| | 168| 1|- (void)testDefaultPolicyDoesNotAllowInvalidCertificate { 169| 1| AFSecurityPolicy *policy = [AFSecurityPolicy defaultPolicy]; 170| 1| SecCertificateRef certificate = AFUTSelfSignedCertificateWithoutDomain(); 171| 1| SecTrustRef trust = AFUTTrustWithCertificate(certificate); 172| 1| XCTAssertFalse([policy evaluateServerTrust:trust forDomain:nil], @"Invalid Certificates should not be allowed"); 173| 1|} 174| | 175| 1|- (void)testDefaultPolicyDoesNotAllowCertificateWithInvalidDomainName { 176| 1| AFSecurityPolicy *policy = [AFSecurityPolicy defaultPolicy]; 177| 1| SecTrustRef trust = AFUTHTTPBinOrgServerTrust(); 178| 1| XCTAssertFalse([policy evaluateServerTrust:trust forDomain:@"apple.com"], @"Certificate should not be allowed because the domain names do not match."); 179| 1|} 180| | 181| |#pragma mark - Public Key Pinning Tests 182| |#pragma mark Default Values Tests 183| | 184| 1|- (void)testPolicyWithPublicKeyPinningModeHasPinnedCertificates { 185| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey]; 186| 1| XCTAssertTrue(policy.pinnedCertificates > 0, @"Policy should contain default pinned certificates"); 187| 1|} 188| | 189| 1|- (void)testPolicyWithPublicKeyPinningModeHasHTTPBinOrgPinnedCertificate { 190| 1| NSBundle *bundle = [NSBundle bundleForClass:[self class]]; 191| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey withPinnedCertificates:[AFSecurityPolicy certificatesInBundle:bundle]]; 192| 1| 193| 1| SecCertificateRef cert = AFUTHTTPBinOrgCertificate(); 194| 1| NSData *certData = (__bridge NSData *)(SecCertificateCopyData(cert)); 195| 1| CFRelease(cert); 196| 15| NSSet *set = [policy.pinnedCertificates objectsPassingTest:^BOOL(NSData *data, BOOL *stop) { 197| 15| return [data isEqualToData:certData]; 198| 15| }]; 199| 1| 200| 1| XCTAssertEqual(set.count, 1U, @"HTTPBin.org certificate not found in the default certificates"); 201| 1|} 202| | 203| |#pragma mark Positive Server Trust Evaluation Tests 204| 1|- (void)testPolicyWithPublicKeyPinningAllowsHTTPBinOrgServerTrustWithHTTPBinOrgLeafCertificatePinned { 205| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey]; 206| 1| 207| 1| SecCertificateRef certificate = AFUTHTTPBinOrgCertificate(); 208| 1| policy.pinnedCertificates = [NSSet setWithObject:(__bridge_transfer id)SecCertificateCopyData(certificate)]; 209| 1| XCTAssertTrue([policy evaluateServerTrust:AFUTHTTPBinOrgServerTrust() forDomain:nil], @"Policy should allow server trust"); 210| 1|} 211| | 212| 1|- (void)testPolicyWithPublicKeyPinningAllowsHTTPBinOrgServerTrustWithHTTPBinOrgIntermediateCertificatePinned { 213| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey]; 214| 1| 215| 1| SecCertificateRef certificate = AFUTAmazonAuthorityCertificate(); 216| 1| policy.pinnedCertificates = [NSSet setWithObject:(__bridge_transfer id)SecCertificateCopyData(certificate)]; 217| 1| XCTAssertTrue([policy evaluateServerTrust:AFUTHTTPBinOrgServerTrust() forDomain:nil], @"Policy should allow server trust"); 218| 1|} 219| | 220| 1|- (void)testPolicyWithPublicKeyPinningAllowsHTTPBinOrgServerTrustWithHTTPBinOrgRootCertificatePinned { 221| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey]; 222| 1| 223| 1| SecCertificateRef certificate = AFUTAmazonRootAuthorityCertificate(); 224| 1| policy.pinnedCertificates = [NSSet setWithObject:(__bridge_transfer id)SecCertificateCopyData(certificate)]; 225| 1| XCTAssertTrue([policy evaluateServerTrust:AFUTHTTPBinOrgServerTrust() forDomain:nil], @"Policy should allow server trust"); 226| 1|} 227| | 228| 1|- (void)testPolicyWithPublicKeyPinningAllowsHTTPBinOrgServerTrustWithEntireCertificateChainPinned { 229| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey]; 230| 1| 231| 1| SecCertificateRef httpBinCertificate = AFUTHTTPBinOrgCertificate(); 232| 1| SecCertificateRef intermediateCertificate = AFUTAmazonAuthorityCertificate(); 233| 1| SecCertificateRef intermediateCertificate2 = AFUTAmazonRootAuthorityCertificate(); 234| 1| SecCertificateRef rootCertificate = AFUTStarfieldServicesRootCertificate(); 235| 1| [policy setPinnedCertificates:[NSSet setWithObjects:(__bridge_transfer NSData *)SecCertificateCopyData(httpBinCertificate), 236| 1| (__bridge_transfer NSData *)SecCertificateCopyData(intermediateCertificate), 237| 1| (__bridge_transfer NSData *)SecCertificateCopyData(intermediateCertificate2), 238| 1| (__bridge_transfer NSData *)SecCertificateCopyData(rootCertificate), nil]]; 239| 1| XCTAssertTrue([policy evaluateServerTrust:AFUTHTTPBinOrgServerTrust() forDomain:nil], @"Policy should allow HTTPBinOrg server trust because at least one of the pinned certificates is valid"); 240| 1| 241| 1|} 242| | 243| 1|- (void)testPolicyWithPublicKeyPinningAllowsHTTPBirnOrgServerTrustWithHTTPbinOrgPinnedCertificateAndAdditionalPinnedCertificates { 244| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey]; 245| 1| 246| 1| SecCertificateRef httpBinCertificate = AFUTHTTPBinOrgCertificate(); 247| 1| SecCertificateRef selfSignedCertificate = AFUTSelfSignedCertificateWithCommonNameDomain(); 248| 1| [policy setPinnedCertificates:[NSSet setWithObjects:(__bridge_transfer NSData *)SecCertificateCopyData(httpBinCertificate), 249| 1| (__bridge_transfer NSData *)SecCertificateCopyData(selfSignedCertificate), nil]]; 250| 1| XCTAssertTrue([policy evaluateServerTrust:AFUTHTTPBinOrgServerTrust() forDomain:nil], @"Policy should allow HTTPBinOrg server trust because at least one of the pinned certificates is valid"); 251| 1|} 252| | 253| 1|- (void)testPolicyWithPublicKeyPinningAllowsHTTPBinOrgServerTrustWithHTTPBinOrgLeafCertificatePinnedAndValidDomainName { 254| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey]; 255| 1| 256| 1| SecCertificateRef certificate = AFUTHTTPBinOrgCertificate(); 257| 1| policy.pinnedCertificates = [NSSet setWithObject:(__bridge_transfer id)SecCertificateCopyData(certificate)]; 258| 1| XCTAssertTrue([policy evaluateServerTrust:AFUTHTTPBinOrgServerTrust() forDomain:@"httpbin.org"], @"Policy should allow server trust"); 259| 1|} 260| | 261| |#pragma mark Negative Server Trust Evaluation Tests 262| | 263| 1|- (void)testPolicyWithPublicKeyPinningAndNoPinnedCertificatesDoesNotAllowHTTPBinOrgServerTrust { 264| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey]; 265| 1| policy.pinnedCertificates = [NSSet set]; 266| 1| XCTAssertFalse([policy evaluateServerTrust:AFUTHTTPBinOrgServerTrust() forDomain:nil], @"Policy should not allow server trust because the policy is set to public key pinning and it does not contain any pinned certificates."); 267| 1|} 268| | 269| 1|- (void)testPolicyWithPublicKeyPinningDoesNotAllowADNServerTrustWithHTTPBinOrgPinnedCertificate { 270| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey]; 271| 1| 272| 1| SecCertificateRef certificate = AFUTHTTPBinOrgCertificate(); 273| 1| policy.pinnedCertificates = [NSSet setWithObject:(__bridge_transfer id)SecCertificateCopyData(certificate)]; 274| 1| XCTAssertFalse([policy evaluateServerTrust:AFUTADNNetServerTrust() forDomain:nil], @"Policy should not allow ADN server trust for pinned HTTPBin.org certificate"); 275| 1|} 276| | 277| 1|- (void)testPolicyWithPublicKeyPinningDoesNotAllowHTTPBinOrgServerTrustWithHTTPBinOrgLeafCertificatePinnedAndInvalidDomainName { 278| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey]; 279| 1| 280| 1| SecCertificateRef certificate = AFUTHTTPBinOrgCertificate(); 281| 1| policy.pinnedCertificates = [NSSet setWithObject:(__bridge_transfer id)SecCertificateCopyData(certificate)]; 282| 1| XCTAssertFalse([policy evaluateServerTrust:AFUTHTTPBinOrgServerTrust() forDomain:@"invaliddomainname.com"], @"Policy should not allow server trust"); 283| 1|} 284| | 285| 1|- (void)testPolicyWithPublicKeyPinningDoesNotAllowADNServerTrustWithMultipleInvalidPinnedCertificates { 286| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey]; 287| 1| 288| 1| SecCertificateRef httpBinCertificate = AFUTHTTPBinOrgCertificate(); 289| 1| SecCertificateRef selfSignedCertificate = AFUTSelfSignedCertificateWithCommonNameDomain(); 290| 1| [policy setPinnedCertificates:[NSSet setWithObjects:(__bridge_transfer NSData *)SecCertificateCopyData(httpBinCertificate), 291| 1| (__bridge_transfer NSData *)SecCertificateCopyData(selfSignedCertificate), nil]]; 292| 1| XCTAssertFalse([policy evaluateServerTrust:AFUTADNNetServerTrust() forDomain:nil], @"Policy should not allow ADN server trust because there are no matching pinned certificates"); 293| 1|} 294| | 295| |#pragma mark - Certificate Pinning Tests 296| |#pragma mark Default Values Tests 297| | 298| 1|- (void)testPolicyWithCertificatePinningModeHasPinnedCertificates { 299| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; 300| 1| XCTAssertTrue(policy.pinnedCertificates > 0, @"Policy should contain default pinned certificates"); 301| 1|} 302| | 303| 1|- (void)testPolicyWithCertificatePinningModeHasHTTPBinOrgPinnedCertificate { 304| 1| NSBundle *bundle = [NSBundle bundleForClass:[self class]]; 305| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate withPinnedCertificates:[AFSecurityPolicy certificatesInBundle:bundle]]; 306| 1| 307| 1| SecCertificateRef cert = AFUTHTTPBinOrgCertificate(); 308| 1| NSData *certData = (__bridge NSData *)(SecCertificateCopyData(cert)); 309| 1| CFRelease(cert); 310| 15| NSSet *set = [policy.pinnedCertificates objectsPassingTest:^BOOL(NSData *data, BOOL *stop) { 311| 15| return [data isEqualToData:certData]; 312| 15| }]; 313| 1| 314| 1| XCTAssertEqual(set.count, 1U, @"HTTPBin.org certificate not found in the default certificates"); 315| 1|} 316| | 317| |#pragma mark Positive Server Trust Evaluation Tests 318| 1|- (void)testPolicyWithCertificatePinningAllowsHTTPBinOrgServerTrustWithHTTPBinOrgLeafCertificatePinned { 319| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; 320| 1| 321| 1| SecCertificateRef certificate = AFUTHTTPBinOrgCertificate(); 322| 1| policy.pinnedCertificates = [NSSet setWithObject:(__bridge_transfer id)SecCertificateCopyData(certificate)]; 323| 1| XCTAssertTrue([policy evaluateServerTrust:AFUTHTTPBinOrgServerTrust() forDomain:nil], @"Policy should allow server trust"); 324| 1|} 325| | 326| 1|- (void)testPolicyWithCertificatePinningAllowsHTTPBinOrgServerTrustWithHTTPBinOrgIntermediateCertificatePinned { 327| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; 328| 1| 329| 1| SecCertificateRef certificate = AFUTAmazonAuthorityCertificate(); 330| 1| policy.pinnedCertificates = [NSSet setWithObject:(__bridge_transfer id)SecCertificateCopyData(certificate)]; 331| 1| XCTAssertTrue([policy evaluateServerTrust:AFUTHTTPBinOrgServerTrust() forDomain:nil], @"Policy should allow server trust"); 332| 1|} 333| | 334| 1|- (void)testPolicyWithCertificatePinningAllowsHTTPBinOrgServerTrustWithHTTPBinOrgRootCertificatePinned { 335| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; 336| 1| 337| 1| SecCertificateRef certificate = AFUTAmazonRootAuthorityCertificate(); 338| 1| policy.pinnedCertificates = [NSSet setWithObject:(__bridge_transfer id)SecCertificateCopyData(certificate)]; 339| 1| XCTAssertTrue([policy evaluateServerTrust:AFUTHTTPBinOrgServerTrust() forDomain:nil], @"Policy should allow server trust"); 340| 1|} 341| | 342| 1|- (void)testPolicyWithCertificatePinningAllowsHTTPBinOrgServerTrustWithEntireCertificateChainPinned { 343| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; 344| 1| 345| 1| SecCertificateRef httpBinCertificate = AFUTHTTPBinOrgCertificate(); 346| 1| SecCertificateRef intermediateCertificate = AFUTAmazonAuthorityCertificate(); 347| 1| SecCertificateRef intermediateCertificate2 = AFUTAmazonRootAuthorityCertificate(); 348| 1| SecCertificateRef rootCertificate = AFUTStarfieldServicesRootCertificate(); 349| 1| [policy setPinnedCertificates:[NSSet setWithObjects:(__bridge_transfer NSData *)SecCertificateCopyData(httpBinCertificate), 350| 1| (__bridge_transfer NSData *)SecCertificateCopyData(intermediateCertificate), 351| 1| (__bridge_transfer NSData *)SecCertificateCopyData(intermediateCertificate2), 352| 1| (__bridge_transfer NSData *)SecCertificateCopyData(rootCertificate), nil]]; 353| 1| XCTAssertTrue([policy evaluateServerTrust:AFUTHTTPBinOrgServerTrust() forDomain:nil], @"Policy should allow HTTPBinOrg server trust because at least one of the pinned certificates is valid"); 354| 1| 355| 1|} 356| | 357| 1|- (void)testPolicyWithCertificatePinningAllowsHTTPBirnOrgServerTrustWithHTTPbinOrgPinnedCertificateAndAdditionalPinnedCertificates { 358| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; 359| 1| 360| 1| SecCertificateRef httpBinCertificate = AFUTHTTPBinOrgCertificate(); 361| 1| SecCertificateRef selfSignedCertificate = AFUTSelfSignedCertificateWithCommonNameDomain(); 362| 1| [policy setPinnedCertificates:[NSSet setWithObjects:(__bridge_transfer NSData *)SecCertificateCopyData(httpBinCertificate), 363| 1| (__bridge_transfer NSData *)SecCertificateCopyData(selfSignedCertificate), nil]]; 364| 1| XCTAssertTrue([policy evaluateServerTrust:AFUTHTTPBinOrgServerTrust() forDomain:nil], @"Policy should allow HTTPBinOrg server trust because at least one of the pinned certificates is valid"); 365| 1|} 366| | 367| 1|- (void)testPolicyWithCertificatePinningAllowsHTTPBinOrgServerTrustWithHTTPBinOrgLeafCertificatePinnedAndValidDomainName { 368| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; 369| 1| 370| 1| SecCertificateRef certificate = AFUTHTTPBinOrgCertificate(); 371| 1| policy.pinnedCertificates = [NSSet setWithObject:(__bridge_transfer id)SecCertificateCopyData(certificate)]; 372| 1| XCTAssertTrue([policy evaluateServerTrust:AFUTHTTPBinOrgServerTrust() forDomain:@"httpbin.org"], @"Policy should allow server trust"); 373| 1|} 374| | 375| |#pragma mark Negative Server Trust Evaluation Tests 376| | 377| 1|- (void)testPolicyWithCertificatePinningAndNoPinnedCertificatesDoesNotAllowHTTPBinOrgServerTrust { 378| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; 379| 1| policy.pinnedCertificates = [NSSet set]; 380| 1| XCTAssertFalse([policy evaluateServerTrust:AFUTHTTPBinOrgServerTrust() forDomain:nil], @"Policy should not allow server trust because the policy does not contain any pinned certificates."); 381| 1|} 382| | 383| 1|- (void)testPolicyWithCertificatePinningDoesNotAllowADNServerTrustWithHTTPBinOrgPinnedCertificate { 384| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; 385| 1| 386| 1| SecCertificateRef certificate = AFUTHTTPBinOrgCertificate(); 387| 1| policy.pinnedCertificates = [NSSet setWithObject:(__bridge_transfer id)SecCertificateCopyData(certificate)]; 388| 1| XCTAssertFalse([policy evaluateServerTrust:AFUTADNNetServerTrust() forDomain:nil], @"Policy should not allow ADN server trust for pinned HTTPBin.org certificate"); 389| 1|} 390| | 391| 1|- (void)testPolicyWithCertificatePinningDoesNotAllowHTTPBinOrgServerTrustWithHTTPBinOrgLeafCertificatePinnedAndInvalidDomainName { 392| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; 393| 1| 394| 1| SecCertificateRef certificate = AFUTHTTPBinOrgCertificate(); 395| 1| policy.pinnedCertificates = [NSSet setWithObject:(__bridge_transfer id)SecCertificateCopyData(certificate)]; 396| 1| XCTAssertFalse([policy evaluateServerTrust:AFUTHTTPBinOrgServerTrust() forDomain:@"invaliddomainname.com"], @"Policy should not allow server trust"); 397| 1|} 398| | 399| 1|- (void)testPolicyWithCertificatePinningDoesNotAllowADNServerTrustWithMultipleInvalidPinnedCertificates { 400| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; 401| 1| 402| 1| SecCertificateRef httpBinCertificate = AFUTHTTPBinOrgCertificate(); 403| 1| SecCertificateRef selfSignedCertificate = AFUTSelfSignedCertificateWithCommonNameDomain(); 404| 1| [policy setPinnedCertificates:[NSSet setWithObjects:(__bridge_transfer NSData *)SecCertificateCopyData(httpBinCertificate), 405| 1| (__bridge_transfer NSData *)SecCertificateCopyData(selfSignedCertificate), nil]]; 406| 1| XCTAssertFalse([policy evaluateServerTrust:AFUTADNNetServerTrust() forDomain:nil], @"Policy should not allow ADN server trust because there are no matching pinned certificates"); 407| 1|} 408| | 409| |#pragma mark - Domain Name Validation Tests 410| |#pragma mark Positive Evaluation Tests 411| | 412| 1|- (void)testThatPolicyWithoutDomainNameValidationAllowsServerTrustWithInvalidDomainName { 413| 1| AFSecurityPolicy *policy = [AFSecurityPolicy defaultPolicy]; 414| 1| [policy setValidatesDomainName:NO]; 415| 1| XCTAssertTrue([policy evaluateServerTrust:AFUTHTTPBinOrgServerTrust() forDomain:@"invalid.org"], @"Policy should allow server trust because domain name validation is disabled"); 416| 1|} 417| | 418| 1|- (void)testThatPolicyWithDomainNameValidationAndSelfSignedCommonNameCertificateAllowsServerTrust { 419| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey]; 420| 1| 421| 1| SecCertificateRef certificate = AFUTSelfSignedCertificateWithCommonNameDomain(); 422| 1| SecTrustRef trust = AFUTTrustWithCertificate(certificate); 423| 1| [policy setPinnedCertificates:[NSSet setWithObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)]]; 424| 1| [policy setAllowInvalidCertificates:YES]; 425| 1| 426| 1| XCTAssertTrue([policy evaluateServerTrust:trust forDomain:@"foobar.com"], @"Policy should allow server trust"); 427| 1|} 428| | 429| 1|- (void)testThatPolicyWithDomainNameValidationAndSelfSignedDNSCertificateAllowsServerTrust { 430| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey]; 431| 1| 432| 1| SecCertificateRef certificate = AFUTSelfSignedCertificateWithDNSNameDomain(); 433| 1| SecTrustRef trust = AFUTTrustWithCertificate(certificate); 434| 1| [policy setPinnedCertificates:[NSSet setWithObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)]]; 435| 1| [policy setAllowInvalidCertificates:YES]; 436| 1| 437| 1| XCTAssertTrue([policy evaluateServerTrust:trust forDomain:@"foobar.com"], @"Policy should allow server trust"); 438| 1|} 439| | 440| |#pragma mark Negative Evaluation Tests 441| | 442| 1|- (void)testThatPolicyWithDomainNameValidationDoesNotAllowServerTrustWithInvalidDomainName { 443| 1| AFSecurityPolicy *policy = [AFSecurityPolicy defaultPolicy]; 444| 1| XCTAssertFalse([policy evaluateServerTrust:AFUTHTTPBinOrgServerTrust() forDomain:@"invalid.org"], @"Policy should not allow allow server trust"); 445| 1|} 446| | 447| 1|- (void)testThatPolicyWithDomainNameValidationAndSelfSignedNoDomainCertificateDoesNotAllowServerTrust { 448| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; 449| 1| 450| 1| SecCertificateRef certificate = AFUTSelfSignedCertificateWithoutDomain(); 451| 1| SecTrustRef trust = AFUTTrustWithCertificate(certificate); 452| 1| [policy setPinnedCertificates:[NSSet setWithObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)]]; 453| 1| [policy setAllowInvalidCertificates:YES]; 454| 1| 455| 1| XCTAssertFalse([policy evaluateServerTrust:trust forDomain:@"foobar.com"], @"Policy should not allow server trust"); 456| 1|} 457| | 458| |#pragma mark - Self Signed Certificate Tests 459| |#pragma mark Positive Test Cases 460| | 461| 1|- (void)testThatPolicyWithInvalidCertificatesAllowedAllowsSelfSignedServerTrust { 462| 1| AFSecurityPolicy *policy = [AFSecurityPolicy defaultPolicy]; 463| 1| [policy setAllowInvalidCertificates:YES]; 464| 1| 465| 1| SecCertificateRef certificate = AFUTSelfSignedCertificateWithDNSNameDomain(); 466| 1| SecTrustRef trust = AFUTTrustWithCertificate(certificate); 467| 1| 468| 1| XCTAssertTrue([policy evaluateServerTrust:trust forDomain:nil], @"Policy should allow server trust because invalid certificates are allowed"); 469| 1|} 470| | 471| 1|- (void)testThatPolicyWithInvalidCertificatesAllowedAndValidPinnedCertificatesDoesAllowSelfSignedServerTrustForValidDomainName { 472| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey]; 473| 1| [policy setAllowInvalidCertificates:YES]; 474| 1| SecCertificateRef certificate = AFUTSelfSignedCertificateWithDNSNameDomain(); 475| 1| SecTrustRef trust = AFUTTrustWithCertificate(certificate); 476| 1| [policy setPinnedCertificates:[NSSet setWithObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)]]; 477| 1| 478| 1| XCTAssertTrue([policy evaluateServerTrust:trust forDomain:@"foobar.com"], @"Policy should allow server trust because invalid certificates are allowed"); 479| 1|} 480| | 481| 1|- (void)testThatPolicyWithInvalidCertificatesAllowedAndNoSSLPinningAndDomainNameValidationDisabledDoesAllowSelfSignedServerTrustForValidDomainName { 482| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone]; 483| 1| [policy setAllowInvalidCertificates:YES]; 484| 1| [policy setValidatesDomainName:NO]; 485| 1| 486| 1| SecCertificateRef certificate = AFUTSelfSignedCertificateWithDNSNameDomain(); 487| 1| SecTrustRef trust = AFUTTrustWithCertificate(certificate); 488| 1| 489| 1| XCTAssertTrue([policy evaluateServerTrust:trust forDomain:@"foobar.com"], @"Policy should allow server trust because invalid certificates are allowed"); 490| 1|} 491| | 492| |#pragma mark Negative Test Cases 493| | 494| 1|- (void)testThatPolicyWithInvalidCertificatesDisabledDoesNotAllowSelfSignedServerTrust { 495| 1| AFSecurityPolicy *policy = [AFSecurityPolicy defaultPolicy]; 496| 1| 497| 1| SecCertificateRef certificate = AFUTSelfSignedCertificateWithDNSNameDomain(); 498| 1| SecTrustRef trust = AFUTTrustWithCertificate(certificate); 499| 1| 500| 1| XCTAssertFalse([policy evaluateServerTrust:trust forDomain:nil], @"Policy should not allow server trust because invalid certificates are not allowed"); 501| 1|} 502| | 503| 1|- (void)testThatPolicyWithInvalidCertificatesAllowedAndNoPinnedCertificatesAndPublicKeyPinningModeDoesNotAllowSelfSignedServerTrustForValidDomainName { 504| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModePublicKey]; 505| 1| [policy setAllowInvalidCertificates:YES]; 506| 1| [policy setPinnedCertificates:[NSSet set]]; 507| 1| SecCertificateRef certificate = AFUTSelfSignedCertificateWithDNSNameDomain(); 508| 1| SecTrustRef trust = AFUTTrustWithCertificate(certificate); 509| 1| 510| 1| XCTAssertFalse([policy evaluateServerTrust:trust forDomain:@"foobar.com"], @"Policy should not allow server trust because invalid certificates are allowed but there are no pinned certificates"); 511| 1|} 512| | 513| 1|- (void)testThatPolicyWithInvalidCertificatesAllowedAndValidPinnedCertificatesAndNoPinningModeDoesNotAllowSelfSignedServerTrustForValidDomainName { 514| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone]; 515| 1| [policy setAllowInvalidCertificates:YES]; 516| 1| SecCertificateRef certificate = AFUTSelfSignedCertificateWithDNSNameDomain(); 517| 1| SecTrustRef trust = AFUTTrustWithCertificate(certificate); 518| 1| [policy setPinnedCertificates:[NSSet setWithObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)]]; 519| 1| 520| 1| XCTAssertFalse([policy evaluateServerTrust:trust forDomain:@"foobar.com"], @"Policy should not allow server trust because invalid certificates are allowed but there are no pinned certificates"); 521| 1|} 522| | 523| 1|- (void)testThatPolicyWithInvalidCertificatesAllowedAndNoValidPinnedCertificatesAndNoPinningModeAndDomainValidationDoesNotAllowSelfSignedServerTrustForValidDomainName { 524| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeNone]; 525| 1| [policy setAllowInvalidCertificates:YES]; 526| 1| [policy setPinnedCertificates:[NSSet set]]; 527| 1| 528| 1| SecCertificateRef certificate = AFUTSelfSignedCertificateWithDNSNameDomain(); 529| 1| SecTrustRef trust = AFUTTrustWithCertificate(certificate); 530| 1| 531| 1| XCTAssertFalse([policy evaluateServerTrust:trust forDomain:@"foobar.com"], @"Policy should not allow server trust because invalid certificates are allowed but there are no pinned certificates"); 532| 1|} 533| | 534| |#pragma mark - NSCopying 535| 1|- (void)testThatPolicyCanBeCopied { 536| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; 537| 1| policy.allowInvalidCertificates = YES; 538| 1| policy.validatesDomainName = NO; 539| 1| policy.pinnedCertificates = [NSSet setWithObject:(__bridge_transfer id)SecCertificateCopyData(AFUTHTTPBinOrgCertificate())]; 540| 1| 541| 1| AFSecurityPolicy *copiedPolicy = [policy copy]; 542| 1| XCTAssertNotEqual(copiedPolicy, policy); 543| 1| XCTAssertEqual(copiedPolicy.allowInvalidCertificates, policy.allowInvalidCertificates); 544| 1| XCTAssertEqual(copiedPolicy.validatesDomainName, policy.validatesDomainName); 545| 1| XCTAssertEqual(copiedPolicy.SSLPinningMode, policy.SSLPinningMode); 546| 1| XCTAssertTrue([copiedPolicy.pinnedCertificates isEqualToSet:policy.pinnedCertificates]); 547| 1|} 548| | 549| 1|- (void)testThatPolicyCanBeEncodedAndDecoded { 550| 1| AFSecurityPolicy *policy = [AFSecurityPolicy policyWithPinningMode:AFSSLPinningModeCertificate]; 551| 1| policy.allowInvalidCertificates = YES; 552| 1| policy.validatesDomainName = NO; 553| 1| policy.pinnedCertificates = [NSSet setWithObject:(__bridge_transfer id)SecCertificateCopyData(AFUTHTTPBinOrgCertificate())]; 554| 1| 555| 1| NSMutableData *archiveData = [NSMutableData new]; 556| 1| NSKeyedArchiver *archiver = [[NSKeyedArchiver alloc] initForWritingWithMutableData:archiveData]; 557| 1| [archiver encodeObject:policy forKey:@"policy"]; 558| 1| [archiver finishEncoding]; 559| 1| 560| 1| NSKeyedUnarchiver *unarchiver = [[NSKeyedUnarchiver alloc] initForReadingWithData:archiveData]; 561| 1| AFSecurityPolicy *unarchivedPolicy = [unarchiver decodeObjectOfClass:[AFSecurityPolicy class] forKey:@"policy"]; 562| 1| 563| 1| XCTAssertNotEqual(unarchivedPolicy, policy); 564| 1| XCTAssertEqual(unarchivedPolicy.allowInvalidCertificates, policy.allowInvalidCertificates); 565| 1| XCTAssertEqual(unarchivedPolicy.validatesDomainName, policy.validatesDomainName); 566| 1| XCTAssertEqual(unarchivedPolicy.SSLPinningMode, policy.SSLPinningMode); 567| 1| XCTAssertTrue([unarchivedPolicy.pinnedCertificates isEqualToSet:policy.pinnedCertificates]); 568| 1|} 569| | 570| |@end /Users/travis/build/AFNetworking/AFNetworking/Tests/Tests/AFTestCase.m: 1| |// AFTestCase.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "AFTestCase.h" 23| | 24| |@implementation AFTestCase 25| | 26| 227|- (void)setUp { 27| 227| [super setUp]; 28| 227| self.networkTimeout = 20.0; 29| 227|} 30| | 31| 231|- (void)tearDown { 32| 231| [super tearDown]; 33| 231|} 34| | 35| |#pragma mark - 36| | 37| 567|- (NSURL *)baseURL { 38| 567| NSDictionary *environment = [[NSProcessInfo processInfo] environment]; 39| 567| return [NSURL URLWithString:environment[@"HTTPBIN_BASE_URL"] ?: @"https://httpbin.org"]; 40| 567|} 41| | 42| 19|- (NSURL *)pngURL { 43| 19| return [self.baseURL URLByAppendingPathComponent:@"image/png"]; 44| 19|} 45| | 46| 35|- (NSURL *)jpegURL { 47| 35| return [self.baseURL URLByAppendingPathComponent:@"image/jpeg"]; 48| 35|} 49| | 50| 15|- (NSURL *)delayURL { 51| 15| return [self.baseURL URLByAppendingPathComponent:@"delay/1"]; 52| 15|} 53| | 54| 11|- (NSURL *)URLWithStatusCode:(NSInteger)statusCode { 55| 11| return [self.baseURL URLByAppendingPathComponent:[NSString stringWithFormat:@"status/%@", @(statusCode)]]; 56| 11|} 57| | 58| 84|- (void)waitForExpectationsWithCommonTimeout { 59| 84| [self waitForExpectationsWithCommonTimeoutUsingHandler:nil]; 60| 84|} 61| | 62| 84|- (void)waitForExpectationsWithCommonTimeoutUsingHandler:(XCWaitCompletionHandler)handler { 63| 84| [self waitForExpectationsWithTimeout:self.networkTimeout handler:handler]; 64| 84|} 65| | 66| |@end /Users/travis/build/AFNetworking/AFNetworking/Tests/Tests/AFUIActivityIndicatorViewTests.m: 1| |// AFUIActivityIndicatorViewTests.h 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "AFTestCase.h" 23| |#import "UIActivityIndicatorView+AFNetworking.h" 24| |#import "AFURLSessionManager.h" 25| | 26| |@interface AFUIActivityIndicatorViewTests : AFTestCase 27| |@property (nonatomic, strong) NSURLRequest *request; 28| |@property (nonatomic, strong) UIActivityIndicatorView *activityIndicatorView; 29| |@property (nonatomic, strong) AFURLSessionManager *sessionManager; 30| |@end 31| | 32| |@implementation AFUIActivityIndicatorViewTests 33| | 34| 3|- (void)setUp { 35| 3| [super setUp]; 36| 3| self.activityIndicatorView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite]; 37| 3| self.request = [NSURLRequest requestWithURL:self.delayURL]; 38| 3| self.sessionManager = [[AFURLSessionManager alloc] initWithSessionConfiguration:nil]; 39| 3|} 40| | 41| 3|- (void)tearDown { 42| 3| [super tearDown]; 43| 3| [self.sessionManager invalidateSessionCancelingTasks:YES resetSession:NO]; 44| 3| self.sessionManager = nil; 45| 3|} 46| | 47| 1|- (void)testTaskDidResumeNotificationDoesNotCauseCrashForAIVWithTask { 48| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"No Crash"]; 49| 1| [self expectationForNotification:AFNetworkingTaskDidResumeNotification object:nil handler:nil]; 50| 1| NSURLSessionDataTask *task = [self.sessionManager 51| 1| dataTaskWithRequest:self.request 52| 1| uploadProgress:nil 53| 1| downloadProgress:nil 54| 1| completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) { 55| 1| [expectation fulfill]; 56| 1| }]; 57| 1| 58| 1| [self.activityIndicatorView setAnimatingWithStateOfTask:task]; 59| 1| self.activityIndicatorView = nil; 60| 1| 61| 1| [task resume]; 62| 1| [self waitForExpectationsWithCommonTimeout]; 63| 1| [task cancel]; 64| 1|} 65| | 66| | 67| 1|- (void)testTaskDidCompleteNotificationDoesNotCauseCrashForAIVWithTask { 68| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"No Crash"]; 69| 1| [self expectationForNotification:AFNetworkingTaskDidCompleteNotification object:nil handler:nil]; 70| 1| NSURLSessionDataTask *task = [self.sessionManager 71| 1| dataTaskWithRequest:self.request 72| 1| uploadProgress:nil 73| 1| downloadProgress:nil 74| 1| completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) { 75| 1| //Without the dispatch after, this test would PASS errorenously because the test 76| 1| //would finish before the notification was posted to all objects that were 77| 1| //observing it. 78| 1| dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 79| 1| [expectation fulfill]; 80| 1| }); 81| 1| }]; 82| 1| 83| 1| [self.activityIndicatorView setAnimatingWithStateOfTask:task]; 84| 1| self.activityIndicatorView = nil; 85| 1| 86| 1| [task resume]; 87| 1| [self waitForExpectationsWithCommonTimeout]; 88| 1| [task cancel]; 89| 1|} 90| | 91| 1|- (void)testTaskDidSuspendNotificationDoesNotCauseCrashForAIVWithTask { 92| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"No Crash"]; 93| 1| [self expectationForNotification:AFNetworkingTaskDidSuspendNotification object:nil handler:nil]; 94| 1| NSURLSessionDataTask *task = [self.sessionManager 95| 1| dataTaskWithRequest:self.request 96| 1| uploadProgress:nil 97| 1| downloadProgress:nil 98| 1| completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) { 99| 1| //Without the dispatch after, this test would PASS errorenously because the test 100| 1| //would finish before the notification was posted to all objects that were 101| 1| //observing it. 102| 1| dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 103| 1| [expectation fulfill]; 104| 1| }); 105| 1| }]; 106| 1| 107| 1| [self.activityIndicatorView setAnimatingWithStateOfTask:task]; 108| 1| self.activityIndicatorView = nil; 109| 1| 110| 1| [task resume]; 111| 1| [task suspend]; 112| 1| [task resume]; 113| 1| [self waitForExpectationsWithCommonTimeout]; 114| 1| [task cancel]; 115| 1|} 116| | 117| |@end /Users/travis/build/AFNetworking/AFNetworking/Tests/Tests/AFUIButtonTests.m: 1| |// AFUIButtonTests.h 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import 23| |#import "AFTestCase.h" 24| |#import "UIButton+AFNetworking.h" 25| |#import "AFImageDownloader.h" 26| | 27| |@interface AFUIButtonTests : AFTestCase 28| |@property (nonatomic, strong) UIImage *cachedImage; 29| |@property (nonatomic, strong) NSURLRequest *cachedImageRequest; 30| |@property (nonatomic, strong) UIButton *button; 31| | 32| |@property (nonatomic, strong) NSURLRequest *error404URLRequest; 33| | 34| |@property (nonatomic, strong) NSURLRequest *jpegURLRequest; 35| |@end 36| | 37| |@implementation AFUIButtonTests 38| | 39| 3|- (void)setUp { 40| 3| [super setUp]; 41| 3| [[UIButton sharedImageDownloader].imageCache removeAllImages]; 42| 3| [[[[[[UIButton sharedImageDownloader] sessionManager] session] configuration] URLCache] removeAllCachedResponses]; 43| 3| [UIButton setSharedImageDownloader:[[AFImageDownloader alloc] init]]; 44| 3| 45| 3| self.button = [UIButton new]; 46| 3| 47| 3| self.jpegURLRequest = [NSURLRequest requestWithURL:self.jpegURL]; 48| 3| 49| 3| self.error404URLRequest = [NSURLRequest requestWithURL:[self URLWithStatusCode:404]]; 50| 3|} 51| | 52| 3|- (void)tearDown { 53| 3| self.button = nil; 54| 3| [super tearDown]; 55| 3| 56| 3|} 57| | 58| 1|- (void)testThatBackgroundImageChanges { 59| 1| XCTAssertNil([self.button backgroundImageForState:UIControlStateNormal]); 60| 1| [self.button setBackgroundImageForState:UIControlStateNormal withURL:self.jpegURL]; 61| 1| NSPredicate *predicate = [NSPredicate predicateWithBlock:^BOOL(UIButton * _Nonnull button, NSDictionary * _Nullable bindings) { 62| 1| return [button backgroundImageForState:UIControlStateNormal] != nil; 63| 1| }]; 64| 1| 65| 1| [self expectationForPredicate:predicate 66| 1| evaluatedWithObject:self.button 67| 1| handler:nil]; 68| 1| 69| 1| [self waitForExpectationsWithCommonTimeout]; 70| 1|} 71| | 72| 1|- (void)testThatForegroundImageCanBeCancelledAndDownloadedImmediately { 73| 1| //https://github.com/Alamofire/AlamofireImage/issues/55 74| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 75| 1| [self.button setImageForState:UIControlStateNormal withURL:self.jpegURL]; 76| 1| [self.button cancelImageDownloadTaskForState:UIControlStateNormal]; 77| 1| __block UIImage *responseImage; 78| 1| [self.button 79| 1| setImageForState:UIControlStateNormal 80| 1| withURLRequest:self.jpegURLRequest 81| 1| placeholderImage:nil 82| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull image) { 83| 1| responseImage = image; 84| 1| [expectation fulfill]; 85| 1| } 86| 1| failure:nil]; 87| 1| [self waitForExpectationsWithCommonTimeout]; 88| 1| XCTAssertNotNil(responseImage); 89| 1|} 90| | 91| 1|- (void)testThatBackgroundImageCanBeCancelledAndDownloadedImmediately { 92| 1| //https://github.com/Alamofire/AlamofireImage/issues/55 93| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 94| 1| [self.button setBackgroundImageForState:UIControlStateNormal withURL:self.jpegURL]; 95| 1| [self.button cancelBackgroundImageDownloadTaskForState:UIControlStateNormal]; 96| 1| __block UIImage *responseImage; 97| 1| [self.button 98| 1| setBackgroundImageForState:UIControlStateNormal 99| 1| withURLRequest:self.jpegURLRequest 100| 1| placeholderImage:nil 101| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull image) { 102| 1| responseImage = image; 103| 1| [expectation fulfill]; 104| 1| } 105| 1| failure:nil]; 106| 1| [self waitForExpectationsWithCommonTimeout]; 107| 1| XCTAssertNotNil(responseImage); 108| 1|} 109| | 110| |@end /Users/travis/build/AFNetworking/AFNetworking/Tests/Tests/AFUIImageViewTests.m: 1| |// AFUIImageViewTests.h 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "AFTestCase.h" 23| |#import "UIImageView+AFNetworking.h" 24| |#import "AFImageDownloader.h" 25| | 26| |@interface AFUIImageViewTests : AFTestCase 27| |@property (nonatomic, strong) UIImage *cachedImage; 28| |@property (nonatomic, strong) NSURLRequest *cachedImageRequest; 29| |@property (nonatomic, strong) UIImageView *imageView; 30| | 31| |@property (nonatomic, strong) NSURLRequest *error404URLRequest; 32| | 33| |@property (nonatomic, strong) NSURLRequest *jpegURLRequest; 34| | 35| |@end 36| | 37| |@implementation AFUIImageViewTests 38| | 39| 7|- (void)setUp { 40| 7| [super setUp]; 41| 7| [[UIImageView sharedImageDownloader].imageCache removeAllImages]; 42| 7| [[[[[[UIImageView sharedImageDownloader] sessionManager] session] configuration] URLCache] removeAllCachedResponses]; 43| 7| [UIImageView setSharedImageDownloader:[[AFImageDownloader alloc] init]]; 44| 7| 45| 7| self.imageView = [UIImageView new]; 46| 7| 47| 7| self.jpegURLRequest = [NSURLRequest requestWithURL:self.jpegURL]; 48| 7| 49| 7| self.error404URLRequest = [NSURLRequest requestWithURL:[self URLWithStatusCode:404]]; 50| 7|} 51| | 52| 7|- (void)tearDown { 53| 7| self.imageView = nil; 54| 7| [super tearDown]; 55| 7| 56| 7|} 57| | 58| 1|- (void)testThatImageCanBeDownloadedFromURL { 59| 1| XCTAssertNil(self.imageView.image); 60| 1| [self.imageView setImageWithURL:self.jpegURL]; 61| 1| [self expectationForPredicate:[NSPredicate predicateWithFormat:@"image != nil"] 62| 1| evaluatedWithObject:self.imageView 63| 1| handler:nil]; 64| 1| [self waitForExpectationsWithCommonTimeout]; 65| 1|} 66| | 67| 1|- (void)testThatImageDownloadSucceedsWhenDuplicateRequestIsSentToImageView { 68| 1| XCTAssertNil(self.imageView.image); 69| 1| [self.imageView setImageWithURL:self.jpegURL]; 70| 1| [self.imageView setImageWithURL:self.jpegURL]; 71| 1| [self expectationForPredicate:[NSPredicate predicateWithFormat:@"image != nil"] 72| 1| evaluatedWithObject:self.imageView 73| 1| handler:nil]; 74| 1| [self waitForExpectationsWithCommonTimeout]; 75| 1|} 76| | 77| 1|- (void)testThatPlaceholderImageIsSetIfRequestFails { 78| 1| UIImage *placeholder = [UIImage imageNamed:@"logo"]; 79| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should fail"]; 80| 1| 81| 1| [self.imageView setImageWithURLRequest:self.error404URLRequest 82| 1| placeholderImage:placeholder 83| 1| success:nil 84| 1| failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) { 85| 1| [expectation fulfill]; 86| 1| }]; 87| 1| [self waitForExpectationsWithCommonTimeout]; 88| 1| XCTAssertEqual(self.imageView.image, placeholder); 89| 1|} 90| | 91| 1|- (void)testResponseIsNilWhenLoadedFromCache { 92| 1| AFImageDownloader *downloader = [UIImageView sharedImageDownloader]; 93| 1| XCTestExpectation *cacheExpectation = [self expectationWithDescription:@"Cache request should succeed"]; 94| 1| __block UIImage *downloadImage = nil; 95| 1| [downloader 96| 1| downloadImageForURLRequest:self.jpegURLRequest 97| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 98| 1| downloadImage = responseObject; 99| 1| [cacheExpectation fulfill]; 100| 1| } 101| 1| failure:nil]; 102| 1| [self waitForExpectationsWithCommonTimeout]; 103| 1| 104| 1| __block UIImage *cachedImage = nil; 105| 1| __block NSHTTPURLResponse *urlResponse; 106| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 107| 1| [self.imageView 108| 1| setImageWithURLRequest:self.jpegURLRequest 109| 1| placeholderImage:nil 110| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull image) { 111| 1| urlResponse = response; 112| 1| cachedImage = image; 113| 1| [expectation fulfill]; 114| 1| } 115| 1| failure:nil]; 116| 1| [self waitForExpectationsWithCommonTimeout]; 117| 1| XCTAssertNil(urlResponse); 118| 1| XCTAssertNotNil(cachedImage); 119| 1| XCTAssertEqual(cachedImage, downloadImage); 120| 1|} 121| | 122| 1|- (void)testThatImageCanBeCancelledAndDownloadedImmediately { 123| 1| //https://github.com/Alamofire/AlamofireImage/issues/55 124| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 125| 1| [self.imageView setImageWithURL:self.jpegURL]; 126| 1| [self.imageView cancelImageDownloadTask]; 127| 1| __block UIImage *responseImage; 128| 1| [self.imageView 129| 1| setImageWithURLRequest:self.jpegURLRequest 130| 1| placeholderImage:nil 131| 1| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull image) { 132| 1| responseImage = image; 133| 1| [expectation fulfill]; 134| 1| } 135| 1| failure:nil]; 136| 1| [self waitForExpectationsWithCommonTimeout]; 137| 1| XCTAssertNotNil(responseImage); 138| 1|} 139| | 140| 1|- (void)testThatImageDownloadFailsWhenUsingMalformedURLRequest { 141| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should fail"]; 142| 1| UIImage *placeholder = [UIImage imageNamed:@"logo"]; 143| 1| __block NSURLRequest *failureRequest; 144| 1| __block NSHTTPURLResponse *failureResponse; 145| 1| __block NSError *failureError; 146| 1| NSString *nilString; 147| 1| NSURLRequest *malformedRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:nilString]]; 148| 1| [self.imageView setImageWithURLRequest:malformedRequest 149| 1| placeholderImage:placeholder 150| 1| success:nil 151| 1| failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) { 152| 1| failureRequest = request; 153| 1| failureResponse = response; 154| 1| failureError = error; 155| 1| [expectation fulfill]; 156| 1| }]; 157| 1| [self waitForExpectationsWithCommonTimeout]; 158| 1| XCTAssertEqual(self.imageView.image, placeholder); 159| 1| XCTAssertEqual(failureRequest, malformedRequest); 160| 1| XCTAssertNil(failureResponse); 161| 1| XCTAssertNotNil(failureError); 162| 1|} 163| | 164| 1|- (void)testThatNilURLDoesntCrash { 165| 1|#pragma clang diagnostic push 166| 1|#pragma clang diagnostic ignored "-Wnonnull" 167| 1| [self.imageView setImageWithURL:nil]; 168| 1|#pragma clang diagnostic pop 169| 1| 170| 1|} 171| | 172| | 173| | 174| |@end /Users/travis/build/AFNetworking/AFNetworking/Tests/Tests/AFUIRefreshControlTests.m: 1| |// AFUIRefreshControlTests.h 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "AFTestCase.h" 23| |#import "UIRefreshControl+AFNetworking.h" 24| |#import "AFURLSessionManager.h" 25| | 26| |@interface AFUIRefreshControlTests : AFTestCase 27| |@property (nonatomic, strong) NSURLRequest *request; 28| |@property (nonatomic, strong) UIRefreshControl *refreshControl; 29| |@property (nonatomic, strong) AFURLSessionManager *sessionManager; 30| |@end 31| | 32| |@implementation AFUIRefreshControlTests 33| | 34| 3|- (void)setUp { 35| 3| [super setUp]; 36| 3| self.refreshControl = [[UIRefreshControl alloc] init]; 37| 3| self.request = [NSURLRequest requestWithURL:self.delayURL]; 38| 3| self.sessionManager = [[AFURLSessionManager alloc] initWithSessionConfiguration:nil]; 39| 3|} 40| | 41| 3|- (void)tearDown { 42| 3| [super tearDown]; 43| 3| [self.sessionManager invalidateSessionCancelingTasks:YES resetSession:NO]; 44| 3| self.sessionManager = nil; 45| 3|} 46| | 47| 1|- (void)testTaskDidResumeNotificationDoesNotCauseCrashForUIRCWithTask { 48| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"No Crash"]; 49| 1| [self expectationForNotification:AFNetworkingTaskDidResumeNotification object:nil handler:nil]; 50| 1| NSURLSessionDataTask *task = [self.sessionManager 51| 1| dataTaskWithRequest:self.request 52| 1| uploadProgress:nil 53| 1| downloadProgress:nil 54| 1| completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) { 55| 1| [expectation fulfill]; 56| 1| }]; 57| 1| 58| 1| [self.refreshControl setRefreshingWithStateOfTask:task]; 59| 1| self.refreshControl = nil; 60| 1| 61| 1| [task resume]; 62| 1| [self waitForExpectationsWithCommonTimeout]; 63| 1| [task cancel]; 64| 1|} 65| | 66| 1|- (void)testTaskDidCompleteNotificationDoesNotCauseCrashForUIRCWithTask { 67| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"No Crash"]; 68| 1| [self expectationForNotification:AFNetworkingTaskDidCompleteNotification object:nil handler:nil]; 69| 1| NSURLSessionDataTask *task = [self.sessionManager 70| 1| dataTaskWithRequest:self.request 71| 1| uploadProgress:nil 72| 1| downloadProgress:nil 73| 1| completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) { 74| 1| //Without the dispatch after, this test would PASS errorenously because the test 75| 1| //would finish before the notification was posted to all objects that were 76| 1| //observing it. 77| 1| dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 78| 1| [expectation fulfill]; 79| 1| }); 80| 1| }]; 81| 1| 82| 1| [self.refreshControl setRefreshingWithStateOfTask:task]; 83| 1| self.refreshControl = nil; 84| 1| 85| 1| [task resume]; 86| 1| [self waitForExpectationsWithCommonTimeout]; 87| 1| [task cancel]; 88| 1|} 89| | 90| 1|- (void)testTaskDidSuspendNotificationDoesNotCauseCrashForUIRCWithTask { 91| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"No Crash"]; 92| 1| [self expectationForNotification:AFNetworkingTaskDidSuspendNotification object:nil handler:nil]; 93| 1| NSURLSessionDataTask *task = [self.sessionManager 94| 1| dataTaskWithRequest:self.request 95| 1| uploadProgress:nil 96| 1| downloadProgress:nil 97| 1| completionHandler:^(NSURLResponse *response, id responseObject, NSError *error) { 98| 1| //Without the dispatch after, this test would PASS errorenously because the test 99| 1| //would finish before the notification was posted to all objects that were 100| 1| //observing it. 101| 1| dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 102| 1| [expectation fulfill]; 103| 1| }); 104| 1| }]; 105| 1| 106| 1| [self.refreshControl setRefreshingWithStateOfTask:task]; 107| 1| self.refreshControl = nil; 108| 1| 109| 1| [task resume]; 110| 1| [task suspend]; 111| 1| [task resume]; 112| 1| [self waitForExpectationsWithCommonTimeout]; 113| 1| [task cancel]; 114| 1|} 115| | 116| |@end /Users/travis/build/AFNetworking/AFNetworking/Tests/Tests/AFUIWebViewTests.m: 1| |// AFUIWebViewTests.h 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import 23| |#import "AFTestCase.h" 24| |#import "UIWebView+AFNetworking.h" 25| | 26| |@interface AFUIWebViewTests : AFTestCase 27| | 28| |@property (nonatomic, strong) UIWebView *webView; 29| |@property (nonatomic, strong) NSURLRequest *HTMLRequest; 30| | 31| |@end 32| | 33| |@implementation AFUIWebViewTests 34| | 35| 3|- (void)setUp { 36| 3| [super setUp]; 37| 3| self.webView = [UIWebView new]; 38| 3| self.HTMLRequest = [NSURLRequest requestWithURL:[self.baseURL URLByAppendingPathComponent:@"html"]]; 39| 3|} 40| | 41| 1|- (void)testNilProgressDoesNotCauseCrash { 42| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 43| 1| [self.webView 44| 1| loadRequest:self.HTMLRequest 45| 1| progress:nil 46| 1| success:^NSString * _Nonnull(NSHTTPURLResponse * _Nonnull response, NSString * _Nonnull HTML) { 47| 1| [expectation fulfill]; 48| 1| return HTML; 49| 1| } 50| 1| failure:nil]; 51| 1| [self waitForExpectationsWithCommonTimeout]; 52| 1|} 53| | 54| 1|- (void)testNULLProgressDoesNotCauseCrash { 55| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 56| 1| [self.webView 57| 1| loadRequest:self.HTMLRequest 58| 1| progress:NULL 59| 1| success:^NSString * _Nonnull(NSHTTPURLResponse * _Nonnull response, NSString * _Nonnull HTML) { 60| 1| [expectation fulfill]; 61| 1| return HTML; 62| 1| } 63| 1| failure:nil]; 64| 1| [self waitForExpectationsWithCommonTimeout]; 65| 1|} 66| | 67| |//- (void)testProgressIsSet { 68| |// NSProgress* progress = nil; 69| |// XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 70| |// [self.webView 71| |// loadRequest:self.HTMLRequest 72| |// progress:&progress 73| |// success:^NSString * _Nonnull(NSHTTPURLResponse * _Nonnull response, NSString * _Nonnull HTML) { 74| |// [expectation fulfill]; 75| |// return HTML; 76| |// } 77| |// failure:nil]; 78| |// [self keyValueObservingExpectationForObject:progress 79| |// keyPath:@"fractionCompleted" 80| |// expectedValue:@(1.0)]; 81| |// [self waitForExpectationsWithCommonTimeout]; 82| |//} 83| | 84| 1|- (void)testRequestWithCustomHeaders { 85| 1| NSMutableURLRequest *customHeaderRequest = [NSMutableURLRequest requestWithURL:[self.baseURL URLByAppendingPathComponent:@"headers"]]; 86| 1| [customHeaderRequest setValue:@"Custom-Header-Value" forHTTPHeaderField:@"Custom-Header-Field"]; 87| 1| XCTestExpectation *expectation = [self expectationWithDescription:@"Request should succeed"]; 88| 1| [self.webView 89| 1| loadRequest:customHeaderRequest 90| 1| progress:NULL 91| 1| success:^NSString * _Nonnull(NSHTTPURLResponse * _Nonnull response, NSString * _Nonnull string) { 92| 1| // Here string is actually JSON. 93| 1| NSDictionary *responseObject = [NSJSONSerialization JSONObjectWithData:[string dataUsingEncoding:NSUTF8StringEncoding] options:(NSJSONReadingOptions)0 error:nil]; 94| 1| 95| 1| NSDictionary *headers = responseObject[@"headers"]; 96| 1| XCTAssertTrue([headers[@"Custom-Header-Field"] isEqualToString:@"Custom-Header-Value"]); 97| 1| [expectation fulfill]; 98| 1| return string; 99| 1| } 100| 1| failure:nil]; 101| 1| [self waitForExpectationsWithCommonTimeout]; 102| 1|} 103| | 104| |@end /Users/travis/build/AFNetworking/AFNetworking/Tests/Tests/AFURLSessionManagerTests.m: 1| |// AFURLSessionManagerTests.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import 23| | 24| |#import "AFTestCase.h" 25| | 26| |#import "AFURLSessionManager.h" 27| | 28| |#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED 29| |#define NSFoundationVersionNumber_With_Fixed_28588583_bug 0.0 30| |#else 31| 31|#define NSFoundationVersionNumber_With_Fixed_28588583_bug DBL_MAX 32| |#endif 33| | 34| | 35| |@interface AFURLSessionManagerTests : AFTestCase 36| |@property (readwrite, nonatomic, strong) AFURLSessionManager *localManager; 37| |@property (readwrite, nonatomic, strong) AFURLSessionManager *backgroundManager; 38| |@end 39| | 40| |@implementation AFURLSessionManagerTests 41| | 42| 4|- (NSURLRequest *)bigImageURLRequest { 43| 4| NSURL *url = [NSURL URLWithString:@"http://scitechdaily.com/images/New-Image-of-the-Galaxy-Messier-94-also-Known-as-NGC-4736.jpg"]; 44| 4| NSURLRequest *request = [[NSURLRequest alloc] initWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60.0]; 45| 4| return request; 46| 4|} 47| | 48| 31|- (void)setUp { 49| 31| [super setUp]; 50| 31| self.localManager = [[AFURLSessionManager alloc] init]; 51| 31| [self.localManager.session.configuration.URLCache removeAllCachedResponses]; 52| 31| 53| 31| //It was discovered that background sessions were hanging the test target 54| 31| //on iOS 10 and Xcode 8. 55| 31| // 56| 31| //rdar://28588583 57| 31| // 58| 31| //For now, we'll disable the unit tests for background managers until that can 59| 31| //be resolved 60| 31| if (NSFoundationVersionNumber > NSFoundationVersionNumber_With_Fixed_28588583_bug) { 61| 0| NSString *identifier = [NSString stringWithFormat:@"com.afnetworking.tests.urlsession.%@", [[NSUUID UUID] UUIDString]]; 62| 0| NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:identifier]; 63| 0| self.backgroundManager = [[AFURLSessionManager alloc] initWithSessionConfiguration:configuration]; 64| 0| } 65| 31| else { 66| 31| self.backgroundManager = nil; 67| 31| } 68| 31|} 69| | 70| 31|- (void)tearDown { 71| 31| [super tearDown]; 72| 31| [self.localManager.session.configuration.URLCache removeAllCachedResponses]; 73| 31| [self.localManager invalidateSessionCancelingTasks:YES resetSession:NO]; 74| 31| self.localManager = nil; 75| 31| 76| 31| [self.backgroundManager invalidateSessionCancelingTasks:YES resetSession:NO]; 77| 31| self.backgroundManager = nil; 78| 31|} 79| | 80| |#pragma mark Progress - 81| | 82| 1|- (void)testDataTaskDoesReportDownloadProgress { 83| 1| NSURLSessionDataTask *task; 84| 1| 85| 1| __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Progress should equal 1.0"]; 86| 1| task = [self.localManager 87| 1| dataTaskWithRequest:[self bigImageURLRequest] 88| 1| uploadProgress:nil 89| 3| downloadProgress:^(NSProgress * _Nonnull downloadProgress) { 90| 3| if (downloadProgress.fractionCompleted == 1.0) { 91| 1| [expectation fulfill]; 92| 1| } 93| 3| } 94| 1| completionHandler:nil]; 95| 1| 96| 1| [task resume]; 97| 1| [self waitForExpectationsWithCommonTimeout]; 98| 1|} 99| | 100| 1|- (void)testDataTaskDownloadProgressCanBeKVOd { 101| 1| NSURLSessionDataTask *task; 102| 1| 103| 1| task = [self.localManager 104| 1| dataTaskWithRequest:[self bigImageURLRequest] 105| 1| uploadProgress:nil 106| 1| downloadProgress:nil 107| 1| completionHandler:nil]; 108| 1| 109| 1| NSProgress *progress = [self.localManager downloadProgressForTask:task]; 110| 1| [self keyValueObservingExpectationForObject:progress keyPath:@"fractionCompleted" 111| 3| handler:^BOOL(NSProgress *observedProgress, NSDictionary * _Nonnull change) { 112| 3| double new = [change[@"new"] doubleValue]; 113| 3| double old = [change[@"old"] doubleValue]; 114| 3| return new == 1.0 && old != 0.0; 115| 3| }]; 116| 1| [task resume]; 117| 1| [self waitForExpectationsWithCommonTimeout]; 118| 1|} 119| | 120| 1|- (void)testDownloadTaskDoesReportProgress { 121| 1| __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Progress should equal 1.0"]; 122| 1| NSURLSessionTask *task; 123| 1| task = [self.localManager 124| 1| downloadTaskWithRequest:[self bigImageURLRequest] 125| 3| progress:^(NSProgress * _Nonnull downloadProgress) { 126| 3| if (downloadProgress.fractionCompleted == 1.0) { 127| 1| [expectation fulfill]; 128| 1| } 129| 3| } 130| 1| destination:nil 131| 1| completionHandler:nil]; 132| 1| [task resume]; 133| 1| [self waitForExpectationsWithCommonTimeout]; 134| 1|} 135| | 136| 1|- (void)testSessionTaskDoesReportMetrics { 137| 99| [self expectationForNotification:AFNetworkingTaskDidCompleteNotification object:nil handler:^BOOL(NSNotification * _Nonnull notification) { 138| 99|#if AF_CAN_USE_AT_AVAILABLE && AF_CAN_INCLUDE_SESSION_TASK_METRICS 139| 99| if (@available(iOS 10, macOS 10.12, watchOS 3, tvOS 10, *)) { 140| 99| return [notification userInfo][AFNetworkingTaskDidCompleteSessionTaskMetrics] != nil; 141| 99| } 142| 0|#endif 143| 0| return YES; 144| 0| }]; 145| 1| 146| 1|#if AF_CAN_INCLUDE_SESSION_TASK_METRICS 147| 1| __weak XCTestExpectation *metricsBlock = [self expectationWithDescription:@"Metrics completion block is called"]; 148| 1| [self.localManager setTaskDidFinishCollectingMetricsBlock:^(NSURLSession * _Nonnull session, NSURLSessionTask * _Nonnull task, NSURLSessionTaskMetrics * _Nullable metrics) { 149| 1| [metricsBlock fulfill]; 150| 1| }]; 151| 1|#endif 152| 1| 153| 1| NSURLSessionTask *task = [self.localManager downloadTaskWithRequest:[self bigImageURLRequest] 154| 1| progress:nil 155| 1| destination:nil 156| 1| completionHandler:nil]; 157| 1| [task resume]; 158| 1| [self waitForExpectationsWithCommonTimeout]; 159| 1|} 160| | 161| 1|- (void)testSessionIsStillValid { 162| 1| 163| 1| NSURLSession *session = self.localManager.session; 164| 1| [self.localManager invalidateSessionCancelingTasks:YES resetSession:NO]; 165| 1| 166| 1| XCTAssertEqual(session, self.localManager.session); 167| 1|} 168| | 169| 1|- (void)testSessionRecreatesAgain { 170| 1| 171| 1| [self.localManager invalidateSessionCancelingTasks:YES resetSession:YES]; 172| 1| 173| 1| XCTAssertNotNil(self.localManager.session); 174| 1|} 175| | 176| 1|- (void)testUploadTaskDoesReportProgress { 177| 1| NSMutableString *payload = [NSMutableString stringWithString:@"AFNetworking"]; 178| 1.66k| while ([payload lengthOfBytesUsingEncoding:NSUTF8StringEncoding] < 20000) { 179| 1.66k| [payload appendString:@"AFNetworking"]; 180| 1.66k| } 181| 1| 182| 1| NSURL *url = [NSURL URLWithString:[[self.baseURL absoluteString] stringByAppendingString:@"/post"]]; 183| 1| NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60.0]; 184| 1| [request setHTTPMethod:@"POST"]; 185| 1| 186| 1| __weak XCTestExpectation *expectation = [self expectationWithDescription:@"Progress should equal 1.0"]; 187| 1| 188| 1| NSURLSessionTask *task; 189| 1| task = [self.localManager 190| 1| uploadTaskWithRequest:request 191| 1| fromData:[payload dataUsingEncoding:NSUTF8StringEncoding] 192| 1| progress:^(NSProgress * _Nonnull uploadProgress) { 193| 1| NSLog(@"%@", uploadProgress.localizedDescription); 194| 1| if (uploadProgress.fractionCompleted == 1.0) { 195| 1| [expectation fulfill]; 196| 1| } 197| 1| } 198| 1| completionHandler:nil]; 199| 1| [task resume]; 200| 1| [self waitForExpectationsWithCommonTimeout]; 201| 1|} 202| | 203| 1|- (void)testUploadProgressCanBeKVOd { 204| 1| NSMutableString *payload = [NSMutableString stringWithString:@"AFNetworking"]; 205| 1.66k| while ([payload lengthOfBytesUsingEncoding:NSUTF8StringEncoding] < 20000) { 206| 1.66k| [payload appendString:@"AFNetworking"]; 207| 1.66k| } 208| 1| 209| 1| NSURL *url = [NSURL URLWithString:[[self.baseURL absoluteString] stringByAppendingString:@"/post"]]; 210| 1| NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:60.0]; 211| 1| [request setHTTPMethod:@"POST"]; 212| 1| 213| 1| NSURLSessionTask *task; 214| 1| task = [self.localManager 215| 1| uploadTaskWithRequest:request 216| 1| fromData:[payload dataUsingEncoding:NSUTF8StringEncoding] 217| 1| progress:nil 218| 1| completionHandler:nil]; 219| 1| 220| 1| NSProgress *uploadProgress = [self.localManager uploadProgressForTask:task]; 221| 1| [self keyValueObservingExpectationForObject:uploadProgress keyPath:NSStringFromSelector(@selector(fractionCompleted)) expectedValue:@(1.0)]; 222| 1| 223| 1| [task resume]; 224| 1| [self waitForExpectationsWithCommonTimeout]; 225| 1|} 226| | 227| |#pragma mark - rdar://17029580 228| | 229| 1|- (void)testRDAR17029580IsFixed { 230| 1| //https://github.com/AFNetworking/AFNetworking/issues/2093 231| 1| //https://github.com/AFNetworking/AFNetworking/pull/3205 232| 1| //http://openradar.appspot.com/radar?id=5871104061079552 233| 1| dispatch_queue_t serial_queue = dispatch_queue_create("com.alamofire.networking.test.RDAR17029580", DISPATCH_QUEUE_SERIAL); 234| 1| NSMutableArray *taskIDs = [[NSMutableArray alloc] init]; 235| 101| for (NSInteger i = 0; i < 100; i++) { 236| 100| XCTestExpectation *expectation = [self expectationWithDescription:@"Wait for task creation"]; 237| 100| __block NSURLSessionTask *task; 238| 100| dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 239| 100| task = [self.localManager 240| 100| dataTaskWithRequest:[NSURLRequest requestWithURL:self.baseURL] 241| 100| uploadProgress:nil 242| 100| downloadProgress:nil 243| 100| completionHandler:nil]; 244| 100| dispatch_sync(serial_queue, ^{ 245| 100| XCTAssertFalse([taskIDs containsObject:@(task.taskIdentifier)]); 246| 100| [taskIDs addObject:@(task.taskIdentifier)]; 247| 100| }); 248| 100| [task cancel]; 249| 100| [expectation fulfill]; 250| 100| }); 251| 100| } 252| 1| [self waitForExpectationsWithCommonTimeout]; 253| 1|} 254| | 255| |#pragma mark - Issue #2702 Tests 256| |// The following tests are all releated to issue #2702 257| | 258| 1|- (void)testDidResumeNotificationIsReceivedByLocalDataTaskAfterResume { 259| 1| NSURLSessionDataTask *task = [self.localManager dataTaskWithRequest:[self _delayURLRequest] 260| 1| uploadProgress:nil 261| 1| downloadProgress:nil 262| 1| completionHandler:nil]; 263| 1| [self _testResumeNotificationForTask:task]; 264| 1|} 265| | 266| 1|- (void)testDidSuspendNotificationIsReceivedByLocalDataTaskAfterSuspend { 267| 1| NSURLSessionDataTask *task = [self.localManager dataTaskWithRequest:[self _delayURLRequest] 268| 1| uploadProgress:nil 269| 1| downloadProgress:nil 270| 1| completionHandler:nil]; 271| 1| [self _testSuspendNotificationForTask:task]; 272| 1|} 273| | 274| 1|- (void)testDidResumeNotificationIsReceivedByBackgroundDataTaskAfterResume { 275| 1| if (self.backgroundManager) { 276| 0| NSURLSessionDataTask *task = [self.backgroundManager dataTaskWithRequest:[self _delayURLRequest] 277| 0| uploadProgress:nil 278| 0| downloadProgress:nil 279| 0| completionHandler:nil]; 280| 0| [self _testResumeNotificationForTask:task]; 281| 0| } 282| 1|} 283| | 284| 1|- (void)testDidSuspendNotificationIsReceivedByBackgroundDataTaskAfterSuspend { 285| 1| if (self.backgroundManager) { 286| 0| NSURLSessionDataTask *task = [self.backgroundManager dataTaskWithRequest:[self _delayURLRequest] 287| 0| uploadProgress:nil 288| 0| downloadProgress:nil 289| 0| completionHandler:nil]; 290| 0| [self _testSuspendNotificationForTask:task]; 291| 0| } 292| 1|} 293| | 294| 1|- (void)testDidResumeNotificationIsReceivedByLocalUploadTaskAfterResume { 295| 1| NSURLSessionUploadTask *task = [self.localManager uploadTaskWithRequest:[self _delayURLRequest] 296| 1| fromData:[NSData data] 297| 1| progress:nil 298| 1| completionHandler:nil]; 299| 1| [self _testResumeNotificationForTask:task]; 300| 1|} 301| | 302| 1|- (void)testDidSuspendNotificationIsReceivedByLocalUploadTaskAfterSuspend { 303| 1| NSURLSessionUploadTask *task = [self.localManager uploadTaskWithRequest:[self _delayURLRequest] 304| 1| fromData:[NSData data] 305| 1| progress:nil 306| 1| completionHandler:nil]; 307| 1| [self _testSuspendNotificationForTask:task]; 308| 1|} 309| | 310| 1|- (void)testDidResumeNotificationIsReceivedByBackgroundUploadTaskAfterResume { 311| 1| if (self.backgroundManager) { 312| 0|#pragma GCC diagnostic push 313| 0|#pragma GCC diagnostic ignored "-Wnonnull" 314| 0| NSURLSessionUploadTask *task = [self.backgroundManager uploadTaskWithRequest:[self _delayURLRequest] 315| 0| fromFile:nil 316| 0| progress:nil 317| 0| completionHandler:nil]; 318| 0|#pragma clang diagnostic pop 319| 0| [self _testResumeNotificationForTask:task]; 320| 0| } 321| 1|} 322| | 323| 1|- (void)testDidSuspendNotificationIsReceivedByBackgroundUploadTaskAfterSuspend { 324| 1| if (self.backgroundManager) { 325| 0|#pragma GCC diagnostic push 326| 0|#pragma GCC diagnostic ignored "-Wnonnull" 327| 0| NSURLSessionUploadTask *task = [self.backgroundManager uploadTaskWithRequest:[self _delayURLRequest] 328| 0| fromFile:nil 329| 0| progress:nil 330| 0| completionHandler:nil]; 331| 0|#pragma clang diagnostic pop 332| 0| [self _testSuspendNotificationForTask:task]; 333| 0| } 334| 1|} 335| | 336| 1|- (void)testDidResumeNotificationIsReceivedByLocalDownloadTaskAfterResume { 337| 1| NSURLSessionDownloadTask *task = [self.localManager downloadTaskWithRequest:[self _delayURLRequest] 338| 1| progress:nil 339| 1| destination:nil 340| 1| completionHandler:nil]; 341| 1| [self _testResumeNotificationForTask:task]; 342| 1|} 343| | 344| 1|- (void)testDidSuspendNotificationIsReceivedByLocalDownloadTaskAfterSuspend { 345| 1| NSURLSessionDownloadTask *task = [self.localManager downloadTaskWithRequest:[self _delayURLRequest] 346| 1| progress:nil 347| 1| destination:nil 348| 1| completionHandler:nil]; 349| 1| [self _testSuspendNotificationForTask:task]; 350| 1|} 351| | 352| 1|- (void)testDidResumeNotificationIsReceivedByBackgroundDownloadTaskAfterResume { 353| 1| if (self.backgroundManager) { 354| 0| NSURLSessionDownloadTask *task = [self.backgroundManager downloadTaskWithRequest:[self _delayURLRequest] 355| 0| progress:nil 356| 0| destination:nil 357| 0| completionHandler:nil]; 358| 0| [self _testResumeNotificationForTask:task]; 359| 0| } 360| 1|} 361| | 362| 1|- (void)testDidSuspendNotificationIsReceivedByBackgroundDownloadTaskAfterSuspend { 363| 1| if (self.backgroundManager) { 364| 0| NSURLSessionDownloadTask *task = [self.backgroundManager downloadTaskWithRequest:[self _delayURLRequest] 365| 0| progress:nil 366| 0| destination:nil 367| 0| completionHandler:nil]; 368| 0| [self _testSuspendNotificationForTask:task]; 369| 0| } 370| 1|} 371| | 372| 1|- (void)testSwizzlingIsProperlyConfiguredForDummyClass { 373| 1| IMP originalAFResumeIMP = [self _originalAFResumeImplementation]; 374| 1| IMP originalAFSuspendIMP = [self _originalAFSuspendImplementation]; 375| 1| XCTAssert(originalAFResumeIMP, @"Swizzled af_resume Method Not Found"); 376| 1| XCTAssert(originalAFSuspendIMP, @"Swizzled af_suspend Method Not Found"); 377| 1| XCTAssertNotEqual(originalAFResumeIMP, originalAFSuspendIMP, @"af_resume and af_suspend should not be equal"); 378| 1|} 379| | 380| 1|- (void)testSwizzlingIsWorkingAsExpectedForForegroundDataTask { 381| 1| NSURLSessionTask *task = [self.localManager dataTaskWithRequest:[self _delayURLRequest] 382| 1| uploadProgress:nil 383| 1| downloadProgress:nil 384| 1| completionHandler:nil]; 385| 1| [self _testSwizzlingForTask:task]; 386| 1| [task cancel]; 387| 1|} 388| | 389| 1|- (void)testSwizzlingIsWorkingAsExpectedForForegroundUpload { 390| 1| NSURLSessionTask *task = [self.localManager uploadTaskWithRequest:[self _delayURLRequest] 391| 1| fromData:[NSData data] 392| 1| progress:nil 393| 1| completionHandler:nil]; 394| 1| [self _testSwizzlingForTask:task]; 395| 1| [task cancel]; 396| 1|} 397| | 398| 1|- (void)testSwizzlingIsWorkingAsExpectedForForegroundDownload { 399| 1| NSURLSessionTask *task = [self.localManager downloadTaskWithRequest:[self _delayURLRequest] 400| 1| progress:nil 401| 1| destination:nil 402| 1| completionHandler:nil]; 403| 1| [self _testSwizzlingForTask:task]; 404| 1| [task cancel]; 405| 1|} 406| | 407| 1|- (void)testSwizzlingIsWorkingAsExpectedForBackgroundDataTask { 408| 1| //iOS 7 doesn't let us use a background manager in these tests, so reference these 409| 1| //classes directly. There are tests below to confirm background manager continues 410| 1| //to return the exepcted classes going forward. If those fail in a future iOS version, 411| 1| //it should point us to a problem here. 412| 1| [self _testSwizzlingForTaskClass:NSClassFromString(@"__NSCFBackgroundDataTask")]; 413| 1|} 414| | 415| 1|- (void)testSwizzlingIsWorkingAsExpectedForBackgroundUploadTask { 416| 1| //iOS 7 doesn't let us use a background manager in these tests, so reference these 417| 1| //classes directly. There are tests below to confirm background manager continues 418| 1| //to return the exepcted classes going forward. If those fail in a future iOS version, 419| 1| //it should point us to a problem here. 420| 1| [self _testSwizzlingForTaskClass:NSClassFromString(@"__NSCFBackgroundUploadTask")]; 421| 1|} 422| | 423| 1|- (void)testSwizzlingIsWorkingAsExpectedForBackgroundDownloadTask { 424| 1| //iOS 7 doesn't let us use a background manager in these tests, so reference these 425| 1| //classes directly. There are tests below to confirm background manager continues 426| 1| //to return the exepcted classes going forward. If those fail in a future iOS version, 427| 1| //it should point us to a problem here. 428| 1| [self _testSwizzlingForTaskClass:NSClassFromString(@"__NSCFBackgroundDownloadTask")]; 429| 1|} 430| | 431| 1|- (void)testBackgroundManagerReturnsExpectedClassForDataTask { 432| 1| if (self.backgroundManager) { 433| 0| NSURLSessionTask *task = [self.backgroundManager dataTaskWithRequest:[self _delayURLRequest] 434| 0| uploadProgress:nil 435| 0| downloadProgress:nil 436| 0| completionHandler:nil]; 437| 0| XCTAssert([NSStringFromClass([task class]) isEqualToString:@"__NSCFBackgroundDataTask"]); 438| 0| [task cancel]; 439| 1| } else { 440| 1| NSLog(@"Unable to run %@ because self.backgroundManager is nil", NSStringFromSelector(_cmd)); 441| 1| } 442| 1|} 443| | 444| 1|- (void)testBackgroundManagerReturnsExpectedClassForUploadTask { 445| 1| if (self.backgroundManager) { 446| 0|#pragma GCC diagnostic push 447| 0|#pragma GCC diagnostic ignored "-Wnonnull" 448| 0| NSURLSessionTask *task = [self.backgroundManager uploadTaskWithRequest:[self _delayURLRequest] 449| 0| fromFile:nil 450| 0| progress:nil 451| 0| completionHandler:nil]; 452| 0|#pragma clang diagnostic pop 453| 0| XCTAssert([NSStringFromClass([task class]) isEqualToString:@"__NSCFBackgroundUploadTask"]); 454| 0| [task cancel]; 455| 1| } else { 456| 1| NSLog(@"Unable to run %@ because self.backgroundManager is nil", NSStringFromSelector(_cmd)); 457| 1| } 458| 1|} 459| | 460| 1|- (void)testBackgroundManagerReturnsExpectedClassForDownloadTask { 461| 1| if (self.backgroundManager) { 462| 0| NSURLSessionTask *task = [self.backgroundManager downloadTaskWithRequest:[self _delayURLRequest] 463| 0| progress:nil 464| 0| destination:nil 465| 0| completionHandler:nil]; 466| 0| XCTAssert([NSStringFromClass([task class]) isEqualToString:@"__NSCFBackgroundDownloadTask"]); 467| 0| [task cancel]; 468| 1| } else { 469| 1| NSLog(@"Unable to run %@ because self.backgroundManager is nil", NSStringFromSelector(_cmd)); 470| 1| } 471| 1|} 472| | 473| |#pragma mark - private 474| | 475| 3|- (void)_testResumeNotificationForTask:(NSURLSessionTask *)task { 476| 3| [self expectationForNotification:AFNetworkingTaskDidResumeNotification 477| 3| object:nil 478| 3| handler:nil]; 479| 3| [task resume]; 480| 3| [task suspend]; 481| 3| [task resume]; 482| 3| [self waitForExpectationsWithTimeout:2.0 handler:nil]; 483| 3| [task cancel]; 484| 3|} 485| | 486| 3|- (void)_testSuspendNotificationForTask:(NSURLSessionTask *)task { 487| 3| [self expectationForNotification:AFNetworkingTaskDidSuspendNotification 488| 3| object:nil 489| 3| handler:nil]; 490| 3| [task resume]; 491| 3| [task suspend]; 492| 3| [task resume]; 493| 3| [self waitForExpectationsWithTimeout:2.0 handler:nil]; 494| 3| [task cancel]; 495| 3|} 496| | 497| 9|- (NSURLRequest *)_delayURLRequest { 498| 9| return [NSURLRequest requestWithURL:self.delayURL]; 499| 9|} 500| | 501| 0|- (IMP)_implementationForTask:(NSURLSessionTask *)task selector:(SEL)selector { 502| 0| return [self _implementationForClass:[task class] selector:selector]; 503| 0|} 504| | 505| 24|- (IMP)_implementationForClass:(Class)class selector:(SEL)selector { 506| 24| return method_getImplementation(class_getInstanceMethod(class, selector)); 507| 24|} 508| | 509| |#pragma clang diagnostic push 510| |#pragma clang diagnostic ignored "-Wundeclared-selector" 511| 7|- (IMP)_originalAFResumeImplementation { 512| 7| return method_getImplementation(class_getInstanceMethod(NSClassFromString(@"_AFURLSessionTaskSwizzling"), @selector(af_resume))); 513| 7|} 514| | 515| 7|- (IMP)_originalAFSuspendImplementation { 516| 7| return method_getImplementation(class_getInstanceMethod(NSClassFromString(@"_AFURLSessionTaskSwizzling"), @selector(af_suspend))); 517| 7|} 518| | 519| 3|- (void)_testSwizzlingForTask:(NSURLSessionTask *)task { 520| 3| [self _testSwizzlingForTaskClass:[task class]]; 521| 3|} 522| | 523| 6|- (void)_testSwizzlingForTaskClass:(Class)class { 524| 6| IMP originalAFResumeIMP = [self _originalAFResumeImplementation]; 525| 6| IMP originalAFSuspendIMP = [self _originalAFSuspendImplementation]; 526| 6| 527| 6| IMP taskResumeImp = [self _implementationForClass:class selector:@selector(resume)]; 528| 6| IMP taskSuspendImp = [self _implementationForClass:class selector:@selector(suspend)]; 529| 6| XCTAssertEqual(originalAFResumeIMP, taskResumeImp, @"resume has not been properly swizzled for %@", NSStringFromClass(class)); 530| 6| XCTAssertEqual(originalAFSuspendIMP, taskSuspendImp, @"suspend has not been properly swizzled for %@", NSStringFromClass(class)); 531| 6| 532| 6| IMP taskAFResumeImp = [self _implementationForClass:class selector:@selector(af_resume)]; 533| 6| IMP taskAFSuspendImp = [self _implementationForClass:class selector:@selector(af_suspend)]; 534| 6| XCTAssert(taskAFResumeImp != NULL, @"af_resume is nil. Something has not been been swizzled right for %@", NSStringFromClass(class)); 535| 6| XCTAssertNotEqual(taskAFResumeImp, taskResumeImp, @"af_resume has not been properly swizzled for %@", NSStringFromClass(class)); 536| 6| XCTAssert(taskAFSuspendImp != NULL, @"af_suspend is nil. Something has not been been swizzled right for %@", NSStringFromClass(class)); 537| 6| XCTAssertNotEqual(taskAFSuspendImp, taskSuspendImp, @"af_suspend has not been properly swizzled for %@", NSStringFromClass(class)); 538| 6|} 539| |#pragma clang diagnostic pop 540| | 541| |@end /Users/travis/build/AFNetworking/AFNetworking/Tests/Tests/AFXMLParserResponseSerializerTests.m: 1| |// AFXMLParserResponseSerializerTests.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "AFTestCase.h" 23| | 24| |#import "AFURLRequestSerialization.h" 25| |#import "AFURLResponseSerialization.h" 26| | 27| 4|static NSData * AFXMLTestData() { 28| 4| return [@"someValue" dataUsingEncoding:NSUTF8StringEncoding]; 29| 4|} 30| | 31| |#pragma mark - 32| | 33| |@interface AFXMLParserResponseSerializerTests : AFTestCase 34| |@property (nonatomic, strong) AFXMLParserResponseSerializer *responseSerializer; 35| |@end 36| | 37| |#pragma mark - 38| | 39| |@implementation AFXMLParserResponseSerializerTests 40| | 41| 5|- (void)setUp { 42| 5| [super setUp]; 43| 5| self.responseSerializer = [AFXMLParserResponseSerializer serializer]; 44| 5|} 45| | 46| 1|- (void)testThatXMLParserResponseSerializerAcceptsApplicationXMLMimeType { 47| 1| NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.baseURL statusCode:200 HTTPVersion:@"1.1" headerFields:@{@"Content-Type": @"application/xml"}]; 48| 1| NSError *error = nil; 49| 1| [self.responseSerializer validateResponse:response data:AFXMLTestData() error:&error]; 50| 1| 51| 1| XCTAssertNil(error, @"Error handling application/xml"); 52| 1|} 53| | 54| 1|- (void)testThatXMLParserResponseSerializerAcceptsTextXMLMimeType { 55| 1| NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.baseURL statusCode:200 HTTPVersion:@"1.1" headerFields:@{@"Content-Type": @"text/xml"}]; 56| 1| NSError *error = nil; 57| 1| [self.responseSerializer validateResponse:response data:AFXMLTestData() error:&error]; 58| 1| 59| 1| XCTAssertNil(error, @"Error handling text/xml"); 60| 1|} 61| | 62| 1|- (void)testThatXMLParserResponseSerializerDoesNotAcceptsNonStandardXMLMimeType { 63| 1| NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.baseURL statusCode:200 HTTPVersion:@"1.1" headerFields:@{@"Content-Type": @"nonstandard/xml"}]; 64| 1| NSError *error = nil; 65| 1| [self.responseSerializer validateResponse:response data:AFXMLTestData() error:&error]; 66| 1| 67| 1| XCTAssertNotNil(error, @"Error should have been thrown for nonstandard/xml"); 68| 1|} 69| | 70| 1|- (void)testThatXMLParserResponseSerializerReturnsNSXMLParserObjectForValidXML { 71| 1| NSHTTPURLResponse *response = [[NSHTTPURLResponse alloc] initWithURL:self.baseURL statusCode:200 HTTPVersion:@"1.1" headerFields:@{@"Content-Type": @"application/xml"}]; 72| 1| NSError *error = nil; 73| 1| id responseObject = [self.responseSerializer responseObjectForResponse:response data:AFXMLTestData() error:&error]; 74| 1| 75| 1| XCTAssertNil(error, @"Serialization error should be nil"); 76| 1| XCTAssert([responseObject isKindOfClass:[NSXMLParser class]], @"Expected response to be a NSXMLParser"); 77| 1|} 78| | 79| 1|- (void)testThatXMLParserResponseSerializerCanBeCopied { 80| 1| [self.responseSerializer setAcceptableStatusCodes:[NSIndexSet indexSetWithIndex:100]]; 81| 1| [self.responseSerializer setAcceptableContentTypes:[NSSet setWithObject:@"test/type"]]; 82| 1| 83| 1| AFXMLParserResponseSerializer *copiedSerializer = [self.responseSerializer copy]; 84| 1| XCTAssertNotEqual(copiedSerializer, self.responseSerializer); 85| 1| XCTAssertEqual(copiedSerializer.acceptableStatusCodes, self.responseSerializer.acceptableStatusCodes); 86| 1| XCTAssertEqual(copiedSerializer.acceptableContentTypes, self.responseSerializer.acceptableContentTypes); 87| 1|} 88| | 89| |@end <<<<<< EOF # path=fastlane/report.xml <<<<<< EOF # path=AFNetworking.framework.coverage.txt /Users/travis/build/AFNetworking/AFNetworking/AFNetworking/AFHTTPSessionManager.m: 1| |// AFHTTPSessionManager.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "AFHTTPSessionManager.h" 23| | 24| |#import "AFURLRequestSerialization.h" 25| |#import "AFURLResponseSerialization.h" 26| | 27| |#import 28| |#import 29| |#import 30| | 31| |#import 32| |#import 33| |#import 34| |#import 35| |#import 36| | 37| |#if TARGET_OS_IOS || TARGET_OS_TV 38| |#import 39| |#elif TARGET_OS_WATCH 40| |#import 41| |#endif 42| | 43| |@interface AFHTTPSessionManager () 44| |@property (readwrite, nonatomic, strong) NSURL *baseURL; 45| |@end 46| | 47| |@implementation AFHTTPSessionManager 48| |@dynamic responseSerializer; 49| | 50| 1|+ (instancetype)manager { 51| 1| return [[[self class] alloc] initWithBaseURL:nil]; 52| 1|} 53| | 54| 2|- (instancetype)init { 55| 2| return [self initWithBaseURL:nil]; 56| 2|} 57| | 58| 59|- (instancetype)initWithBaseURL:(NSURL *)url { 59| 59| return [self initWithBaseURL:url sessionConfiguration:nil]; 60| 59|} 61| | 62| 30|- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration { 63| 30| return [self initWithBaseURL:nil sessionConfiguration:configuration]; 64| 30|} 65| | 66| |- (instancetype)initWithBaseURL:(NSURL *)url 67| | sessionConfiguration:(NSURLSessionConfiguration *)configuration 68| 95|{ 69| 95| self = [super initWithSessionConfiguration:configuration]; 70| 95| if (!self) { 71| 0| return nil; 72| 0| } 73| 95| 74| 95| // Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected 75| 95| if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) { 76| 0| url = [url URLByAppendingPathComponent:@""]; 77| 0| } 78| 95| 79| 95| self.baseURL = url; 80| 95| 81| 95| self.requestSerializer = [AFHTTPRequestSerializer serializer]; 82| 95| self.responseSerializer = [AFJSONResponseSerializer serializer]; 83| 95| 84| 95| return self; 85| 95|} 86| | 87| |#pragma mark - 88| | 89| 98|- (void)setRequestSerializer:(AFHTTPRequestSerializer *)requestSerializer { 90| 98| NSParameterAssert(requestSerializer); 91| 98| 92| 98| _requestSerializer = requestSerializer; 93| 98|} 94| | 95| 224|- (void)setResponseSerializer:(AFHTTPResponseSerializer *)responseSerializer { 96| 224| NSParameterAssert(responseSerializer); 97| 224| 98| 224| [super setResponseSerializer:responseSerializer]; 99| 224|} 100| | 101| |@dynamic securityPolicy; 102| | 103| 107|- (void)setSecurityPolicy:(AFSecurityPolicy *)securityPolicy { 104| 107| if (securityPolicy.SSLPinningMode != AFSSLPinningModeNone && ![self.baseURL.scheme isEqualToString:@"https"]) { 105| 4| NSString *pinningMode = @"Unknown Pinning Mode"; 106| 4| switch (securityPolicy.SSLPinningMode) { 107| 4| case AFSSLPinningModeNone: pinningMode = @"AFSSLPinningModeNone"; break; 108| 4| case AFSSLPinningModeCertificate: pinningMode = @"AFSSLPinningModeCertificate"; break; 109| 4| case AFSSLPinningModePublicKey: pinningMode = @"AFSSLPinningModePublicKey"; break; 110| 4| } 111| 4| NSString *reason = [NSString stringWithFormat:@"A security policy configured with `%@` can only be applied on a manager with a secure base URL (i.e. https)", pinningMode]; 112| 4| @throw [NSException exceptionWithName:@"Invalid Security Policy" reason:reason userInfo:nil]; 113| 4| } 114| 107| 115| 107| [super setSecurityPolicy:securityPolicy]; 116| 107|} 117| | 118| |#pragma mark - 119| | 120| |- (NSURLSessionDataTask *)GET:(NSString *)URLString 121| | parameters:(id)parameters 122| | success:(void (^)(NSURLSessionDataTask *task, id responseObject))success 123| | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure 124| 1|{ 125| 1| 126| 1| return [self GET:URLString parameters:parameters headers:nil progress:nil success:success failure:failure]; 127| 1|} 128| | 129| |- (NSURLSessionDataTask *)GET:(NSString *)URLString 130| | parameters:(id)parameters 131| | progress:(void (^)(NSProgress * _Nonnull))downloadProgress 132| | success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success 133| | failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure 134| 2|{ 135| 2| 136| 2| return [self GET:URLString parameters:parameters headers:nil progress:downloadProgress success:success failure:failure]; 137| 2|} 138| | 139| |- (NSURLSessionDataTask *)GET:(NSString *)URLString 140| | parameters:(id)parameters 141| | headers:(nullable NSDictionary *)headers 142| | progress:(void (^)(NSProgress * _Nonnull))downloadProgress 143| | success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success 144| | failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure 145| 17|{ 146| 17| 147| 17| NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET" 148| 17| URLString:URLString 149| 17| parameters:parameters 150| 17| headers:headers 151| 17| uploadProgress:nil 152| 17| downloadProgress:downloadProgress 153| 17| success:success 154| 17| failure:failure]; 155| 17| 156| 17| [dataTask resume]; 157| 17| 158| 17| return dataTask; 159| 17|} 160| | 161| |- (NSURLSessionDataTask *)HEAD:(NSString *)URLString 162| | parameters:(id)parameters 163| | success:(void (^)(NSURLSessionDataTask *task))success 164| | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure 165| 1|{ 166| 1| return [self HEAD:URLString parameters:parameters headers:nil success:success failure:failure]; 167| 1|} 168| | 169| |- (NSURLSessionDataTask *)HEAD:(NSString *)URLString 170| | parameters:(id)parameters 171| | headers:(NSDictionary *)headers 172| | success:(void (^)(NSURLSessionDataTask * _Nonnull))success 173| | failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure 174| 2|{ 175| 2| NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"HEAD" URLString:URLString parameters:parameters headers:headers uploadProgress:nil downloadProgress:nil success:^(NSURLSessionDataTask *task, __unused id responseObject) { 176| 2| if (success) { 177| 2| success(task); 178| 2| } 179| 2| } failure:failure]; 180| 2| 181| 2| [dataTask resume]; 182| 2| 183| 2| return dataTask; 184| 2|} 185| | 186| |- (NSURLSessionDataTask *)POST:(NSString *)URLString 187| | parameters:(id)parameters 188| | success:(void (^)(NSURLSessionDataTask *task, id responseObject))success 189| | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure 190| 1|{ 191| 1| return [self POST:URLString parameters:parameters headers:nil progress:nil success:success failure:failure]; 192| 1|} 193| | 194| |- (NSURLSessionDataTask *)POST:(NSString *)URLString 195| | parameters:(id)parameters 196| | progress:(void (^)(NSProgress * _Nonnull))uploadProgress 197| | success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success 198| | failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure 199| 2|{ 200| 2| return [self POST:URLString parameters:parameters headers:nil progress:uploadProgress success:success failure:failure]; 201| 2|} 202| | 203| |- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString 204| | parameters:(nullable id)parameters 205| | headers:(nullable NSDictionary *)headers 206| | progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress 207| | success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success 208| | failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure 209| 5|{ 210| 5| NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"POST" URLString:URLString parameters:parameters headers:headers uploadProgress:uploadProgress downloadProgress:nil success:success failure:failure]; 211| 5| 212| 5| [dataTask resume]; 213| 5| 214| 5| return dataTask; 215| 5|} 216| | 217| |- (NSURLSessionDataTask *)POST:(NSString *)URLString 218| | parameters:(nullable id)parameters 219| | constructingBodyWithBlock:(nullable void (^)(id _Nonnull))block 220| | success:(nullable void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success 221| | failure:(nullable void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure 222| 1|{ 223| 1| return [self POST:URLString parameters:parameters headers:nil constructingBodyWithBlock:block progress:nil success:success failure:failure]; 224| 1|} 225| | 226| |- (NSURLSessionDataTask *)POST:(NSString *)URLString 227| | parameters:(id)parameters 228| | constructingBodyWithBlock:(void (^)(id formData))block 229| | progress:(nullable void (^)(NSProgress * _Nonnull))uploadProgress 230| | success:(void (^)(NSURLSessionDataTask *task, id responseObject))success 231| | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure 232| 2|{ 233| 2| return [self POST:URLString parameters:parameters headers:nil constructingBodyWithBlock:block progress:uploadProgress success:success failure:failure]; 234| 2|} 235| | 236| |- (NSURLSessionDataTask *)POST:(NSString *)URLString 237| | parameters:(id)parameters 238| | headers:(NSDictionary *)headers 239| | constructingBodyWithBlock:(void (^)(id _Nonnull))block 240| | progress:(void (^)(NSProgress * _Nonnull))uploadProgress 241| | success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure 242| 5|{ 243| 5| NSError *serializationError = nil; 244| 5| NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:&serializationError]; 245| 5| for (NSString *headerField in headers.keyEnumerator) { 246| 1| [request addValue:headers[headerField] forHTTPHeaderField:headerField]; 247| 1| } 248| 5| if (serializationError) { 249| 0| if (failure) { 250| 0| dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{ 251| 0| failure(nil, serializationError); 252| 0| }); 253| 0| } 254| 0| 255| 0| return nil; 256| 0| } 257| 5| 258| 5| __block NSURLSessionDataTask *task = [self uploadTaskWithStreamedRequest:request progress:uploadProgress completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) { 259| 5| if (error) { 260| 2| if (failure) { 261| 0| failure(task, error); 262| 0| } 263| 3| } else { 264| 3| if (success) { 265| 3| success(task, responseObject); 266| 3| } 267| 3| } 268| 5| }]; 269| 5| 270| 5| [task resume]; 271| 5| 272| 5| return task; 273| 5|} 274| | 275| |- (NSURLSessionDataTask *)PUT:(NSString *)URLString 276| | parameters:(id)parameters 277| | success:(void (^)(NSURLSessionDataTask *task, id responseObject))success 278| | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure 279| 1|{ 280| 1| return [self PUT:URLString parameters:parameters headers:nil success:success failure:failure]; 281| 1|} 282| | 283| |- (NSURLSessionDataTask *)PUT:(NSString *)URLString 284| | parameters:(id)parameters 285| | headers:(NSDictionary *)headers 286| | success:(void (^)(NSURLSessionDataTask *task, id responseObject))success 287| | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure 288| 2|{ 289| 2| NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"PUT" URLString:URLString parameters:parameters headers:headers uploadProgress:nil downloadProgress:nil success:success failure:failure]; 290| 2| 291| 2| [dataTask resume]; 292| 2| 293| 2| return dataTask; 294| 2|} 295| | 296| |- (NSURLSessionDataTask *)PATCH:(NSString *)URLString 297| | parameters:(id)parameters 298| | success:(void (^)(NSURLSessionDataTask *task, id responseObject))success 299| | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure 300| 1|{ 301| 1| return [self PATCH:URLString parameters:parameters headers:nil success:success failure:failure]; 302| 1|} 303| | 304| |- (NSURLSessionDataTask *)PATCH:(NSString *)URLString 305| | parameters:(id)parameters 306| | headers:(NSDictionary *)headers 307| | success:(void (^)(NSURLSessionDataTask *task, id responseObject))success 308| | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure 309| 2|{ 310| 2| NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"PATCH" URLString:URLString parameters:parameters headers:headers uploadProgress:nil downloadProgress:nil success:success failure:failure]; 311| 2| 312| 2| [dataTask resume]; 313| 2| 314| 2| return dataTask; 315| 2|} 316| | 317| |- (NSURLSessionDataTask *)DELETE:(NSString *)URLString 318| | parameters:(id)parameters 319| | success:(void (^)(NSURLSessionDataTask *task, id responseObject))success 320| | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure 321| 1|{ 322| 1| return [self DELETE:URLString parameters:parameters headers:nil success:success failure:failure]; 323| 1|} 324| | 325| |- (NSURLSessionDataTask *)DELETE:(NSString *)URLString 326| | parameters:(id)parameters 327| | headers:(NSDictionary *)headers 328| | success:(void (^)(NSURLSessionDataTask *task, id responseObject))success 329| | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure 330| 2|{ 331| 2| NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"DELETE" URLString:URLString parameters:parameters headers:headers uploadProgress:nil downloadProgress:nil success:success failure:failure]; 332| 2| 333| 2| [dataTask resume]; 334| 2| 335| 2| return dataTask; 336| 2|} 337| | 338| |- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method 339| | URLString:(NSString *)URLString 340| | parameters:(id)parameters 341| | headers:(NSDictionary *)headers 342| | uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress 343| | downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress 344| | success:(void (^)(NSURLSessionDataTask *, id))success 345| | failure:(void (^)(NSURLSessionDataTask *, NSError *))failure 346| 30|{ 347| 30| NSError *serializationError = nil; 348| 30| NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError]; 349| 30| for (NSString *headerField in headers.keyEnumerator) { 350| 4| [request addValue:headers[headerField] forHTTPHeaderField:headerField]; 351| 4| } 352| 30| if (serializationError) { 353| 1| if (failure) { 354| 1| dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{ 355| 1| failure(nil, serializationError); 356| 1| }); 357| 1| } 358| 1| 359| 1| return nil; 360| 1| } 361| 29| 362| 29| __block NSURLSessionDataTask *dataTask = nil; 363| 29| dataTask = [self dataTaskWithRequest:request 364| 29| uploadProgress:uploadProgress 365| 29| downloadProgress:downloadProgress 366| 29| completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) { 367| 29| if (error) { 368| 8| if (failure) { 369| 4| failure(dataTask, error); 370| 4| } 371| 21| } else { 372| 21| if (success) { 373| 21| success(dataTask, responseObject); 374| 21| } 375| 21| } 376| 29| }]; 377| 29| 378| 29| return dataTask; 379| 29|} 380| | 381| |#pragma mark - NSObject 382| | 383| 0|- (NSString *)description { 384| 0| return [NSString stringWithFormat:@"<%@: %p, baseURL: %@, session: %@, operationQueue: %@>", NSStringFromClass([self class]), self, [self.baseURL absoluteString], self.session, self.operationQueue]; 385| 0|} 386| | 387| |#pragma mark - NSSecureCoding 388| | 389| 1|+ (BOOL)supportsSecureCoding { 390| 1| return YES; 391| 1|} 392| | 393| 1|- (instancetype)initWithCoder:(NSCoder *)decoder { 394| 1| NSURL *baseURL = [decoder decodeObjectOfClass:[NSURL class] forKey:NSStringFromSelector(@selector(baseURL))]; 395| 1| NSURLSessionConfiguration *configuration = [decoder decodeObjectOfClass:[NSURLSessionConfiguration class] forKey:@"sessionConfiguration"]; 396| 1| if (!configuration) { 397| 0| NSString *configurationIdentifier = [decoder decodeObjectOfClass:[NSString class] forKey:@"identifier"]; 398| 0| if (configurationIdentifier) { 399| 0|#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 80000) || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1100) 400| 0| configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:configurationIdentifier]; 401| |#else 402| | configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:configurationIdentifier]; 403| |#endif 404| | } 405| 0| } 406| 1| 407| 1| self = [self initWithBaseURL:baseURL sessionConfiguration:configuration]; 408| 1| if (!self) { 409| 0| return nil; 410| 0| } 411| 1| 412| 1| self.requestSerializer = [decoder decodeObjectOfClass:[AFHTTPRequestSerializer class] forKey:NSStringFromSelector(@selector(requestSerializer))]; 413| 1| self.responseSerializer = [decoder decodeObjectOfClass:[AFHTTPResponseSerializer class] forKey:NSStringFromSelector(@selector(responseSerializer))]; 414| 1| AFSecurityPolicy *decodedPolicy = [decoder decodeObjectOfClass:[AFSecurityPolicy class] forKey:NSStringFromSelector(@selector(securityPolicy))]; 415| 1| if (decodedPolicy) { 416| 1| self.securityPolicy = decodedPolicy; 417| 1| } 418| 1| 419| 1| return self; 420| 1|} 421| | 422| 2|- (void)encodeWithCoder:(NSCoder *)coder { 423| 2| [super encodeWithCoder:coder]; 424| 2| 425| 2| [coder encodeObject:self.baseURL forKey:NSStringFromSelector(@selector(baseURL))]; 426| 2| if ([self.session.configuration conformsToProtocol:@protocol(NSCoding)]) { 427| 2| [coder encodeObject:self.session.configuration forKey:@"sessionConfiguration"]; 428| 2| } else { 429| 0| [coder encodeObject:self.session.configuration.identifier forKey:@"identifier"]; 430| 0| } 431| 2| [coder encodeObject:self.requestSerializer forKey:NSStringFromSelector(@selector(requestSerializer))]; 432| 2| [coder encodeObject:self.responseSerializer forKey:NSStringFromSelector(@selector(responseSerializer))]; 433| 2| [coder encodeObject:self.securityPolicy forKey:NSStringFromSelector(@selector(securityPolicy))]; 434| 2|} 435| | 436| |#pragma mark - NSCopying 437| | 438| 1|- (instancetype)copyWithZone:(NSZone *)zone { 439| 1| AFHTTPSessionManager *HTTPClient = [[[self class] allocWithZone:zone] initWithBaseURL:self.baseURL sessionConfiguration:self.session.configuration]; 440| 1| 441| 1| HTTPClient.requestSerializer = [self.requestSerializer copyWithZone:zone]; 442| 1| HTTPClient.responseSerializer = [self.responseSerializer copyWithZone:zone]; 443| 1| HTTPClient.securityPolicy = [self.securityPolicy copyWithZone:zone]; 444| 1| return HTTPClient; 445| 1|} 446| | 447| |@end /Users/travis/build/AFNetworking/AFNetworking/AFNetworking/AFNetworkReachabilityManager.m: 1| |// AFNetworkReachabilityManager.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "AFNetworkReachabilityManager.h" 23| |#if !TARGET_OS_WATCH 24| | 25| |#import 26| |#import 27| |#import 28| |#import 29| |#import 30| | 31| |NSString * const AFNetworkingReachabilityDidChangeNotification = @"com.alamofire.networking.reachability.change"; 32| |NSString * const AFNetworkingReachabilityNotificationStatusItem = @"AFNetworkingReachabilityNotificationStatusItem"; 33| | 34| |typedef void (^AFNetworkReachabilityStatusBlock)(AFNetworkReachabilityStatus status); 35| |typedef AFNetworkReachabilityManager * (^AFNetworkReachabilityStatusCallback)(AFNetworkReachabilityStatus status); 36| | 37| 0|NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status) { 38| 0| switch (status) { 39| 0| case AFNetworkReachabilityStatusNotReachable: 40| 0| return NSLocalizedStringFromTable(@"Not Reachable", @"AFNetworking", nil); 41| 0| case AFNetworkReachabilityStatusReachableViaWWAN: 42| 0| return NSLocalizedStringFromTable(@"Reachable via WWAN", @"AFNetworking", nil); 43| 0| case AFNetworkReachabilityStatusReachableViaWiFi: 44| 0| return NSLocalizedStringFromTable(@"Reachable via WiFi", @"AFNetworking", nil); 45| 0| case AFNetworkReachabilityStatusUnknown: 46| 0| default: 47| 0| return NSLocalizedStringFromTable(@"Unknown", @"AFNetworking", nil); 48| 0| } 49| 0|} 50| | 51| 7|static AFNetworkReachabilityStatus AFNetworkReachabilityStatusForFlags(SCNetworkReachabilityFlags flags) { 52| 7| BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0); 53| 7| BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0); 54| 7| BOOL canConnectionAutomatically = (((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)); 55| 7| BOOL canConnectWithoutUserInteraction = (canConnectionAutomatically && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0); 56| 7| BOOL isNetworkReachable = (isReachable && (!needsConnection || canConnectWithoutUserInteraction)); 57| 7| 58| 7| AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusUnknown; 59| 7| if (isNetworkReachable == NO) { 60| 0| status = AFNetworkReachabilityStatusNotReachable; 61| 0| } 62| 7|#if TARGET_OS_IPHONE 63| 7| else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0) { 64| 0| status = AFNetworkReachabilityStatusReachableViaWWAN; 65| 0| } 66| 7|#endif 67| 7| else { 68| 7| status = AFNetworkReachabilityStatusReachableViaWiFi; 69| 7| } 70| 7| 71| 7| return status; 72| 7|} 73| | 74| |/** 75| | * Queue a status change notification for the main thread. 76| | * 77| | * This is done to ensure that the notifications are received in the same order 78| | * as they are sent. If notifications are sent directly, it is possible that 79| | * a queued notification (for an earlier status condition) is processed after 80| | * the later update, resulting in the listener being left in the wrong state. 81| | */ 82| 7|static void AFPostReachabilityStatusChange(SCNetworkReachabilityFlags flags, AFNetworkReachabilityStatusCallback block) { 83| 7| AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags); 84| 7| dispatch_async(dispatch_get_main_queue(), ^{ 85| 7| AFNetworkReachabilityManager *manager = nil; 86| 7| if (block) { 87| 7| manager = block(status); 88| 7| } 89| 7| NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 90| 7| NSDictionary *userInfo = @{ AFNetworkingReachabilityNotificationStatusItem: @(status) }; 91| 7| [notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:manager userInfo:userInfo]; 92| 7| }); 93| 7|} 94| | 95| 2|static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) { 96| 2| AFPostReachabilityStatusChange(flags, (__bridge AFNetworkReachabilityStatusCallback)info); 97| 2|} 98| | 99| | 100| 7|static const void * AFNetworkReachabilityRetainCallback(const void *info) { 101| 7| return Block_copy(info); 102| 7|} 103| | 104| 2|static void AFNetworkReachabilityReleaseCallback(const void *info) { 105| 2| if (info) { 106| 2| Block_release(info); 107| 2| } 108| 2|} 109| | 110| |@interface AFNetworkReachabilityManager () 111| |@property (readonly, nonatomic, assign) SCNetworkReachabilityRef networkReachability; 112| |@property (readwrite, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus; 113| |@property (readwrite, nonatomic, copy) AFNetworkReachabilityStatusBlock networkReachabilityStatusBlock; 114| |@end 115| | 116| |@implementation AFNetworkReachabilityManager 117| | 118| 132|+ (instancetype)sharedManager { 119| 132| static AFNetworkReachabilityManager *_sharedManager = nil; 120| 132| static dispatch_once_t onceToken; 121| 132| dispatch_once(&onceToken, ^{ 122| 1| _sharedManager = [self manager]; 123| 1| }); 124| 132| 125| 132| return _sharedManager; 126| 132|} 127| | 128| 9|+ (instancetype)managerForDomain:(NSString *)domain { 129| 9| SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]); 130| 9| 131| 9| AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability]; 132| 9| 133| 9| CFRelease(reachability); 134| 9| 135| 9| return manager; 136| 9|} 137| | 138| 10|+ (instancetype)managerForAddress:(const void *)address { 139| 10| SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address); 140| 10| AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability]; 141| 10| 142| 10| CFRelease(reachability); 143| 10| 144| 10| return manager; 145| 10|} 146| | 147| |+ (instancetype)manager 148| 10|{ 149| |#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 90000) || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100) 150| | struct sockaddr_in6 address; 151| | bzero(&address, sizeof(address)); 152| | address.sin6_len = sizeof(address); 153| | address.sin6_family = AF_INET6; 154| |#else 155| | struct sockaddr_in address; 156| 10| bzero(&address, sizeof(address)); 157| 10| address.sin_len = sizeof(address); 158| 10| address.sin_family = AF_INET; 159| 10|#endif 160| 10| return [self managerForAddress:&address]; 161| 10|} 162| | 163| 19|- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability { 164| 19| self = [super init]; 165| 19| if (!self) { 166| 0| return nil; 167| 0| } 168| 19| 169| 19| _networkReachability = CFRetain(reachability); 170| 19| self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown; 171| 19| 172| 19| return self; 173| 19|} 174| | 175| |- (instancetype)init 176| 2|{ 177| 2| @throw [NSException exceptionWithName:NSGenericException 178| 2| reason:@"`-init` unavailable. Use `-initWithReachability:` instead" 179| 2| userInfo:nil]; 180| 2| return nil; 181| 2|} 182| | 183| 1|- (void)dealloc { 184| 1| [self stopMonitoring]; 185| 1| 186| 1| if (_networkReachability != NULL) { 187| 0| CFRelease(_networkReachability); 188| 0| } 189| 1|} 190| | 191| |#pragma mark - 192| | 193| 0|- (BOOL)isReachable { 194| 0| return [self isReachableViaWWAN] || [self isReachableViaWiFi]; 195| 0|} 196| | 197| 0|- (BOOL)isReachableViaWWAN { 198| 0| return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN; 199| 0|} 200| | 201| 0|- (BOOL)isReachableViaWiFi { 202| 0| return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWiFi; 203| 0|} 204| | 205| |#pragma mark - 206| | 207| 5|- (void)startMonitoring { 208| 5| [self stopMonitoring]; 209| 5| 210| 5| if (!self.networkReachability) { 211| 0| return; 212| 0| } 213| 5| 214| 5| __weak __typeof(self)weakSelf = self; 215| 7| AFNetworkReachabilityStatusCallback callback = ^(AFNetworkReachabilityStatus status) { 216| 7| __strong __typeof(weakSelf)strongSelf = weakSelf; 217| 7| 218| 7| strongSelf.networkReachabilityStatus = status; 219| 7| if (strongSelf.networkReachabilityStatusBlock) { 220| 2| strongSelf.networkReachabilityStatusBlock(status); 221| 2| } 222| 7| 223| 7| return strongSelf; 224| 7| }; 225| 5| 226| 5| SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL}; 227| 5| SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context); 228| 5| SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); 229| 5| 230| 5| dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{ 231| 5| SCNetworkReachabilityFlags flags; 232| 5| if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) { 233| 5| AFPostReachabilityStatusChange(flags, callback); 234| 5| } 235| 5| }); 236| 5|} 237| | 238| 24|- (void)stopMonitoring { 239| 24| if (!self.networkReachability) { 240| 1| return; 241| 1| } 242| 23| 243| 23| SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); 244| 23|} 245| | 246| |#pragma mark - 247| | 248| 0|- (NSString *)localizedNetworkReachabilityStatusString { 249| 0| return AFStringFromNetworkReachabilityStatus(self.networkReachabilityStatus); 250| 0|} 251| | 252| |#pragma mark - 253| | 254| 4|- (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block { 255| 4| self.networkReachabilityStatusBlock = block; 256| 4|} 257| | 258| |#pragma mark - NSKeyValueObserving 259| | 260| 0|+ (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key { 261| 0| if ([key isEqualToString:@"reachable"] || [key isEqualToString:@"reachableViaWWAN"] || [key isEqualToString:@"reachableViaWiFi"]) { 262| 0| return [NSSet setWithObject:@"networkReachabilityStatus"]; 263| 0| } 264| 0| 265| 0| return [super keyPathsForValuesAffectingValueForKey:key]; 266| 0|} 267| | 268| |@end 269| |#endif /Users/travis/build/AFNetworking/AFNetworking/AFNetworking/AFSecurityPolicy.m: 1| |// AFSecurityPolicy.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "AFSecurityPolicy.h" 23| | 24| |#import 25| | 26| |#if !TARGET_OS_IOS && !TARGET_OS_WATCH && !TARGET_OS_TV 27| |static NSData * AFSecKeyGetData(SecKeyRef key) { 28| | CFDataRef data = NULL; 29| | 30| | __Require_noErr_Quiet(SecItemExport(key, kSecFormatUnknown, kSecItemPemArmour, NULL, &data), _out); 31| | 32| | return (__bridge_transfer NSData *)data; 33| | 34| |_out: 35| | if (data) { 36| | CFRelease(data); 37| | } 38| | 39| | return nil; 40| |} 41| |#endif 42| | 43| 36|static BOOL AFSecKeyIsEqualToKey(SecKeyRef key1, SecKeyRef key2) { 44| 36|#if TARGET_OS_IOS || TARGET_OS_WATCH || TARGET_OS_TV 45| 36| return [(__bridge id)key1 isEqual:(__bridge id)key2]; 46| |#else 47| | return [AFSecKeyGetData(key1) isEqual:AFSecKeyGetData(key2)]; 48| |#endif 49| |} 50| | 51| 69|static id AFPublicKeyForCertificate(NSData *certificate) { 52| 69| id allowedPublicKey = nil; 53| 69| SecCertificateRef allowedCertificate; 54| 69| SecPolicyRef policy = nil; 55| 69| SecTrustRef allowedTrust = nil; 56| 69| SecTrustResultType result; 57| 69| 58| 69| allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificate); 59| 69| __Require_Quiet(allowedCertificate != NULL, _out); 60| 69| 61| 69| policy = SecPolicyCreateBasicX509(); 62| 69| __Require_noErr_Quiet(SecTrustCreateWithCertificates(allowedCertificate, policy, &allowedTrust), _out); 63| 69| __Require_noErr_Quiet(SecTrustEvaluate(allowedTrust, &result), _out); 64| 69| 65| 69| allowedPublicKey = (__bridge_transfer id)SecTrustCopyPublicKey(allowedTrust); 66| 69| 67| 69|_out: 68| 69| if (allowedTrust) { 69| 69| CFRelease(allowedTrust); 70| 69| } 71| 69| 72| 69| if (policy) { 73| 69| CFRelease(policy); 74| 69| } 75| 69| 76| 69| if (allowedCertificate) { 77| 69| CFRelease(allowedCertificate); 78| 69| } 79| 69| 80| 69| return allowedPublicKey; 81| 69|} 82| | 83| 113|static BOOL AFServerTrustIsValid(SecTrustRef serverTrust) { 84| 113| BOOL isValid = NO; 85| 113| SecTrustResultType result; 86| 113| __Require_noErr_Quiet(SecTrustEvaluate(serverTrust, &result), _out); 87| 113| 88| 113| isValid = (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed); 89| 113| 90| 113|_out: 91| 113| return isValid; 92| 113|} 93| | 94| 6|static NSArray * AFCertificateTrustChainForServerTrust(SecTrustRef serverTrust) { 95| 6| CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust); 96| 6| NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount]; 97| 6| 98| 15| for (CFIndex i = 0; i < certificateCount; i++) { 99| 9| SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i); 100| 9| [trustChain addObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)]; 101| 9| } 102| 6| 103| 6| return [NSArray arrayWithArray:trustChain]; 104| 6|} 105| | 106| 11|static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) { 107| 11| SecPolicyRef policy = SecPolicyCreateBasicX509(); 108| 11| CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust); 109| 11| NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount]; 110| 38| for (CFIndex i = 0; i < certificateCount; i++) { 111| 27| SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i); 112| 27| 113| 27| SecCertificateRef someCertificates[] = {certificate}; 114| 27| CFArrayRef certificates = CFArrayCreate(NULL, (const void **)someCertificates, 1, NULL); 115| 27| 116| 27| SecTrustRef trust; 117| 27| __Require_noErr_Quiet(SecTrustCreateWithCertificates(certificates, policy, &trust), _out); 118| 27| 119| 27| SecTrustResultType result; 120| 27| __Require_noErr_Quiet(SecTrustEvaluate(trust, &result), _out); 121| 27| 122| 27| [trustChain addObject:(__bridge_transfer id)SecTrustCopyPublicKey(trust)]; 123| 27| 124| 27| _out: 125| 27| if (trust) { 126| 27| CFRelease(trust); 127| 27| } 128| 27| 129| 27| if (certificates) { 130| 27| CFRelease(certificates); 131| 27| } 132| 27| 133| 27| continue; 134| 27| } 135| 11| CFRelease(policy); 136| 11| 137| 11| return [NSArray arrayWithArray:trustChain]; 138| 11|} 139| | 140| |#pragma mark - 141| | 142| |@interface AFSecurityPolicy() 143| |@property (readwrite, nonatomic, assign) AFSSLPinningMode SSLPinningMode; 144| |@property (readwrite, nonatomic, strong) NSSet *pinnedPublicKeys; 145| |@end 146| | 147| |@implementation AFSecurityPolicy 148| | 149| 3|+ (NSSet *)certificatesInBundle:(NSBundle *)bundle { 150| 3| NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"."]; 151| 3| 152| 3| NSMutableSet *certificates = [NSMutableSet setWithCapacity:[paths count]]; 153| 30| for (NSString *path in paths) { 154| 30| NSData *certificateData = [NSData dataWithContentsOfFile:path]; 155| 30| [certificates addObject:certificateData]; 156| 30| } 157| 3| 158| 3| return [NSSet setWithSet:certificates]; 159| 3|} 160| | 161| 40|+ (NSSet *)defaultPinnedCertificates { 162| 40| static NSSet *_defaultPinnedCertificates = nil; 163| 40| static dispatch_once_t onceToken; 164| 40| dispatch_once(&onceToken, ^{ 165| 1| NSBundle *bundle = [NSBundle bundleForClass:[self class]]; 166| 1| _defaultPinnedCertificates = [self certificatesInBundle:bundle]; 167| 1| }); 168| 40| 169| 40| return _defaultPinnedCertificates; 170| 40|} 171| | 172| 144|+ (instancetype)defaultPolicy { 173| 144| AFSecurityPolicy *securityPolicy = [[self alloc] init]; 174| 144| securityPolicy.SSLPinningMode = AFSSLPinningModeNone; 175| 144| 176| 144| return securityPolicy; 177| 144|} 178| | 179| 40|+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode { 180| 40| return [self policyWithPinningMode:pinningMode withPinnedCertificates:[self defaultPinnedCertificates]]; 181| 40|} 182| | 183| 44|+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet *)pinnedCertificates { 184| 44| AFSecurityPolicy *securityPolicy = [[self alloc] init]; 185| 44| securityPolicy.SSLPinningMode = pinningMode; 186| 44| 187| 44| [securityPolicy setPinnedCertificates:pinnedCertificates]; 188| 44| 189| 44| return securityPolicy; 190| 44|} 191| | 192| 192|- (instancetype)init { 193| 192| self = [super init]; 194| 192| if (!self) { 195| 0| return nil; 196| 0| } 197| 192| 198| 192| self.validatesDomainName = YES; 199| 192| 200| 192| return self; 201| 192|} 202| | 203| 77|- (void)setPinnedCertificates:(NSSet *)pinnedCertificates { 204| 77| _pinnedCertificates = pinnedCertificates; 205| 77| 206| 77| if (self.pinnedCertificates) { 207| 75| NSMutableSet *mutablePinnedPublicKeys = [NSMutableSet setWithCapacity:[self.pinnedCertificates count]]; 208| 75| for (NSData *certificate in self.pinnedCertificates) { 209| 69| id publicKey = AFPublicKeyForCertificate(certificate); 210| 69| if (!publicKey) { 211| 0| continue; 212| 0| } 213| 69| [mutablePinnedPublicKeys addObject:publicKey]; 214| 69| } 215| 75| self.pinnedPublicKeys = [NSSet setWithSet:mutablePinnedPublicKeys]; 216| 75| } else { 217| 2| self.pinnedPublicKeys = nil; 218| 2| } 219| 77|} 220| | 221| |#pragma mark - 222| | 223| |- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust 224| | forDomain:(NSString *)domain 225| 109|{ 226| 109| if (domain && self.allowInvalidCertificates && self.validatesDomainName && (self.SSLPinningMode == AFSSLPinningModeNone || [self.pinnedCertificates count] == 0)) { 227| 3| // https://developer.apple.com/library/mac/documentation/NetworkingInternet/Conceptual/NetworkingTopics/Articles/OverridingSSLChainValidationCorrectly.html 228| 3| // According to the docs, you should only trust your provided certs for evaluation. 229| 3| // Pinned certificates are added to the trust. Without pinned certificates, 230| 3| // there is nothing to evaluate against. 231| 3| // 232| 3| // From Apple Docs: 233| 3| // "Do not implicitly trust self-signed certificates as anchors (kSecTrustOptionImplicitAnchors). 234| 3| // Instead, add your own (self-signed) CA certificate to the list of trusted anchors." 235| 3| NSLog(@"In order to validate a domain name for self signed certificates, you MUST use pinning."); 236| 3| return NO; 237| 3| } 238| 106| 239| 106| NSMutableArray *policies = [NSMutableArray array]; 240| 106| if (self.validatesDomainName) { 241| 104| [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)]; 242| 104| } else { 243| 2| [policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()]; 244| 2| } 245| 106| 246| 106| SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies); 247| 106| 248| 106| if (self.SSLPinningMode == AFSSLPinningModeNone) { 249| 80| return self.allowInvalidCertificates || AFServerTrustIsValid(serverTrust); 250| 80| } else if (!AFServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates) { 251| 6| return NO; 252| 6| } 253| 20| 254| 20| switch (self.SSLPinningMode) { 255| 20| case AFSSLPinningModeCertificate: { 256| 9| NSMutableArray *pinnedCertificates = [NSMutableArray array]; 257| 12| for (NSData *certificateData in self.pinnedCertificates) { 258| 12| [pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)]; 259| 12| } 260| 9| SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates); 261| 9| 262| 9| if (!AFServerTrustIsValid(serverTrust)) { 263| 3| return NO; 264| 3| } 265| 6| 266| 6| // obtain the chain after being validated, which *should* contain the pinned certificate in the last position (if it's the Root CA) 267| 6| NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust); 268| 6| 269| 6| for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) { 270| 6| if ([self.pinnedCertificates containsObject:trustChainCertificate]) { 271| 6| return YES; 272| 6| } 273| 6| } 274| 6| 275| 6| return NO; 276| 6| } 277| 11| case AFSSLPinningModePublicKey: { 278| 11| NSUInteger trustedPublicKeyCount = 0; 279| 11| NSArray *publicKeys = AFPublicKeyTrustChainForServerTrust(serverTrust); 280| 11| 281| 27| for (id trustChainPublicKey in publicKeys) { 282| 36| for (id pinnedPublicKey in self.pinnedPublicKeys) { 283| 36| if (AFSecKeyIsEqualToKey((__bridge SecKeyRef)trustChainPublicKey, (__bridge SecKeyRef)pinnedPublicKey)) { 284| 11| trustedPublicKeyCount += 1; 285| 11| } 286| 36| } 287| 27| } 288| 11| return trustedPublicKeyCount > 0; 289| 6| } 290| 6| 291| 6| default: 292| 0| return NO; 293| 0| } 294| 0| 295| 0| return NO; 296| 0|} 297| | 298| |#pragma mark - NSKeyValueObserving 299| | 300| 0|+ (NSSet *)keyPathsForValuesAffectingPinnedPublicKeys { 301| 0| return [NSSet setWithObject:@"pinnedCertificates"]; 302| 0|} 303| | 304| |#pragma mark - NSSecureCoding 305| | 306| 0|+ (BOOL)supportsSecureCoding { 307| 0| return YES; 308| 0|} 309| | 310| 2|- (instancetype)initWithCoder:(NSCoder *)decoder { 311| 2| 312| 2| self = [self init]; 313| 2| if (!self) { 314| 0| return nil; 315| 0| } 316| 2| 317| 2| self.SSLPinningMode = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(SSLPinningMode))] unsignedIntegerValue]; 318| 2| self.allowInvalidCertificates = [decoder decodeBoolForKey:NSStringFromSelector(@selector(allowInvalidCertificates))]; 319| 2| self.validatesDomainName = [decoder decodeBoolForKey:NSStringFromSelector(@selector(validatesDomainName))]; 320| 2| self.pinnedCertificates = [decoder decodeObjectOfClass:[NSSet class] forKey:NSStringFromSelector(@selector(pinnedCertificates))]; 321| 2| 322| 2| return self; 323| 2|} 324| | 325| 3|- (void)encodeWithCoder:(NSCoder *)coder { 326| 3| [coder encodeObject:[NSNumber numberWithUnsignedInteger:self.SSLPinningMode] forKey:NSStringFromSelector(@selector(SSLPinningMode))]; 327| 3| [coder encodeBool:self.allowInvalidCertificates forKey:NSStringFromSelector(@selector(allowInvalidCertificates))]; 328| 3| [coder encodeBool:self.validatesDomainName forKey:NSStringFromSelector(@selector(validatesDomainName))]; 329| 3| [coder encodeObject:self.pinnedCertificates forKey:NSStringFromSelector(@selector(pinnedCertificates))]; 330| 3|} 331| | 332| |#pragma mark - NSCopying 333| | 334| 2|- (instancetype)copyWithZone:(NSZone *)zone { 335| 2| AFSecurityPolicy *securityPolicy = [[[self class] allocWithZone:zone] init]; 336| 2| securityPolicy.SSLPinningMode = self.SSLPinningMode; 337| 2| securityPolicy.allowInvalidCertificates = self.allowInvalidCertificates; 338| 2| securityPolicy.validatesDomainName = self.validatesDomainName; 339| 2| securityPolicy.pinnedCertificates = [self.pinnedCertificates copyWithZone:zone]; 340| 2| 341| 2| return securityPolicy; 342| 2|} 343| | 344| |@end /Users/travis/build/AFNetworking/AFNetworking/AFNetworking/AFURLRequestSerialization.m: 1| |// AFURLRequestSerialization.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "AFURLRequestSerialization.h" 23| | 24| |#if TARGET_OS_IOS || TARGET_OS_WATCH || TARGET_OS_TV 25| |#import 26| |#else 27| |#import 28| |#endif 29| | 30| |NSString * const AFURLRequestSerializationErrorDomain = @"com.alamofire.error.serialization.request"; 31| |NSString * const AFNetworkingOperationFailingURLRequestErrorKey = @"com.alamofire.serialization.request.error.response"; 32| | 33| |typedef NSString * (^AFQueryStringSerializationBlock)(NSURLRequest *request, id parameters, NSError *__autoreleasing *error); 34| | 35| |/** 36| | Returns a percent-escaped string following RFC 3986 for a query string key or value. 37| | RFC 3986 states that the following characters are "reserved" characters. 38| | - General Delimiters: ":", "#", "[", "]", "@", "?", "/" 39| | - Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "=" 40| | 41| | In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow 42| | query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/" 43| | should be percent-escaped in the query string. 44| | - parameter string: The string to be percent-escaped. 45| | - returns: The percent-escaped string. 46| | */ 47| 37|NSString * AFPercentEscapedStringFromString(NSString *string) { 48| 37| static NSString * const kAFCharactersGeneralDelimitersToEncode = @":#[]@"; // does not include "?" or "/" due to RFC 3986 - Section 3.4 49| 37| static NSString * const kAFCharactersSubDelimitersToEncode = @"!$&'()*+,;="; 50| 37| 51| 37| NSMutableCharacterSet * allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy]; 52| 37| [allowedCharacterSet removeCharactersInString:[kAFCharactersGeneralDelimitersToEncode stringByAppendingString:kAFCharactersSubDelimitersToEncode]]; 53| 37| 54| 37| // FIXME: https://github.com/AFNetworking/AFNetworking/pull/3028 55| 37| // return [string stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet]; 56| 37| 57| 37| static NSUInteger const batchSize = 50; 58| 37| 59| 37| NSUInteger index = 0; 60| 37| NSMutableString *escaped = @"".mutableCopy; 61| 37| 62| 873| while (index < string.length) { 63| 836| NSUInteger length = MIN(string.length - index, batchSize); 64| 836| NSRange range = NSMakeRange(index, length); 65| 836| 66| 836| // To avoid breaking up character sequences such as 👴🏻👮🏽 67| 836| range = [string rangeOfComposedCharacterSequencesForRange:range]; 68| 836| 69| 836| NSString *substring = [string substringWithRange:range]; 70| 836| NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet]; 71| 836| [escaped appendString:encoded]; 72| 836| 73| 836| index += range.length; 74| 836| } 75| 37| 76| 37| return escaped; 77| 37|} 78| | 79| |#pragma mark - 80| | 81| |@interface AFQueryStringPair : NSObject 82| |@property (readwrite, nonatomic, strong) id field; 83| |@property (readwrite, nonatomic, strong) id value; 84| | 85| |- (instancetype)initWithField:(id)field value:(id)value; 86| | 87| |- (NSString *)URLEncodedStringValue; 88| |@end 89| | 90| |@implementation AFQueryStringPair 91| | 92| 21|- (instancetype)initWithField:(id)field value:(id)value { 93| 21| self = [super init]; 94| 21| if (!self) { 95| 0| return nil; 96| 0| } 97| 21| 98| 21| self.field = field; 99| 21| self.value = value; 100| 21| 101| 21| return self; 102| 21|} 103| | 104| 18|- (NSString *)URLEncodedStringValue { 105| 18| if (!self.value || [self.value isEqual:[NSNull null]]) { 106| 0| return AFPercentEscapedStringFromString([self.field description]); 107| 18| } else { 108| 18| return [NSString stringWithFormat:@"%@=%@", AFPercentEscapedStringFromString([self.field description]), AFPercentEscapedStringFromString([self.value description])]; 109| 18| } 110| 18|} 111| | 112| |@end 113| | 114| |#pragma mark - 115| | 116| |FOUNDATION_EXPORT NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary); 117| |FOUNDATION_EXPORT NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value); 118| | 119| 18|NSString * AFQueryStringFromParameters(NSDictionary *parameters) { 120| 18| NSMutableArray *mutablePairs = [NSMutableArray array]; 121| 18| for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) { 122| 18| [mutablePairs addObject:[pair URLEncodedStringValue]]; 123| 18| } 124| 18| 125| 18| return [mutablePairs componentsJoinedByString:@"&"]; 126| 18|} 127| | 128| 21|NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary) { 129| 21| return AFQueryStringPairsFromKeyAndValue(nil, dictionary); 130| 21|} 131| | 132| 40|NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value) { 133| 40| NSMutableArray *mutableQueryStringComponents = [NSMutableArray array]; 134| 40| 135| 40| NSSortDescriptor *sortDescriptor = [NSSortDescriptor sortDescriptorWithKey:@"description" ascending:YES selector:@selector(compare:)]; 136| 40| 137| 40| if ([value isKindOfClass:[NSDictionary class]]) { 138| 19| NSDictionary *dictionary = value; 139| 19| // Sort dictionary keys to ensure consistent ordering in query string, which is important when deserializing potentially ambiguous sequences, such as an array of dictionaries 140| 19| for (id nestedKey in [dictionary.allKeys sortedArrayUsingDescriptors:@[ sortDescriptor ]]) { 141| 19| id nestedValue = dictionary[nestedKey]; 142| 19| if (nestedValue) { 143| 19| [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue((key ? [NSString stringWithFormat:@"%@[%@]", key, nestedKey] : nestedKey), nestedValue)]; 144| 19| } 145| 19| } 146| 21| } else if ([value isKindOfClass:[NSArray class]]) { 147| 0| NSArray *array = value; 148| 0| for (id nestedValue in array) { 149| 0| [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue([NSString stringWithFormat:@"%@[]", key], nestedValue)]; 150| 0| } 151| 21| } else if ([value isKindOfClass:[NSSet class]]) { 152| 0| NSSet *set = value; 153| 0| for (id obj in [set sortedArrayUsingDescriptors:@[ sortDescriptor ]]) { 154| 0| [mutableQueryStringComponents addObjectsFromArray:AFQueryStringPairsFromKeyAndValue(key, obj)]; 155| 0| } 156| 21| } else { 157| 21| [mutableQueryStringComponents addObject:[[AFQueryStringPair alloc] initWithField:key value:value]]; 158| 21| } 159| 40| 160| 40| return mutableQueryStringComponents; 161| 40|} 162| | 163| |#pragma mark - 164| | 165| |@interface AFStreamingMultipartFormData : NSObject 166| |- (instancetype)initWithURLRequest:(NSMutableURLRequest *)urlRequest 167| | stringEncoding:(NSStringEncoding)encoding; 168| | 169| |- (NSMutableURLRequest *)requestByFinalizingMultipartFormData; 170| |@end 171| | 172| |#pragma mark - 173| | 174| 261|static NSArray * AFHTTPRequestSerializerObservedKeyPaths() { 175| 261| static NSArray *_AFHTTPRequestSerializerObservedKeyPaths = nil; 176| 261| static dispatch_once_t onceToken; 177| 261| dispatch_once(&onceToken, ^{ 178| 1| _AFHTTPRequestSerializerObservedKeyPaths = @[NSStringFromSelector(@selector(allowsCellularAccess)), NSStringFromSelector(@selector(cachePolicy)), NSStringFromSelector(@selector(HTTPShouldHandleCookies)), NSStringFromSelector(@selector(HTTPShouldUsePipelining)), NSStringFromSelector(@selector(networkServiceType)), NSStringFromSelector(@selector(timeoutInterval))]; 179| 1| }); 180| 261| 181| 261| return _AFHTTPRequestSerializerObservedKeyPaths; 182| 261|} 183| | 184| |static void *AFHTTPRequestSerializerObserverContext = &AFHTTPRequestSerializerObserverContext; 185| | 186| |@interface AFHTTPRequestSerializer () 187| |@property (readwrite, nonatomic, strong) NSMutableSet *mutableObservedChangedKeyPaths; 188| |@property (readwrite, nonatomic, strong) NSMutableDictionary *mutableHTTPRequestHeaders; 189| |@property (readwrite, nonatomic, strong) dispatch_queue_t requestHeaderModificationQueue; 190| |@property (readwrite, nonatomic, assign) AFHTTPRequestQueryStringSerializationStyle queryStringSerializationStyle; 191| |@property (readwrite, nonatomic, copy) AFQueryStringSerializationBlock queryStringSerialization; 192| |@end 193| | 194| |@implementation AFHTTPRequestSerializer 195| | 196| 115|+ (instancetype)serializer { 197| 115| return [[self alloc] init]; 198| 115|} 199| | 200| 123|- (instancetype)init { 201| 123| self = [super init]; 202| 123| if (!self) { 203| 0| return nil; 204| 0| } 205| 123| 206| 123| self.stringEncoding = NSUTF8StringEncoding; 207| 123| 208| 123| self.mutableHTTPRequestHeaders = [NSMutableDictionary dictionary]; 209| 123| self.requestHeaderModificationQueue = dispatch_queue_create("requestHeaderModificationQueue", DISPATCH_QUEUE_CONCURRENT); 210| 123| 211| 123| // Accept-Language HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4 212| 123| NSMutableArray *acceptLanguagesComponents = [NSMutableArray array]; 213| 123| [[NSLocale preferredLanguages] enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { 214| 123| float q = 1.0f - (idx * 0.1f); 215| 123| [acceptLanguagesComponents addObject:[NSString stringWithFormat:@"%@;q=%0.1g", obj, q]]; 216| 123| *stop = q <= 0.5f; 217| 123| }]; 218| 123| [self setValue:[acceptLanguagesComponents componentsJoinedByString:@", "] forHTTPHeaderField:@"Accept-Language"]; 219| 123| 220| 123| // User-Agent Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43 221| 123| NSString *userAgent = nil; 222| 123|#if TARGET_OS_IOS 223| 123| userAgent = [NSString stringWithFormat:@"%@/%@ (%@; iOS %@; Scale/%0.2f)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], [[UIScreen mainScreen] scale]]; 224| |#elif TARGET_OS_TV 225| | userAgent = [NSString stringWithFormat:@"%@/%@ (%@; tvOS %@; Scale/%0.2f)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], [[UIScreen mainScreen] scale]]; 226| |#elif TARGET_OS_WATCH 227| | userAgent = [NSString stringWithFormat:@"%@/%@ (%@; watchOS %@; Scale/%0.2f)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[WKInterfaceDevice currentDevice] model], [[WKInterfaceDevice currentDevice] systemVersion], [[WKInterfaceDevice currentDevice] screenScale]]; 228| |#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) 229| | userAgent = [NSString stringWithFormat:@"%@/%@ (Mac OS X %@)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[NSProcessInfo processInfo] operatingSystemVersionString]]; 230| |#endif 231| 123| if (userAgent) { 232| 123| if (![userAgent canBeConvertedToEncoding:NSASCIIStringEncoding]) { 233| 0| NSMutableString *mutableUserAgent = [userAgent mutableCopy]; 234| 0| if (CFStringTransform((__bridge CFMutableStringRef)(mutableUserAgent), NULL, (__bridge CFStringRef)@"Any-Latin; Latin-ASCII; [:^ASCII:] Remove", false)) { 235| 0| userAgent = mutableUserAgent; 236| 0| } 237| 0| } 238| 123| [self setValue:userAgent forHTTPHeaderField:@"User-Agent"]; 239| 123| } 240| 123| 241| 123| // HTTP Method Definitions; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html 242| 123| self.HTTPMethodsEncodingParametersInURI = [NSSet setWithObjects:@"GET", @"HEAD", @"DELETE", nil]; 243| 123| 244| 123| self.mutableObservedChangedKeyPaths = [NSMutableSet set]; 245| 738| for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) { 246| 738| if ([self respondsToSelector:NSSelectorFromString(keyPath)]) { 247| 738| [self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:AFHTTPRequestSerializerObserverContext]; 248| 738| } 249| 738| } 250| 123| 251| 123| return self; 252| 123|} 253| | 254| 77|- (void)dealloc { 255| 462| for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) { 256| 462| if ([self respondsToSelector:NSSelectorFromString(keyPath)]) { 257| 462| [self removeObserver:self forKeyPath:keyPath context:AFHTTPRequestSerializerObserverContext]; 258| 462| } 259| 462| } 260| 77|} 261| | 262| |#pragma mark - 263| | 264| |// Workarounds for crashing behavior using Key-Value Observing with XCTest 265| |// See https://github.com/AFNetworking/AFNetworking/issues/2523 266| | 267| 0|- (void)setAllowsCellularAccess:(BOOL)allowsCellularAccess { 268| 0| [self willChangeValueForKey:NSStringFromSelector(@selector(allowsCellularAccess))]; 269| 0| _allowsCellularAccess = allowsCellularAccess; 270| 0| [self didChangeValueForKey:NSStringFromSelector(@selector(allowsCellularAccess))]; 271| 0|} 272| | 273| 0|- (void)setCachePolicy:(NSURLRequestCachePolicy)cachePolicy { 274| 0| [self willChangeValueForKey:NSStringFromSelector(@selector(cachePolicy))]; 275| 0| _cachePolicy = cachePolicy; 276| 0| [self didChangeValueForKey:NSStringFromSelector(@selector(cachePolicy))]; 277| 0|} 278| | 279| 0|- (void)setHTTPShouldHandleCookies:(BOOL)HTTPShouldHandleCookies { 280| 0| [self willChangeValueForKey:NSStringFromSelector(@selector(HTTPShouldHandleCookies))]; 281| 0| _HTTPShouldHandleCookies = HTTPShouldHandleCookies; 282| 0| [self didChangeValueForKey:NSStringFromSelector(@selector(HTTPShouldHandleCookies))]; 283| 0|} 284| | 285| 0|- (void)setHTTPShouldUsePipelining:(BOOL)HTTPShouldUsePipelining { 286| 0| [self willChangeValueForKey:NSStringFromSelector(@selector(HTTPShouldUsePipelining))]; 287| 0| _HTTPShouldUsePipelining = HTTPShouldUsePipelining; 288| 0| [self didChangeValueForKey:NSStringFromSelector(@selector(HTTPShouldUsePipelining))]; 289| 0|} 290| | 291| 0|- (void)setNetworkServiceType:(NSURLRequestNetworkServiceType)networkServiceType { 292| 0| [self willChangeValueForKey:NSStringFromSelector(@selector(networkServiceType))]; 293| 0| _networkServiceType = networkServiceType; 294| 0| [self didChangeValueForKey:NSStringFromSelector(@selector(networkServiceType))]; 295| 0|} 296| | 297| 0|- (void)setTimeoutInterval:(NSTimeInterval)timeoutInterval { 298| 0| [self willChangeValueForKey:NSStringFromSelector(@selector(timeoutInterval))]; 299| 0| _timeoutInterval = timeoutInterval; 300| 0| [self didChangeValueForKey:NSStringFromSelector(@selector(timeoutInterval))]; 301| 0|} 302| | 303| |#pragma mark - 304| | 305| 52|- (NSDictionary *)HTTPRequestHeaders { 306| 52| NSDictionary __block *value; 307| 52| dispatch_sync(self.requestHeaderModificationQueue, ^{ 308| 52| value = [NSDictionary dictionaryWithDictionary:self.mutableHTTPRequestHeaders]; 309| 52| }); 310| 52| return value; 311| 52|} 312| | 313| |- (void)setValue:(NSString *)value 314| |forHTTPHeaderField:(NSString *)field 315| 1.25k|{ 316| 1.25k| dispatch_barrier_sync(self.requestHeaderModificationQueue, ^{ 317| 1.25k| [self.mutableHTTPRequestHeaders setValue:value forKey:field]; 318| 1.25k| }); 319| 1.25k|} 320| | 321| 2|- (NSString *)valueForHTTPHeaderField:(NSString *)field { 322| 2| NSString __block *value; 323| 2| dispatch_sync(self.requestHeaderModificationQueue, ^{ 324| 2| value = [self.mutableHTTPRequestHeaders valueForKey:field]; 325| 2| }); 326| 2| return value; 327| 2|} 328| | 329| |- (void)setAuthorizationHeaderFieldWithUsername:(NSString *)username 330| | password:(NSString *)password 331| 1|{ 332| 1| NSData *basicAuthCredentials = [[NSString stringWithFormat:@"%@:%@", username, password] dataUsingEncoding:NSUTF8StringEncoding]; 333| 1| NSString *base64AuthCredentials = [basicAuthCredentials base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)0]; 334| 1| [self setValue:[NSString stringWithFormat:@"Basic %@", base64AuthCredentials] forHTTPHeaderField:@"Authorization"]; 335| 1|} 336| | 337| 0|- (void)clearAuthorizationHeader { 338| 0| dispatch_barrier_sync(self.requestHeaderModificationQueue, ^{ 339| 0| [self.mutableHTTPRequestHeaders removeObjectForKey:@"Authorization"]; 340| 0| }); 341| 0|} 342| | 343| |#pragma mark - 344| | 345| 0|- (void)setQueryStringSerializationWithStyle:(AFHTTPRequestQueryStringSerializationStyle)style { 346| 0| self.queryStringSerializationStyle = style; 347| 0| self.queryStringSerialization = nil; 348| 0|} 349| | 350| 3|- (void)setQueryStringSerializationWithBlock:(NSString *(^)(NSURLRequest *, id, NSError *__autoreleasing *))block { 351| 3| self.queryStringSerialization = block; 352| 3|} 353| | 354| |#pragma mark - 355| | 356| |- (NSMutableURLRequest *)requestWithMethod:(NSString *)method 357| | URLString:(NSString *)URLString 358| | parameters:(id)parameters 359| | error:(NSError *__autoreleasing *)error 360| 43|{ 361| 43| NSParameterAssert(method); 362| 43| NSParameterAssert(URLString); 363| 43| 364| 43| NSURL *url = [NSURL URLWithString:URLString]; 365| 43| 366| 43| NSParameterAssert(url); 367| 43| 368| 43| NSMutableURLRequest *mutableRequest = [[NSMutableURLRequest alloc] initWithURL:url]; 369| 43| mutableRequest.HTTPMethod = method; 370| 43| 371| 258| for (NSString *keyPath in AFHTTPRequestSerializerObservedKeyPaths()) { 372| 258| if ([self.mutableObservedChangedKeyPaths containsObject:keyPath]) { 373| 0| [mutableRequest setValue:[self valueForKeyPath:keyPath] forKey:keyPath]; 374| 0| } 375| 258| } 376| 43| 377| 43| mutableRequest = [[self requestBySerializingRequest:mutableRequest withParameters:parameters error:error] mutableCopy]; 378| 43| 379| 43| return mutableRequest; 380| 43|} 381| | 382| |- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method 383| | URLString:(NSString *)URLString 384| | parameters:(NSDictionary *)parameters 385| | constructingBodyWithBlock:(void (^)(id formData))block 386| | error:(NSError *__autoreleasing *)error 387| 5|{ 388| 5| NSParameterAssert(method); 389| 5| NSParameterAssert(![method isEqualToString:@"GET"] && ![method isEqualToString:@"HEAD"]); 390| 5| 391| 5| NSMutableURLRequest *mutableRequest = [self requestWithMethod:method URLString:URLString parameters:nil error:error]; 392| 5| 393| 5| __block AFStreamingMultipartFormData *formData = [[AFStreamingMultipartFormData alloc] initWithURLRequest:mutableRequest stringEncoding:NSUTF8StringEncoding]; 394| 5| 395| 5| if (parameters) { 396| 3| for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) { 397| 3| NSData *data = nil; 398| 3| if ([pair.value isKindOfClass:[NSData class]]) { 399| 0| data = pair.value; 400| 3| } else if ([pair.value isEqual:[NSNull null]]) { 401| 0| data = [NSData data]; 402| 3| } else { 403| 3| data = [[pair.value description] dataUsingEncoding:self.stringEncoding]; 404| 3| } 405| 3| 406| 3| if (data) { 407| 3| [formData appendPartWithFormData:data name:[pair.field description]]; 408| 3| } 409| 3| } 410| 3| } 411| 5| 412| 5| if (block) { 413| 5| block(formData); 414| 5| } 415| 5| 416| 5| return [formData requestByFinalizingMultipartFormData]; 417| 5|} 418| | 419| |- (NSMutableURLRequest *)requestWithMultipartFormRequest:(NSURLRequest *)request 420| | writingStreamContentsToFile:(NSURL *)fileURL 421| | completionHandler:(void (^)(NSError *error))handler 422| 0|{ 423| 0| NSParameterAssert(request.HTTPBodyStream); 424| 0| NSParameterAssert([fileURL isFileURL]); 425| 0| 426| 0| NSInputStream *inputStream = request.HTTPBodyStream; 427| 0| NSOutputStream *outputStream = [[NSOutputStream alloc] initWithURL:fileURL append:NO]; 428| 0| __block NSError *error = nil; 429| 0| 430| 0| dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{ 431| 0| [inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 432| 0| [outputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; 433| 0| 434| 0| [inputStream open]; 435| 0| [outputStream open]; 436| 0| 437| 0| while ([inputStream hasBytesAvailable] && [outputStream hasSpaceAvailable]) { 438| 0| uint8_t buffer[1024]; 439| 0| 440| 0| NSInteger bytesRead = [inputStream read:buffer maxLength:1024]; 441| 0| if (inputStream.streamError || bytesRead < 0) { 442| 0| error = inputStream.streamError; 443| 0| break; 444| 0| } 445| 0| 446| 0| NSInteger bytesWritten = [outputStream write:buffer maxLength:(NSUInteger)bytesRead]; 447| 0| if (outputStream.streamError || bytesWritten < 0) { 448| 0| error = outputStream.streamError; 449| 0| break; 450| 0| } 451| 0| 452| 0| if (bytesRead == 0 && bytesWritten == 0) { 453| 0| break; 454| 0| } 455| 0| } 456| 0| 457| 0| [outputStream close]; 458| 0| [inputStream close]; 459| 0| 460| 0| if (handler) { 461| 0| dispatch_async(dispatch_get_main_queue(), ^{ 462| 0| handler(error); 463| 0| }); 464| 0| } 465| 0| }); 466| 0| 467| 0| NSMutableURLRequest *mutableRequest = [request mutableCopy]; 468| 0| mutableRequest.HTTPBodyStream = nil; 469| 0| 470| 0| return mutableRequest; 471| 0|} 472| | 473| |#pragma mark - AFURLRequestSerialization 474| | 475| |- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request 476| | withParameters:(id)parameters 477| | error:(NSError *__autoreleasing *)error 478| 44|{ 479| 44| NSParameterAssert(request); 480| 44| 481| 44| NSMutableURLRequest *mutableRequest = [request mutableCopy]; 482| 44| 483| 89| [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) { 484| 89| if (![request valueForHTTPHeaderField:field]) { 485| 89| [mutableRequest setValue:value forHTTPHeaderField:field]; 486| 89| } 487| 89| }]; 488| 44| 489| 44| NSString *query = nil; 490| 44| if (parameters) { 491| 20| if (self.queryStringSerialization) { 492| 3| NSError *serializationError; 493| 3| query = self.queryStringSerialization(request, parameters, &serializationError); 494| 3| 495| 3| if (serializationError) { 496| 2| if (error) { 497| 2| *error = serializationError; 498| 2| } 499| 2| 500| 2| return nil; 501| 2| } 502| 17| } else { 503| 17| switch (self.queryStringSerializationStyle) { 504| 17| case AFHTTPRequestQueryStringDefaultStyle: 505| 17| query = AFQueryStringFromParameters(parameters); 506| 17| break; 507| 42| } 508| 42| } 509| 20| } 510| 42| 511| 42| if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) { 512| 26| if (query && query.length > 0) { 513| 7| mutableRequest.URL = [NSURL URLWithString:[[mutableRequest.URL absoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @"&%@" : @"?%@", query]]; 514| 7| } 515| 26| } else { 516| 16| // #2864: an empty string is a valid x-www-form-urlencoded payload 517| 16| if (!query) { 518| 6| query = @""; 519| 6| } 520| 16| if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) { 521| 16| [mutableRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"]; 522| 16| } 523| 16| [mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]]; 524| 16| } 525| 42| 526| 42| return mutableRequest; 527| 42|} 528| | 529| |#pragma mark - NSKeyValueObserving 530| | 531| 18|+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)key { 532| 18| if ([AFHTTPRequestSerializerObservedKeyPaths() containsObject:key]) { 533| 18| return NO; 534| 18| } 535| 0| 536| 0| return [super automaticallyNotifiesObserversForKey:key]; 537| 0|} 538| | 539| |- (void)observeValueForKeyPath:(NSString *)keyPath 540| | ofObject:(__unused id)object 541| | change:(NSDictionary *)change 542| | context:(void *)context 543| 0|{ 544| 0| if (context == AFHTTPRequestSerializerObserverContext) { 545| 0| if ([change[NSKeyValueChangeNewKey] isEqual:[NSNull null]]) { 546| 0| [self.mutableObservedChangedKeyPaths removeObject:keyPath]; 547| 0| } else { 548| 0| [self.mutableObservedChangedKeyPaths addObject:keyPath]; 549| 0| } 550| 0| } 551| 0|} 552| | 553| |#pragma mark - NSSecureCoding 554| | 555| 0|+ (BOOL)supportsSecureCoding { 556| 0| return YES; 557| 0|} 558| | 559| 1|- (instancetype)initWithCoder:(NSCoder *)decoder { 560| 1| self = [self init]; 561| 1| if (!self) { 562| 0| return nil; 563| 0| } 564| 1| 565| 1| self.mutableHTTPRequestHeaders = [[decoder decodeObjectOfClass:[NSDictionary class] forKey:NSStringFromSelector(@selector(mutableHTTPRequestHeaders))] mutableCopy]; 566| 1| self.queryStringSerializationStyle = (AFHTTPRequestQueryStringSerializationStyle)[[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(queryStringSerializationStyle))] unsignedIntegerValue]; 567| 1| 568| 1| return self; 569| 1|} 570| | 571| 2|- (void)encodeWithCoder:(NSCoder *)coder { 572| 2| dispatch_sync(self.requestHeaderModificationQueue, ^{ 573| 2| [coder encodeObject:self.mutableHTTPRequestHeaders forKey:NSStringFromSelector(@selector(mutableHTTPRequestHeaders))]; 574| 2| }); 575| 2| [coder encodeObject:@(self.queryStringSerializationStyle) forKey:NSStringFromSelector(@selector(queryStringSerializationStyle))]; 576| 2|} 577| | 578| |#pragma mark - NSCopying 579| | 580| 1|- (instancetype)copyWithZone:(NSZone *)zone { 581| 1| AFHTTPRequestSerializer *serializer = [[[self class] allocWithZone:zone] init]; 582| 1| dispatch_sync(self.requestHeaderModificationQueue, ^{ 583| 1| serializer.mutableHTTPRequestHeaders = [self.mutableHTTPRequestHeaders mutableCopyWithZone:zone]; 584| 1| }); 585| 1| serializer.queryStringSerializationStyle = self.queryStringSerializationStyle; 586| 1| serializer.queryStringSerialization = self.queryStringSerialization; 587| 1| 588| 1| return serializer; 589| 1|} 590| | 591| |@end 592| | 593| |#pragma mark - 594| | 595| 6|static NSString * AFCreateMultipartFormBoundary() { 596| 6| return [NSString stringWithFormat:@"Boundary+%08X%08X", arc4random(), arc4random()]; 597| 6|} 598| | 599| |static NSString * const kAFMultipartFormCRLF = @"\r\n"; 600| | 601| 10|static inline NSString * AFMultipartFormInitialBoundary(NSString *boundary) { 602| 10| return [NSString stringWithFormat:@"--%@%@", boundary, kAFMultipartFormCRLF]; 603| 10|} 604| | 605| 6|static inline NSString * AFMultipartFormEncapsulationBoundary(NSString *boundary) { 606| 6| return [NSString stringWithFormat:@"%@--%@%@", kAFMultipartFormCRLF, boundary, kAFMultipartFormCRLF]; 607| 6|} 608| | 609| 10|static inline NSString * AFMultipartFormFinalBoundary(NSString *boundary) { 610| 10| return [NSString stringWithFormat:@"%@--%@--%@", kAFMultipartFormCRLF, boundary, kAFMultipartFormCRLF]; 611| 10|} 612| | 613| 1|static inline NSString * AFContentTypeForPathExtension(NSString *extension) { 614| 1| NSString *UTI = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)extension, NULL); 615| 1| NSString *contentType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)UTI, kUTTagClassMIMEType); 616| 1| if (!contentType) { 617| 0| return @"application/octet-stream"; 618| 1| } else { 619| 1| return contentType; 620| 1| } 621| 1|} 622| | 623| |NSUInteger const kAFUploadStream3GSuggestedPacketSize = 1024 * 16; 624| |NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2; 625| | 626| |@interface AFHTTPBodyPart : NSObject 627| |@property (nonatomic, assign) NSStringEncoding stringEncoding; 628| |@property (nonatomic, strong) NSDictionary *headers; 629| |@property (nonatomic, copy) NSString *boundary; 630| |@property (nonatomic, strong) id body; 631| |@property (nonatomic, assign) unsigned long long bodyContentLength; 632| |@property (nonatomic, strong) NSInputStream *inputStream; 633| | 634| |@property (nonatomic, assign) BOOL hasInitialBoundary; 635| |@property (nonatomic, assign) BOOL hasFinalBoundary; 636| | 637| |@property (readonly, nonatomic, assign, getter = hasBytesAvailable) BOOL bytesAvailable; 638| |@property (readonly, nonatomic, assign) unsigned long long contentLength; 639| | 640| |- (NSInteger)read:(uint8_t *)buffer 641| | maxLength:(NSUInteger)length; 642| |@end 643| | 644| |@interface AFMultipartBodyStream : NSInputStream 645| |@property (nonatomic, assign) NSUInteger numberOfBytesInPacket; 646| |@property (nonatomic, assign) NSTimeInterval delay; 647| |@property (nonatomic, strong) NSInputStream *inputStream; 648| |@property (readonly, nonatomic, assign) unsigned long long contentLength; 649| |@property (readonly, nonatomic, assign, getter = isEmpty) BOOL empty; 650| | 651| |- (instancetype)initWithStringEncoding:(NSStringEncoding)encoding; 652| |- (void)setInitialAndFinalBoundaries; 653| |- (void)appendHTTPBodyPart:(AFHTTPBodyPart *)bodyPart; 654| |@end 655| | 656| |#pragma mark - 657| | 658| |@interface AFStreamingMultipartFormData () 659| |@property (readwrite, nonatomic, copy) NSMutableURLRequest *request; 660| |@property (readwrite, nonatomic, assign) NSStringEncoding stringEncoding; 661| |@property (readwrite, nonatomic, copy) NSString *boundary; 662| |@property (readwrite, nonatomic, strong) AFMultipartBodyStream *bodyStream; 663| |@end 664| | 665| |@implementation AFStreamingMultipartFormData 666| | 667| |- (instancetype)initWithURLRequest:(NSMutableURLRequest *)urlRequest 668| | stringEncoding:(NSStringEncoding)encoding 669| 6|{ 670| 6| self = [super init]; 671| 6| if (!self) { 672| 0| return nil; 673| 0| } 674| 6| 675| 6| self.request = urlRequest; 676| 6| self.stringEncoding = encoding; 677| 6| self.boundary = AFCreateMultipartFormBoundary(); 678| 6| self.bodyStream = [[AFMultipartBodyStream alloc] initWithStringEncoding:encoding]; 679| 6| 680| 6| return self; 681| 6|} 682| | 683| |- (void)setRequest:(NSMutableURLRequest *)request 684| 6|{ 685| 6| _request = [request mutableCopy]; 686| 6|} 687| | 688| |- (BOOL)appendPartWithFileURL:(NSURL *)fileURL 689| | name:(NSString *)name 690| | error:(NSError * __autoreleasing *)error 691| 1|{ 692| 1| NSParameterAssert(fileURL); 693| 1| NSParameterAssert(name); 694| 1| 695| 1| NSString *fileName = [fileURL lastPathComponent]; 696| 1| NSString *mimeType = AFContentTypeForPathExtension([fileURL pathExtension]); 697| 1| 698| 1| return [self appendPartWithFileURL:fileURL name:name fileName:fileName mimeType:mimeType error:error]; 699| 1|} 700| | 701| |- (BOOL)appendPartWithFileURL:(NSURL *)fileURL 702| | name:(NSString *)name 703| | fileName:(NSString *)fileName 704| | mimeType:(NSString *)mimeType 705| | error:(NSError * __autoreleasing *)error 706| 1|{ 707| 1| NSParameterAssert(fileURL); 708| 1| NSParameterAssert(name); 709| 1| NSParameterAssert(fileName); 710| 1| NSParameterAssert(mimeType); 711| 1| 712| 1| if (![fileURL isFileURL]) { 713| 0| NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey: NSLocalizedStringFromTable(@"Expected URL to be a file URL", @"AFNetworking", nil)}; 714| 0| if (error) { 715| 0| *error = [[NSError alloc] initWithDomain:AFURLRequestSerializationErrorDomain code:NSURLErrorBadURL userInfo:userInfo]; 716| 0| } 717| 0| 718| 0| return NO; 719| 1| } else if ([fileURL checkResourceIsReachableAndReturnError:error] == NO) { 720| 0| NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey: NSLocalizedStringFromTable(@"File URL not reachable.", @"AFNetworking", nil)}; 721| 0| if (error) { 722| 0| *error = [[NSError alloc] initWithDomain:AFURLRequestSerializationErrorDomain code:NSURLErrorBadURL userInfo:userInfo]; 723| 0| } 724| 0| 725| 0| return NO; 726| 0| } 727| 1| 728| 1| NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[fileURL path] error:error]; 729| 1| if (!fileAttributes) { 730| 0| return NO; 731| 0| } 732| 1| 733| 1| NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; 734| 1| [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"]; 735| 1| [mutableHeaders setValue:mimeType forKey:@"Content-Type"]; 736| 1| 737| 1| AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init]; 738| 1| bodyPart.stringEncoding = self.stringEncoding; 739| 1| bodyPart.headers = mutableHeaders; 740| 1| bodyPart.boundary = self.boundary; 741| 1| bodyPart.body = fileURL; 742| 1| bodyPart.bodyContentLength = [fileAttributes[NSFileSize] unsignedLongLongValue]; 743| 1| [self.bodyStream appendHTTPBodyPart:bodyPart]; 744| 1| 745| 1| return YES; 746| 1|} 747| | 748| |- (void)appendPartWithInputStream:(NSInputStream *)inputStream 749| | name:(NSString *)name 750| | fileName:(NSString *)fileName 751| | length:(int64_t)length 752| | mimeType:(NSString *)mimeType 753| 0|{ 754| 0| NSParameterAssert(name); 755| 0| NSParameterAssert(fileName); 756| 0| NSParameterAssert(mimeType); 757| 0| 758| 0| NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; 759| 0| [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"]; 760| 0| [mutableHeaders setValue:mimeType forKey:@"Content-Type"]; 761| 0| 762| 0| AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init]; 763| 0| bodyPart.stringEncoding = self.stringEncoding; 764| 0| bodyPart.headers = mutableHeaders; 765| 0| bodyPart.boundary = self.boundary; 766| 0| bodyPart.body = inputStream; 767| 0| 768| 0| bodyPart.bodyContentLength = (unsigned long long)length; 769| 0| 770| 0| [self.bodyStream appendHTTPBodyPart:bodyPart]; 771| 0|} 772| | 773| |- (void)appendPartWithFileData:(NSData *)data 774| | name:(NSString *)name 775| | fileName:(NSString *)fileName 776| | mimeType:(NSString *)mimeType 777| 5|{ 778| 5| NSParameterAssert(name); 779| 5| NSParameterAssert(fileName); 780| 5| NSParameterAssert(mimeType); 781| 5| 782| 5| NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; 783| 5| [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"; filename=\"%@\"", name, fileName] forKey:@"Content-Disposition"]; 784| 5| [mutableHeaders setValue:mimeType forKey:@"Content-Type"]; 785| 5| 786| 5| [self appendPartWithHeaders:mutableHeaders body:data]; 787| 5|} 788| | 789| |- (void)appendPartWithFormData:(NSData *)data 790| | name:(NSString *)name 791| 3|{ 792| 3| NSParameterAssert(name); 793| 3| 794| 3| NSMutableDictionary *mutableHeaders = [NSMutableDictionary dictionary]; 795| 3| [mutableHeaders setValue:[NSString stringWithFormat:@"form-data; name=\"%@\"", name] forKey:@"Content-Disposition"]; 796| 3| 797| 3| [self appendPartWithHeaders:mutableHeaders body:data]; 798| 3|} 799| | 800| |- (void)appendPartWithHeaders:(NSDictionary *)headers 801| | body:(NSData *)body 802| 8|{ 803| 8| NSParameterAssert(body); 804| 8| 805| 8| AFHTTPBodyPart *bodyPart = [[AFHTTPBodyPart alloc] init]; 806| 8| bodyPart.stringEncoding = self.stringEncoding; 807| 8| bodyPart.headers = headers; 808| 8| bodyPart.boundary = self.boundary; 809| 8| bodyPart.bodyContentLength = [body length]; 810| 8| bodyPart.body = body; 811| 8| 812| 8| [self.bodyStream appendHTTPBodyPart:bodyPart]; 813| 8|} 814| | 815| |- (void)throttleBandwidthWithPacketSize:(NSUInteger)numberOfBytes 816| | delay:(NSTimeInterval)delay 817| 0|{ 818| 0| self.bodyStream.numberOfBytesInPacket = numberOfBytes; 819| 0| self.bodyStream.delay = delay; 820| 0|} 821| | 822| 5|- (NSMutableURLRequest *)requestByFinalizingMultipartFormData { 823| 5| if ([self.bodyStream isEmpty]) { 824| 0| return self.request; 825| 0| } 826| 5| 827| 5| // Reset the initial and final boundaries to ensure correct Content-Length 828| 5| [self.bodyStream setInitialAndFinalBoundaries]; 829| 5| [self.request setHTTPBodyStream:self.bodyStream]; 830| 5| 831| 5| [self.request setValue:[NSString stringWithFormat:@"multipart/form-data; boundary=%@", self.boundary] forHTTPHeaderField:@"Content-Type"]; 832| 5| [self.request setValue:[NSString stringWithFormat:@"%llu", [self.bodyStream contentLength]] forHTTPHeaderField:@"Content-Length"]; 833| 5| 834| 5| return self.request; 835| 5|} 836| | 837| |@end 838| | 839| |#pragma mark - 840| | 841| |@interface NSStream () 842| |@property (readwrite) NSStreamStatus streamStatus; 843| |@property (readwrite, copy) NSError *streamError; 844| |@end 845| | 846| |@interface AFMultipartBodyStream () 847| |@property (readwrite, nonatomic, assign) NSStringEncoding stringEncoding; 848| |@property (readwrite, nonatomic, strong) NSMutableArray *HTTPBodyParts; 849| |@property (readwrite, nonatomic, strong) NSEnumerator *HTTPBodyPartEnumerator; 850| |@property (readwrite, nonatomic, strong) AFHTTPBodyPart *currentHTTPBodyPart; 851| |@property (readwrite, nonatomic, strong) NSOutputStream *outputStream; 852| |@property (readwrite, nonatomic, strong) NSMutableData *buffer; 853| |@end 854| | 855| |@implementation AFMultipartBodyStream 856| |#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1100) 857| |@synthesize delegate; 858| |#endif 859| |@synthesize streamStatus; 860| |@synthesize streamError; 861| | 862| 6|- (instancetype)initWithStringEncoding:(NSStringEncoding)encoding { 863| 6| self = [super init]; 864| 6| if (!self) { 865| 0| return nil; 866| 0| } 867| 6| 868| 6| self.stringEncoding = encoding; 869| 6| self.HTTPBodyParts = [NSMutableArray array]; 870| 6| self.numberOfBytesInPacket = NSIntegerMax; 871| 6| 872| 6| return self; 873| 6|} 874| | 875| 10|- (void)setInitialAndFinalBoundaries { 876| 10| if ([self.HTTPBodyParts count] > 0) { 877| 16| for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) { 878| 16| bodyPart.hasInitialBoundary = NO; 879| 16| bodyPart.hasFinalBoundary = NO; 880| 16| } 881| 10| 882| 10| [[self.HTTPBodyParts firstObject] setHasInitialBoundary:YES]; 883| 10| [[self.HTTPBodyParts lastObject] setHasFinalBoundary:YES]; 884| 10| } 885| 10|} 886| | 887| 9|- (void)appendHTTPBodyPart:(AFHTTPBodyPart *)bodyPart { 888| 9| [self.HTTPBodyParts addObject:bodyPart]; 889| 9|} 890| | 891| 5|- (BOOL)isEmpty { 892| 5| return [self.HTTPBodyParts count] == 0; 893| 5|} 894| | 895| |#pragma mark - NSInputStream 896| | 897| |- (NSInteger)read:(uint8_t *)buffer 898| | maxLength:(NSUInteger)length 899| 10|{ 900| 10| if ([self streamStatus] == NSStreamStatusClosed) { 901| 0| return 0; 902| 0| } 903| 10| 904| 10| NSInteger totalNumberOfBytesRead = 0; 905| 10| 906| 26| while ((NSUInteger)totalNumberOfBytesRead < MIN(length, self.numberOfBytesInPacket)) { 907| 26| if (!self.currentHTTPBodyPart || ![self.currentHTTPBodyPart hasBytesAvailable]) { 908| 18| if (!(self.currentHTTPBodyPart = [self.HTTPBodyPartEnumerator nextObject])) { 909| 10| break; 910| 10| } 911| 8| } else { 912| 8| NSUInteger maxLength = MIN(length, self.numberOfBytesInPacket) - (NSUInteger)totalNumberOfBytesRead; 913| 8| NSInteger numberOfBytesRead = [self.currentHTTPBodyPart read:&buffer[totalNumberOfBytesRead] maxLength:maxLength]; 914| 8| if (numberOfBytesRead == -1) { 915| 0| self.streamError = self.currentHTTPBodyPart.inputStream.streamError; 916| 0| break; 917| 8| } else { 918| 8| totalNumberOfBytesRead += numberOfBytesRead; 919| 8| 920| 8| if (self.delay > 0.0f) { 921| 0| [NSThread sleepForTimeInterval:self.delay]; 922| 0| } 923| 8| } 924| 8| } 925| 26| } 926| 10| 927| 10| return totalNumberOfBytesRead; 928| 10|} 929| | 930| |- (BOOL)getBuffer:(__unused uint8_t **)buffer 931| | length:(__unused NSUInteger *)len 932| 0|{ 933| 0| return NO; 934| 0|} 935| | 936| 20|- (BOOL)hasBytesAvailable { 937| 20| return [self streamStatus] == NSStreamStatusOpen; 938| 20|} 939| | 940| |#pragma mark - NSStream 941| | 942| 5|- (void)open { 943| 5| if (self.streamStatus == NSStreamStatusOpen) { 944| 0| return; 945| 0| } 946| 5| 947| 5| self.streamStatus = NSStreamStatusOpen; 948| 5| 949| 5| [self setInitialAndFinalBoundaries]; 950| 5| self.HTTPBodyPartEnumerator = [self.HTTPBodyParts objectEnumerator]; 951| 5|} 952| | 953| 5|- (void)close { 954| 5| self.streamStatus = NSStreamStatusClosed; 955| 5|} 956| | 957| 0|- (id)propertyForKey:(__unused NSString *)key { 958| 0| return nil; 959| 0|} 960| | 961| |- (BOOL)setProperty:(__unused id)property 962| | forKey:(__unused NSString *)key 963| 0|{ 964| 0| return NO; 965| 0|} 966| | 967| |- (void)scheduleInRunLoop:(__unused NSRunLoop *)aRunLoop 968| | forMode:(__unused NSString *)mode 969| 0|{} 970| | 971| |- (void)removeFromRunLoop:(__unused NSRunLoop *)aRunLoop 972| | forMode:(__unused NSString *)mode 973| 0|{} 974| | 975| 5|- (unsigned long long)contentLength { 976| 5| unsigned long long length = 0; 977| 8| for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) { 978| 8| length += [bodyPart contentLength]; 979| 8| } 980| 5| 981| 5| return length; 982| 5|} 983| | 984| |#pragma mark - Undocumented CFReadStream Bridged Methods 985| | 986| |- (void)_scheduleInCFRunLoop:(__unused CFRunLoopRef)aRunLoop 987| | forMode:(__unused CFStringRef)aMode 988| 0|{} 989| | 990| |- (void)_unscheduleFromCFRunLoop:(__unused CFRunLoopRef)aRunLoop 991| | forMode:(__unused CFStringRef)aMode 992| 0|{} 993| | 994| |- (BOOL)_setCFClientFlags:(__unused CFOptionFlags)inFlags 995| | callback:(__unused CFReadStreamClientCallBack)inCallback 996| 5| context:(__unused CFStreamClientContext *)inContext { 997| 5| return NO; 998| 5|} 999| | 1000| |#pragma mark - NSCopying 1001| | 1002| 0|- (instancetype)copyWithZone:(NSZone *)zone { 1003| 0| AFMultipartBodyStream *bodyStreamCopy = [[[self class] allocWithZone:zone] initWithStringEncoding:self.stringEncoding]; 1004| 0| 1005| 0| for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) { 1006| 0| [bodyStreamCopy appendHTTPBodyPart:[bodyPart copy]]; 1007| 0| } 1008| 0| 1009| 0| [bodyStreamCopy setInitialAndFinalBoundaries]; 1010| 0| 1011| 0| return bodyStreamCopy; 1012| 0|} 1013| | 1014| |@end 1015| | 1016| |#pragma mark - 1017| | 1018| |typedef enum { 1019| | AFEncapsulationBoundaryPhase = 1, 1020| | AFHeaderPhase = 2, 1021| | AFBodyPhase = 3, 1022| | AFFinalBoundaryPhase = 4, 1023| |} AFHTTPBodyPartReadPhase; 1024| | 1025| |@interface AFHTTPBodyPart () { 1026| | AFHTTPBodyPartReadPhase _phase; 1027| | NSInputStream *_inputStream; 1028| | unsigned long long _phaseReadOffset; 1029| |} 1030| | 1031| |- (BOOL)transitionToNextPhase; 1032| |- (NSInteger)readData:(NSData *)data 1033| | intoBuffer:(uint8_t *)buffer 1034| | maxLength:(NSUInteger)length; 1035| |@end 1036| | 1037| |@implementation AFHTTPBodyPart 1038| | 1039| 9|- (instancetype)init { 1040| 9| self = [super init]; 1041| 9| if (!self) { 1042| 0| return nil; 1043| 0| } 1044| 9| 1045| 9| [self transitionToNextPhase]; 1046| 9| 1047| 9| return self; 1048| 9|} 1049| | 1050| 9|- (void)dealloc { 1051| 9| if (_inputStream) { 1052| 8| [_inputStream close]; 1053| 8| _inputStream = nil; 1054| 8| } 1055| 9|} 1056| | 1057| 56|- (NSInputStream *)inputStream { 1058| 56| if (!_inputStream) { 1059| 8| if ([self.body isKindOfClass:[NSData class]]) { 1060| 8| _inputStream = [NSInputStream inputStreamWithData:self.body]; 1061| 8| } else if ([self.body isKindOfClass:[NSURL class]]) { 1062| 0| _inputStream = [NSInputStream inputStreamWithURL:self.body]; 1063| 0| } else if ([self.body isKindOfClass:[NSInputStream class]]) { 1064| 0| _inputStream = self.body; 1065| 0| } else { 1066| 0| _inputStream = [NSInputStream inputStreamWithData:[NSData data]]; 1067| 0| } 1068| 8| } 1069| 56| 1070| 56| return _inputStream; 1071| 56|} 1072| | 1073| 16|- (NSString *)stringForHeaders { 1074| 16| NSMutableString *headerString = [NSMutableString string]; 1075| 26| for (NSString *field in [self.headers allKeys]) { 1076| 26| [headerString appendString:[NSString stringWithFormat:@"%@: %@%@", field, [self.headers valueForKey:field], kAFMultipartFormCRLF]]; 1077| 26| } 1078| 16| [headerString appendString:kAFMultipartFormCRLF]; 1079| 16| 1080| 16| return [NSString stringWithString:headerString]; 1081| 16|} 1082| | 1083| 8|- (unsigned long long)contentLength { 1084| 8| unsigned long long length = 0; 1085| 8| 1086| 8| NSData *encapsulationBoundaryData = [([self hasInitialBoundary] ? AFMultipartFormInitialBoundary(self.boundary) : AFMultipartFormEncapsulationBoundary(self.boundary)) dataUsingEncoding:self.stringEncoding]; 1087| 8| length += [encapsulationBoundaryData length]; 1088| 8| 1089| 8| NSData *headersData = [[self stringForHeaders] dataUsingEncoding:self.stringEncoding]; 1090| 8| length += [headersData length]; 1091| 8| 1092| 8| length += _bodyContentLength; 1093| 8| 1094| 8| NSData *closingBoundaryData = ([self hasFinalBoundary] ? [AFMultipartFormFinalBoundary(self.boundary) dataUsingEncoding:self.stringEncoding] : [NSData data]); 1095| 8| length += [closingBoundaryData length]; 1096| 8| 1097| 8| return length; 1098| 8|} 1099| | 1100| 16|- (BOOL)hasBytesAvailable { 1101| 16| // Allows `read:maxLength:` to be called again if `AFMultipartFormFinalBoundary` doesn't fit into the available buffer 1102| 16| if (_phase == AFFinalBoundaryPhase) { 1103| 0| return YES; 1104| 0| } 1105| 16| 1106| 16| switch (self.inputStream.streamStatus) { 1107| 16| case NSStreamStatusNotOpen: 1108| 8| case NSStreamStatusOpening: 1109| 8| case NSStreamStatusOpen: 1110| 8| case NSStreamStatusReading: 1111| 8| case NSStreamStatusWriting: 1112| 8| return YES; 1113| 8| case NSStreamStatusAtEnd: 1114| 8| case NSStreamStatusClosed: 1115| 8| case NSStreamStatusError: 1116| 8| default: 1117| 8| return NO; 1118| 16| } 1119| 16|} 1120| | 1121| |- (NSInteger)read:(uint8_t *)buffer 1122| | maxLength:(NSUInteger)length 1123| 8|{ 1124| 8| NSInteger totalNumberOfBytesRead = 0; 1125| 8| 1126| 8| if (_phase == AFEncapsulationBoundaryPhase) { 1127| 8| NSData *encapsulationBoundaryData = [([self hasInitialBoundary] ? AFMultipartFormInitialBoundary(self.boundary) : AFMultipartFormEncapsulationBoundary(self.boundary)) dataUsingEncoding:self.stringEncoding]; 1128| 8| totalNumberOfBytesRead += [self readData:encapsulationBoundaryData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)]; 1129| 8| } 1130| 8| 1131| 8| if (_phase == AFHeaderPhase) { 1132| 8| NSData *headersData = [[self stringForHeaders] dataUsingEncoding:self.stringEncoding]; 1133| 8| totalNumberOfBytesRead += [self readData:headersData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)]; 1134| 8| } 1135| 8| 1136| 8| if (_phase == AFBodyPhase) { 1137| 8| NSInteger numberOfBytesRead = 0; 1138| 8| 1139| 8| numberOfBytesRead = [self.inputStream read:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)]; 1140| 8| if (numberOfBytesRead == -1) { 1141| 0| return -1; 1142| 8| } else { 1143| 8| totalNumberOfBytesRead += numberOfBytesRead; 1144| 8| 1145| 8| if ([self.inputStream streamStatus] >= NSStreamStatusAtEnd) { 1146| 8| [self transitionToNextPhase]; 1147| 8| } 1148| 8| } 1149| 8| } 1150| 8| 1151| 8| if (_phase == AFFinalBoundaryPhase) { 1152| 8| NSData *closingBoundaryData = ([self hasFinalBoundary] ? [AFMultipartFormFinalBoundary(self.boundary) dataUsingEncoding:self.stringEncoding] : [NSData data]); 1153| 8| totalNumberOfBytesRead += [self readData:closingBoundaryData intoBuffer:&buffer[totalNumberOfBytesRead] maxLength:(length - (NSUInteger)totalNumberOfBytesRead)]; 1154| 8| } 1155| 8| 1156| 8| return totalNumberOfBytesRead; 1157| 8|} 1158| | 1159| |- (NSInteger)readData:(NSData *)data 1160| | intoBuffer:(uint8_t *)buffer 1161| | maxLength:(NSUInteger)length 1162| 24|{ 1163| 24| NSRange range = NSMakeRange((NSUInteger)_phaseReadOffset, MIN([data length] - ((NSUInteger)_phaseReadOffset), length)); 1164| 24| [data getBytes:buffer range:range]; 1165| 24| 1166| 24| _phaseReadOffset += range.length; 1167| 24| 1168| 24| if (((NSUInteger)_phaseReadOffset) >= [data length]) { 1169| 24| [self transitionToNextPhase]; 1170| 24| } 1171| 24| 1172| 24| return (NSInteger)range.length; 1173| 24|} 1174| | 1175| 73|- (BOOL)transitionToNextPhase { 1176| 73| if (![[NSThread currentThread] isMainThread]) { 1177| 32| dispatch_sync(dispatch_get_main_queue(), ^{ 1178| 32| [self transitionToNextPhase]; 1179| 32| }); 1180| 32| return YES; 1181| 32| } 1182| 41| 1183| 41| switch (_phase) { 1184| 41| case AFEncapsulationBoundaryPhase: 1185| 8| _phase = AFHeaderPhase; 1186| 8| break; 1187| 41| case AFHeaderPhase: 1188| 8| [self.inputStream scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; 1189| 8| [self.inputStream open]; 1190| 8| _phase = AFBodyPhase; 1191| 8| break; 1192| 41| case AFBodyPhase: 1193| 8| [self.inputStream close]; 1194| 8| _phase = AFFinalBoundaryPhase; 1195| 8| break; 1196| 41| case AFFinalBoundaryPhase: 1197| 17| default: 1198| 17| _phase = AFEncapsulationBoundaryPhase; 1199| 17| break; 1200| 41| } 1201| 41| _phaseReadOffset = 0; 1202| 41| 1203| 41| return YES; 1204| 41|} 1205| | 1206| |#pragma mark - NSCopying 1207| | 1208| 0|- (instancetype)copyWithZone:(NSZone *)zone { 1209| 0| AFHTTPBodyPart *bodyPart = [[[self class] allocWithZone:zone] init]; 1210| 0| 1211| 0| bodyPart.stringEncoding = self.stringEncoding; 1212| 0| bodyPart.headers = self.headers; 1213| 0| bodyPart.bodyContentLength = self.bodyContentLength; 1214| 0| bodyPart.body = self.body; 1215| 0| bodyPart.boundary = self.boundary; 1216| 0| 1217| 0| return bodyPart; 1218| 0|} 1219| | 1220| |@end 1221| | 1222| |#pragma mark - 1223| | 1224| |@implementation AFJSONRequestSerializer 1225| | 1226| 0|+ (instancetype)serializer { 1227| 0| return [self serializerWithWritingOptions:(NSJSONWritingOptions)0]; 1228| 0|} 1229| | 1230| |+ (instancetype)serializerWithWritingOptions:(NSJSONWritingOptions)writingOptions 1231| 0|{ 1232| 0| AFJSONRequestSerializer *serializer = [[self alloc] init]; 1233| 0| serializer.writingOptions = writingOptions; 1234| 0| 1235| 0| return serializer; 1236| 0|} 1237| | 1238| |#pragma mark - AFURLRequestSerialization 1239| | 1240| |- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request 1241| | withParameters:(id)parameters 1242| | error:(NSError *__autoreleasing *)error 1243| 4|{ 1244| 4| NSParameterAssert(request); 1245| 4| 1246| 4| if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) { 1247| 0| return [super requestBySerializingRequest:request withParameters:parameters error:error]; 1248| 0| } 1249| 4| 1250| 4| NSMutableURLRequest *mutableRequest = [request mutableCopy]; 1251| 4| 1252| 8| [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) { 1253| 8| if (![request valueForHTTPHeaderField:field]) { 1254| 8| [mutableRequest setValue:value forHTTPHeaderField:field]; 1255| 8| } 1256| 8| }]; 1257| 4| 1258| 4| if (parameters) { 1259| 4| if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) { 1260| 4| [mutableRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; 1261| 4| } 1262| 4| 1263| 4| if (![NSJSONSerialization isValidJSONObject:parameters]) { 1264| 2| if (error) { 1265| 2| NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey: NSLocalizedStringFromTable(@"The `parameters` argument is not valid JSON.", @"AFNetworking", nil)}; 1266| 2| *error = [[NSError alloc] initWithDomain:AFURLRequestSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo]; 1267| 2| } 1268| 2| return nil; 1269| 2| } 1270| 2| 1271| 2| NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parameters options:self.writingOptions error:error]; 1272| 2| 1273| 2| if (!jsonData) { 1274| 0| return nil; 1275| 0| } 1276| 2| 1277| 2| [mutableRequest setHTTPBody:jsonData]; 1278| 2| } 1279| 4| 1280| 4| return mutableRequest; 1281| 4|} 1282| | 1283| |#pragma mark - NSSecureCoding 1284| | 1285| 0|- (instancetype)initWithCoder:(NSCoder *)decoder { 1286| 0| self = [super initWithCoder:decoder]; 1287| 0| if (!self) { 1288| 0| return nil; 1289| 0| } 1290| 0| 1291| 0| self.writingOptions = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(writingOptions))] unsignedIntegerValue]; 1292| 0| 1293| 0| return self; 1294| 0|} 1295| | 1296| 0|- (void)encodeWithCoder:(NSCoder *)coder { 1297| 0| [super encodeWithCoder:coder]; 1298| 0| 1299| 0| [coder encodeObject:@(self.writingOptions) forKey:NSStringFromSelector(@selector(writingOptions))]; 1300| 0|} 1301| | 1302| |#pragma mark - NSCopying 1303| | 1304| 0|- (instancetype)copyWithZone:(NSZone *)zone { 1305| 0| AFJSONRequestSerializer *serializer = [super copyWithZone:zone]; 1306| 0| serializer.writingOptions = self.writingOptions; 1307| 0| 1308| 0| return serializer; 1309| 0|} 1310| | 1311| |@end 1312| | 1313| |#pragma mark - 1314| | 1315| |@implementation AFPropertyListRequestSerializer 1316| | 1317| 2|+ (instancetype)serializer { 1318| 2| return [self serializerWithFormat:NSPropertyListXMLFormat_v1_0 writeOptions:0]; 1319| 2|} 1320| | 1321| |+ (instancetype)serializerWithFormat:(NSPropertyListFormat)format 1322| | writeOptions:(NSPropertyListWriteOptions)writeOptions 1323| 2|{ 1324| 2| AFPropertyListRequestSerializer *serializer = [[self alloc] init]; 1325| 2| serializer.format = format; 1326| 2| serializer.writeOptions = writeOptions; 1327| 2| 1328| 2| return serializer; 1329| 2|} 1330| | 1331| |#pragma mark - AFURLRequestSerializer 1332| | 1333| |- (NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request 1334| | withParameters:(id)parameters 1335| | error:(NSError *__autoreleasing *)error 1336| 2|{ 1337| 2| NSParameterAssert(request); 1338| 2| 1339| 2| if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) { 1340| 0| return [super requestBySerializingRequest:request withParameters:parameters error:error]; 1341| 0| } 1342| 2| 1343| 2| NSMutableURLRequest *mutableRequest = [request mutableCopy]; 1344| 2| 1345| 4| [self.HTTPRequestHeaders enumerateKeysAndObjectsUsingBlock:^(id field, id value, BOOL * __unused stop) { 1346| 4| if (![request valueForHTTPHeaderField:field]) { 1347| 4| [mutableRequest setValue:value forHTTPHeaderField:field]; 1348| 4| } 1349| 4| }]; 1350| 2| 1351| 2| if (parameters) { 1352| 2| if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) { 1353| 2| [mutableRequest setValue:@"application/x-plist" forHTTPHeaderField:@"Content-Type"]; 1354| 2| } 1355| 2| 1356| 2| NSData *plistData = [NSPropertyListSerialization dataWithPropertyList:parameters format:self.format options:self.writeOptions error:error]; 1357| 2| 1358| 2| if (!plistData) { 1359| 1| return nil; 1360| 1| } 1361| 1| 1362| 1| [mutableRequest setHTTPBody:plistData]; 1363| 1| } 1364| 2| 1365| 2| return mutableRequest; 1366| 2|} 1367| | 1368| |#pragma mark - NSSecureCoding 1369| | 1370| 0|- (instancetype)initWithCoder:(NSCoder *)decoder { 1371| 0| self = [super initWithCoder:decoder]; 1372| 0| if (!self) { 1373| 0| return nil; 1374| 0| } 1375| 0| 1376| 0| self.format = (NSPropertyListFormat)[[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(format))] unsignedIntegerValue]; 1377| 0| self.writeOptions = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(writeOptions))] unsignedIntegerValue]; 1378| 0| 1379| 0| return self; 1380| 0|} 1381| | 1382| 0|- (void)encodeWithCoder:(NSCoder *)coder { 1383| 0| [super encodeWithCoder:coder]; 1384| 0| 1385| 0| [coder encodeObject:@(self.format) forKey:NSStringFromSelector(@selector(format))]; 1386| 0| [coder encodeObject:@(self.writeOptions) forKey:NSStringFromSelector(@selector(writeOptions))]; 1387| 0|} 1388| | 1389| |#pragma mark - NSCopying 1390| | 1391| 0|- (instancetype)copyWithZone:(NSZone *)zone { 1392| 0| AFPropertyListRequestSerializer *serializer = [super copyWithZone:zone]; 1393| 0| serializer.format = self.format; 1394| 0| serializer.writeOptions = self.writeOptions; 1395| 0| 1396| 0| return serializer; 1397| 0|} 1398| | 1399| |@end /Users/travis/build/AFNetworking/AFNetworking/AFNetworking/AFURLResponseSerialization.m: 1| |// AFURLResponseSerialization.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "AFURLResponseSerialization.h" 23| | 24| |#import 25| | 26| |#if TARGET_OS_IOS 27| |#import 28| |#elif TARGET_OS_WATCH 29| |#import 30| |#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED) 31| |#import 32| |#endif 33| | 34| |NSString * const AFURLResponseSerializationErrorDomain = @"com.alamofire.error.serialization.response"; 35| |NSString * const AFNetworkingOperationFailingURLResponseErrorKey = @"com.alamofire.serialization.response.error.response"; 36| |NSString * const AFNetworkingOperationFailingURLResponseDataErrorKey = @"com.alamofire.serialization.response.error.data"; 37| | 38| 216|static NSError * AFErrorWithUnderlyingError(NSError *error, NSError *underlyingError) { 39| 216| if (!error) { 40| 1| return underlyingError; 41| 1| } 42| 215| 43| 215| if (!underlyingError || error.userInfo[NSUnderlyingErrorKey]) { 44| 215| return error; 45| 215| } 46| 0| 47| 0| NSMutableDictionary *mutableUserInfo = [error.userInfo mutableCopy]; 48| 0| mutableUserInfo[NSUnderlyingErrorKey] = underlyingError; 49| 0| 50| 0| return [[NSError alloc] initWithDomain:error.domain code:error.code userInfo:mutableUserInfo]; 51| 0|} 52| | 53| 14|static BOOL AFErrorOrUnderlyingErrorHasCodeInDomain(NSError *error, NSInteger code, NSString *domain) { 54| 14| if ([error.domain isEqualToString:domain] && error.code == code) { 55| 2| return YES; 56| 12| } else if (error.userInfo[NSUnderlyingErrorKey]) { 57| 0| return AFErrorOrUnderlyingErrorHasCodeInDomain(error.userInfo[NSUnderlyingErrorKey], code, domain); 58| 0| } 59| 12| 60| 12| return NO; 61| 12|} 62| | 63| 4|id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingOptions readingOptions) { 64| 4| if ([JSONObject isKindOfClass:[NSArray class]]) { 65| 2| NSMutableArray *mutableArray = [NSMutableArray arrayWithCapacity:[(NSArray *)JSONObject count]]; 66| 2| for (id value in (NSArray *)JSONObject) { 67| 2| if (![value isEqual:[NSNull null]]) { 68| 1| [mutableArray addObject:AFJSONObjectByRemovingKeysWithNullValues(value, readingOptions)]; 69| 1| } 70| 2| } 71| 2| 72| 2| return (readingOptions & NSJSONReadingMutableContainers) ? mutableArray : [NSArray arrayWithArray:mutableArray]; 73| 2| } else if ([JSONObject isKindOfClass:[NSDictionary class]]) { 74| 2| NSMutableDictionary *mutableDictionary = [NSMutableDictionary dictionaryWithDictionary:JSONObject]; 75| 5| for (id key in [(NSDictionary *)JSONObject allKeys]) { 76| 5| id value = (NSDictionary *)JSONObject[key]; 77| 5| if (!value || [value isEqual:[NSNull null]]) { 78| 2| [mutableDictionary removeObjectForKey:key]; 79| 3| } else if ([value isKindOfClass:[NSArray class]] || [value isKindOfClass:[NSDictionary class]]) { 80| 2| mutableDictionary[key] = AFJSONObjectByRemovingKeysWithNullValues(value, readingOptions); 81| 2| } 82| 5| } 83| 2| 84| 2| return (readingOptions & NSJSONReadingMutableContainers) ? mutableDictionary : [NSDictionary dictionaryWithDictionary:mutableDictionary]; 85| 2| } 86| 0| 87| 0| return JSONObject; 88| 0|} 89| | 90| |@implementation AFHTTPResponseSerializer 91| | 92| 45|+ (instancetype)serializer { 93| 45| return [[self alloc] init]; 94| 45|} 95| | 96| 312|- (instancetype)init { 97| 312| self = [super init]; 98| 312| if (!self) { 99| 0| return nil; 100| 0| } 101| 312| 102| 312| self.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)]; 103| 312| self.acceptableContentTypes = nil; 104| 312| 105| 312| return self; 106| 312|} 107| | 108| |#pragma mark - 109| | 110| |- (BOOL)validateResponse:(NSHTTPURLResponse *)response 111| | data:(NSData *)data 112| | error:(NSError * __autoreleasing *)error 113| 395|{ 114| 395| BOOL responseIsValid = YES; 115| 395| NSError *validationError = nil; 116| 395| 117| 395| if ([response isKindOfClass:[NSHTTPURLResponse class]]) { 118| 395| if (self.acceptableContentTypes && ![self.acceptableContentTypes containsObject:[response MIMEType]] && 119| 395| !([response MIMEType] == nil && [data length] == 0)) { 120| 16| 121| 16| if ([data length] > 0 && [response URL]) { 122| 6| NSMutableDictionary *mutableUserInfo = [@{ 123| 6| NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: unacceptable content-type: %@", @"AFNetworking", nil), [response MIMEType]], 124| 6| NSURLErrorFailingURLErrorKey:[response URL], 125| 6| AFNetworkingOperationFailingURLResponseErrorKey: response, 126| 6| } mutableCopy]; 127| 6| if (data) { 128| 6| mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data; 129| 6| } 130| 6| 131| 6| validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:mutableUserInfo], validationError); 132| 6| } 133| 16| 134| 16| responseIsValid = NO; 135| 16| } 136| 395| 137| 395| if (self.acceptableStatusCodes && ![self.acceptableStatusCodes containsIndex:(NSUInteger)response.statusCode] && [response URL]) { 138| 207| NSMutableDictionary *mutableUserInfo = [@{ 139| 207| NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: %@ (%ld)", @"AFNetworking", nil), [NSHTTPURLResponse localizedStringForStatusCode:response.statusCode], (long)response.statusCode], 140| 207| NSURLErrorFailingURLErrorKey:[response URL], 141| 207| AFNetworkingOperationFailingURLResponseErrorKey: response, 142| 207| } mutableCopy]; 143| 207| 144| 207| if (data) { 145| 207| mutableUserInfo[AFNetworkingOperationFailingURLResponseDataErrorKey] = data; 146| 207| } 147| 207| 148| 207| validationError = AFErrorWithUnderlyingError([NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorBadServerResponse userInfo:mutableUserInfo], validationError); 149| 207| 150| 207| responseIsValid = NO; 151| 207| } 152| 395| } 153| 395| 154| 395| if (error && !responseIsValid) { 155| 218| *error = validationError; 156| 218| } 157| 395| 158| 395| return responseIsValid; 159| 395|} 160| | 161| |#pragma mark - AFURLResponseSerialization 162| | 163| |- (id)responseObjectForResponse:(NSURLResponse *)response 164| | data:(NSData *)data 165| | error:(NSError *__autoreleasing *)error 166| 3|{ 167| 3| [self validateResponse:(NSHTTPURLResponse *)response data:data error:error]; 168| 3| 169| 3| return data; 170| 3|} 171| | 172| |#pragma mark - NSSecureCoding 173| | 174| 2|+ (BOOL)supportsSecureCoding { 175| 2| return YES; 176| 2|} 177| | 178| 7|- (instancetype)initWithCoder:(NSCoder *)decoder { 179| 7| self = [self init]; 180| 7| if (!self) { 181| 0| return nil; 182| 0| } 183| 7| 184| 7| self.acceptableStatusCodes = [decoder decodeObjectOfClass:[NSIndexSet class] forKey:NSStringFromSelector(@selector(acceptableStatusCodes))]; 185| 7| self.acceptableContentTypes = [decoder decodeObjectOfClass:[NSSet class] forKey:NSStringFromSelector(@selector(acceptableContentTypes))]; 186| 7| 187| 7| return self; 188| 7|} 189| | 190| 8|- (void)encodeWithCoder:(NSCoder *)coder { 191| 8| [coder encodeObject:self.acceptableStatusCodes forKey:NSStringFromSelector(@selector(acceptableStatusCodes))]; 192| 8| [coder encodeObject:self.acceptableContentTypes forKey:NSStringFromSelector(@selector(acceptableContentTypes))]; 193| 8|} 194| | 195| |#pragma mark - NSCopying 196| | 197| 7|- (instancetype)copyWithZone:(NSZone *)zone { 198| 7| AFHTTPResponseSerializer *serializer = [[[self class] allocWithZone:zone] init]; 199| 7| serializer.acceptableStatusCodes = [self.acceptableStatusCodes copyWithZone:zone]; 200| 7| serializer.acceptableContentTypes = [self.acceptableContentTypes copyWithZone:zone]; 201| 7| 202| 7| return serializer; 203| 7|} 204| | 205| |@end 206| | 207| |#pragma mark - 208| | 209| |@implementation AFJSONResponseSerializer 210| | 211| 240|+ (instancetype)serializer { 212| 240| return [self serializerWithReadingOptions:(NSJSONReadingOptions)0]; 213| 240|} 214| | 215| 240|+ (instancetype)serializerWithReadingOptions:(NSJSONReadingOptions)readingOptions { 216| 240| AFJSONResponseSerializer *serializer = [[self alloc] init]; 217| 240| serializer.readingOptions = readingOptions; 218| 240| 219| 240| return serializer; 220| 240|} 221| | 222| 244|- (instancetype)init { 223| 244| self = [super init]; 224| 244| if (!self) { 225| 0| return nil; 226| 0| } 227| 244| 228| 244| self.acceptableContentTypes = [NSSet setWithObjects:@"application/json", @"text/json", @"text/javascript", nil]; 229| 244| 230| 244| return self; 231| 244|} 232| | 233| |#pragma mark - AFURLResponseSerialization 234| | 235| |- (id)responseObjectForResponse:(NSURLResponse *)response 236| | data:(NSData *)data 237| | error:(NSError *__autoreleasing *)error 238| 47|{ 239| 47| if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) { 240| 11| if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) { 241| 1| return nil; 242| 1| } 243| 46| } 244| 46| 245| 46| // Workaround for behavior of Rails to return a single space for `head :ok` (a workaround for a bug in Safari), which is not interpreted as valid input by NSJSONSerialization. 246| 46| // See https://github.com/rails/rails/issues/1742 247| 46| BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]]; 248| 46| 249| 46| if (data.length == 0 || isSpace) { 250| 12| return nil; 251| 12| } 252| 34| 253| 34| NSError *serializationError = nil; 254| 34| 255| 34| id responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError]; 256| 34| 257| 34| if (!responseObject) 258| 1| { 259| 1| if (error) { 260| 1| *error = AFErrorWithUnderlyingError(serializationError, *error); 261| 1| } 262| 1| return nil; 263| 1| } 264| 33| 265| 33| if (self.removesKeysWithNullValues) { 266| 1| return AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions); 267| 1| } 268| 32| 269| 32| return responseObject; 270| 32|} 271| | 272| |#pragma mark - NSSecureCoding 273| | 274| 2|- (instancetype)initWithCoder:(NSCoder *)decoder { 275| 2| self = [super initWithCoder:decoder]; 276| 2| if (!self) { 277| 0| return nil; 278| 0| } 279| 2| 280| 2| self.readingOptions = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(readingOptions))] unsignedIntegerValue]; 281| 2| self.removesKeysWithNullValues = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(removesKeysWithNullValues))] boolValue]; 282| 2| 283| 2| return self; 284| 2|} 285| | 286| 3|- (void)encodeWithCoder:(NSCoder *)coder { 287| 3| [super encodeWithCoder:coder]; 288| 3| 289| 3| [coder encodeObject:@(self.readingOptions) forKey:NSStringFromSelector(@selector(readingOptions))]; 290| 3| [coder encodeObject:@(self.removesKeysWithNullValues) forKey:NSStringFromSelector(@selector(removesKeysWithNullValues))]; 291| 3|} 292| | 293| |#pragma mark - NSCopying 294| | 295| 2|- (instancetype)copyWithZone:(NSZone *)zone { 296| 2| AFJSONResponseSerializer *serializer = [super copyWithZone:zone]; 297| 2| serializer.readingOptions = self.readingOptions; 298| 2| serializer.removesKeysWithNullValues = self.removesKeysWithNullValues; 299| 2| 300| 2| return serializer; 301| 2|} 302| | 303| |@end 304| | 305| |#pragma mark - 306| | 307| |@implementation AFXMLParserResponseSerializer 308| | 309| 5|+ (instancetype)serializer { 310| 5| AFXMLParserResponseSerializer *serializer = [[self alloc] init]; 311| 5| 312| 5| return serializer; 313| 5|} 314| | 315| 6|- (instancetype)init { 316| 6| self = [super init]; 317| 6| if (!self) { 318| 0| return nil; 319| 0| } 320| 6| 321| 6| self.acceptableContentTypes = [[NSSet alloc] initWithObjects:@"application/xml", @"text/xml", nil]; 322| 6| 323| 6| return self; 324| 6|} 325| | 326| |#pragma mark - AFURLResponseSerialization 327| | 328| |- (id)responseObjectForResponse:(NSHTTPURLResponse *)response 329| | data:(NSData *)data 330| | error:(NSError *__autoreleasing *)error 331| 1|{ 332| 1| if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) { 333| 0| if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) { 334| 0| return nil; 335| 0| } 336| 1| } 337| 1| 338| 1| return [[NSXMLParser alloc] initWithData:data]; 339| 1|} 340| | 341| |@end 342| | 343| |#pragma mark - 344| | 345| |#ifdef __MAC_OS_X_VERSION_MIN_REQUIRED 346| | 347| |@implementation AFXMLDocumentResponseSerializer 348| | 349| |+ (instancetype)serializer { 350| | return [self serializerWithXMLDocumentOptions:0]; 351| |} 352| | 353| |+ (instancetype)serializerWithXMLDocumentOptions:(NSUInteger)mask { 354| | AFXMLDocumentResponseSerializer *serializer = [[self alloc] init]; 355| | serializer.options = mask; 356| | 357| | return serializer; 358| |} 359| | 360| |- (instancetype)init { 361| | self = [super init]; 362| | if (!self) { 363| | return nil; 364| | } 365| | 366| | self.acceptableContentTypes = [[NSSet alloc] initWithObjects:@"application/xml", @"text/xml", nil]; 367| | 368| | return self; 369| |} 370| | 371| |#pragma mark - AFURLResponseSerialization 372| | 373| |- (id)responseObjectForResponse:(NSURLResponse *)response 374| | data:(NSData *)data 375| | error:(NSError *__autoreleasing *)error 376| |{ 377| | if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) { 378| | if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) { 379| | return nil; 380| | } 381| | } 382| | 383| | NSError *serializationError = nil; 384| | NSXMLDocument *document = [[NSXMLDocument alloc] initWithData:data options:self.options error:&serializationError]; 385| | 386| | if (!document) 387| | { 388| | if (error) { 389| | *error = AFErrorWithUnderlyingError(serializationError, *error); 390| | } 391| | return nil; 392| | } 393| | 394| | return document; 395| |} 396| | 397| |#pragma mark - NSSecureCoding 398| | 399| |- (instancetype)initWithCoder:(NSCoder *)decoder { 400| | self = [super initWithCoder:decoder]; 401| | if (!self) { 402| | return nil; 403| | } 404| | 405| | self.options = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(options))] unsignedIntegerValue]; 406| | 407| | return self; 408| |} 409| | 410| |- (void)encodeWithCoder:(NSCoder *)coder { 411| | [super encodeWithCoder:coder]; 412| | 413| | [coder encodeObject:@(self.options) forKey:NSStringFromSelector(@selector(options))]; 414| |} 415| | 416| |#pragma mark - NSCopying 417| | 418| |- (instancetype)copyWithZone:(NSZone *)zone { 419| | AFXMLDocumentResponseSerializer *serializer = [super copyWithZone:zone]; 420| | serializer.options = self.options; 421| | 422| | return serializer; 423| |} 424| | 425| |@end 426| | 427| |#endif 428| | 429| |#pragma mark - 430| | 431| |@implementation AFPropertyListResponseSerializer 432| | 433| 5|+ (instancetype)serializer { 434| 5| return [self serializerWithFormat:NSPropertyListXMLFormat_v1_0 readOptions:0]; 435| 5|} 436| | 437| |+ (instancetype)serializerWithFormat:(NSPropertyListFormat)format 438| | readOptions:(NSPropertyListReadOptions)readOptions 439| 5|{ 440| 5| AFPropertyListResponseSerializer *serializer = [[self alloc] init]; 441| 5| serializer.format = format; 442| 5| serializer.readOptions = readOptions; 443| 5| 444| 5| return serializer; 445| 5|} 446| | 447| 7|- (instancetype)init { 448| 7| self = [super init]; 449| 7| if (!self) { 450| 0| return nil; 451| 0| } 452| 7| 453| 7| self.acceptableContentTypes = [[NSSet alloc] initWithObjects:@"application/x-plist", nil]; 454| 7| 455| 7| return self; 456| 7|} 457| | 458| |#pragma mark - AFURLResponseSerialization 459| | 460| |- (id)responseObjectForResponse:(NSURLResponse *)response 461| | data:(NSData *)data 462| | error:(NSError *__autoreleasing *)error 463| 3|{ 464| 3| if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) { 465| 0| if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) { 466| 0| return nil; 467| 0| } 468| 3| } 469| 3| 470| 3| if (!data) { 471| 1| return nil; 472| 1| } 473| 2| 474| 2| NSError *serializationError = nil; 475| 2| 476| 2| id responseObject = [NSPropertyListSerialization propertyListWithData:data options:self.readOptions format:NULL error:&serializationError]; 477| 2| 478| 2| if (!responseObject) 479| 1| { 480| 1| if (error) { 481| 1| *error = AFErrorWithUnderlyingError(serializationError, *error); 482| 1| } 483| 1| return nil; 484| 1| } 485| 1| 486| 1| return responseObject; 487| 1|} 488| | 489| |#pragma mark - NSSecureCoding 490| | 491| 1|- (instancetype)initWithCoder:(NSCoder *)decoder { 492| 1| self = [super initWithCoder:decoder]; 493| 1| if (!self) { 494| 0| return nil; 495| 0| } 496| 1| 497| 1| self.format = (NSPropertyListFormat)[[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(format))] unsignedIntegerValue]; 498| 1| self.readOptions = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(readOptions))] unsignedIntegerValue]; 499| 1| 500| 1| return self; 501| 1|} 502| | 503| 1|- (void)encodeWithCoder:(NSCoder *)coder { 504| 1| [super encodeWithCoder:coder]; 505| 1| 506| 1| [coder encodeObject:@(self.format) forKey:NSStringFromSelector(@selector(format))]; 507| 1| [coder encodeObject:@(self.readOptions) forKey:NSStringFromSelector(@selector(readOptions))]; 508| 1|} 509| | 510| |#pragma mark - NSCopying 511| | 512| 1|- (instancetype)copyWithZone:(NSZone *)zone { 513| 1| AFPropertyListResponseSerializer *serializer = [super copyWithZone:zone]; 514| 1| serializer.format = self.format; 515| 1| serializer.readOptions = self.readOptions; 516| 1| 517| 1| return serializer; 518| 1|} 519| | 520| |@end 521| | 522| |#pragma mark - 523| | 524| |#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH 525| |#import 526| |#import 527| | 528| |@interface UIImage (AFNetworkingSafeImageLoading) 529| |+ (UIImage *)af_safeImageWithData:(NSData *)data; 530| |@end 531| | 532| |static NSLock* imageLock = nil; 533| | 534| |@implementation UIImage (AFNetworkingSafeImageLoading) 535| | 536| 27|+ (UIImage *)af_safeImageWithData:(NSData *)data { 537| 27| UIImage* image = nil; 538| 27| static dispatch_once_t onceToken; 539| 27| dispatch_once(&onceToken, ^{ 540| 1| imageLock = [[NSLock alloc] init]; 541| 1| }); 542| 27| 543| 27| [imageLock lock]; 544| 27| image = [UIImage imageWithData:data]; 545| 27| [imageLock unlock]; 546| 27| return image; 547| 27|} 548| | 549| |@end 550| | 551| 27|static UIImage * AFImageWithDataAtScale(NSData *data, CGFloat scale) { 552| 27| UIImage *image = [UIImage af_safeImageWithData:data]; 553| 27| if (image.images) { 554| 0| return image; 555| 0| } 556| 27| 557| 27| return [[UIImage alloc] initWithCGImage:[image CGImage] scale:scale orientation:image.imageOrientation]; 558| 27|} 559| | 560| 29|static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *response, NSData *data, CGFloat scale) { 561| 29| if (!data || [data length] == 0) { 562| 2| return nil; 563| 2| } 564| 27| 565| 27| CGImageRef imageRef = NULL; 566| 27| CGDataProviderRef dataProvider = CGDataProviderCreateWithCFData((__bridge CFDataRef)data); 567| 27| 568| 27| if ([response.MIMEType isEqualToString:@"image/png"]) { 569| 18| imageRef = CGImageCreateWithPNGDataProvider(dataProvider, NULL, true, kCGRenderingIntentDefault); 570| 18| } else if ([response.MIMEType isEqualToString:@"image/jpeg"]) { 571| 9| imageRef = CGImageCreateWithJPEGDataProvider(dataProvider, NULL, true, kCGRenderingIntentDefault); 572| 9| 573| 9| if (imageRef) { 574| 9| CGColorSpaceRef imageColorSpace = CGImageGetColorSpace(imageRef); 575| 9| CGColorSpaceModel imageColorSpaceModel = CGColorSpaceGetModel(imageColorSpace); 576| 9| 577| 9| // CGImageCreateWithJPEGDataProvider does not properly handle CMKY, so fall back to AFImageWithDataAtScale 578| 9| if (imageColorSpaceModel == kCGColorSpaceModelCMYK) { 579| 0| CGImageRelease(imageRef); 580| 0| imageRef = NULL; 581| 0| } 582| 9| } 583| 9| } 584| 27| 585| 27| CGDataProviderRelease(dataProvider); 586| 27| 587| 27| UIImage *image = AFImageWithDataAtScale(data, scale); 588| 27| if (!imageRef) { 589| 0| if (image.images || !image) { 590| 0| return image; 591| 0| } 592| 0| 593| 0| imageRef = CGImageCreateCopy([image CGImage]); 594| 0| if (!imageRef) { 595| 0| return nil; 596| 0| } 597| 27| } 598| 27| 599| 27| size_t width = CGImageGetWidth(imageRef); 600| 27| size_t height = CGImageGetHeight(imageRef); 601| 27| size_t bitsPerComponent = CGImageGetBitsPerComponent(imageRef); 602| 27| 603| 27| if (width * height > 1024 * 1024 || bitsPerComponent > 8) { 604| 0| CGImageRelease(imageRef); 605| 0| 606| 0| return image; 607| 0| } 608| 27| 609| 27| // CGImageGetBytesPerRow() calculates incorrectly in iOS 5.0, so defer to CGBitmapContextCreate 610| 27| size_t bytesPerRow = 0; 611| 27| CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 612| 27| CGColorSpaceModel colorSpaceModel = CGColorSpaceGetModel(colorSpace); 613| 27| CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(imageRef); 614| 27| 615| 27| if (colorSpaceModel == kCGColorSpaceModelRGB) { 616| 27| uint32_t alpha = (bitmapInfo & kCGBitmapAlphaInfoMask); 617| 27|#pragma clang diagnostic push 618| 27|#pragma clang diagnostic ignored "-Wassign-enum" 619| 27| if (alpha == kCGImageAlphaNone) { 620| 0| bitmapInfo &= ~kCGBitmapAlphaInfoMask; 621| 0| bitmapInfo |= kCGImageAlphaNoneSkipFirst; 622| 27| } else if (!(alpha == kCGImageAlphaNoneSkipFirst || alpha == kCGImageAlphaNoneSkipLast)) { 623| 5| bitmapInfo &= ~kCGBitmapAlphaInfoMask; 624| 5| bitmapInfo |= kCGImageAlphaPremultipliedFirst; 625| 5| } 626| 27|#pragma clang diagnostic pop 627| 27| } 628| 27| 629| 27| CGContextRef context = CGBitmapContextCreate(NULL, width, height, bitsPerComponent, bytesPerRow, colorSpace, bitmapInfo); 630| 27| 631| 27| CGColorSpaceRelease(colorSpace); 632| 27| 633| 27| if (!context) { 634| 0| CGImageRelease(imageRef); 635| 0| 636| 0| return image; 637| 0| } 638| 27| 639| 27| CGContextDrawImage(context, CGRectMake(0.0f, 0.0f, width, height), imageRef); 640| 27| CGImageRef inflatedImageRef = CGBitmapContextCreateImage(context); 641| 27| 642| 27| CGContextRelease(context); 643| 27| 644| 27| UIImage *inflatedImage = [[UIImage alloc] initWithCGImage:inflatedImageRef scale:scale orientation:image.imageOrientation]; 645| 27| 646| 27| CGImageRelease(inflatedImageRef); 647| 27| CGImageRelease(imageRef); 648| 27| 649| 27| return inflatedImage; 650| 27|} 651| |#endif 652| | 653| | 654| |@implementation AFImageResponseSerializer 655| | 656| 39|- (instancetype)init { 657| 39| self = [super init]; 658| 39| if (!self) { 659| 0| return nil; 660| 0| } 661| 39| 662| 39| self.acceptableContentTypes = [[NSSet alloc] initWithObjects:@"image/tiff", @"image/jpeg", @"image/gif", @"image/png", @"image/ico", @"image/x-icon", @"image/bmp", @"image/x-bmp", @"image/x-xbitmap", @"image/x-win-bitmap", nil]; 663| 39| 664| 39|#if TARGET_OS_IOS || TARGET_OS_TV 665| 39| self.imageScale = [[UIScreen mainScreen] scale]; 666| 39| self.automaticallyInflatesResponseImage = YES; 667| |#elif TARGET_OS_WATCH 668| | self.imageScale = [[WKInterfaceDevice currentDevice] screenScale]; 669| | self.automaticallyInflatesResponseImage = YES; 670| |#endif 671| | 672| 39| return self; 673| 39|} 674| | 675| |#pragma mark - AFURLResponseSerializer 676| | 677| |- (id)responseObjectForResponse:(NSURLResponse *)response 678| | data:(NSData *)data 679| | error:(NSError *__autoreleasing *)error 680| 30|{ 681| 30| if (![self validateResponse:(NSHTTPURLResponse *)response data:data error:error]) { 682| 3| if (!error || AFErrorOrUnderlyingErrorHasCodeInDomain(*error, NSURLErrorCannotDecodeContentData, AFURLResponseSerializationErrorDomain)) { 683| 1| return nil; 684| 1| } 685| 29| } 686| 29| 687| 29|#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH 688| 29| if (self.automaticallyInflatesResponseImage) { 689| 29| return AFInflatedImageFromResponseWithDataAtScale((NSHTTPURLResponse *)response, data, self.imageScale); 690| 29| } else { 691| 0| return AFImageWithDataAtScale(data, self.imageScale); 692| 0| } 693| |#else 694| | // Ensure that the image is set to it's correct pixel width and height 695| | NSBitmapImageRep *bitimage = [[NSBitmapImageRep alloc] initWithData:data]; 696| | NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize([bitimage pixelsWide], [bitimage pixelsHigh])]; 697| | [image addRepresentation:bitimage]; 698| | 699| | return image; 700| |#endif 701| | 702| 0| return nil; 703| 0|} 704| | 705| |#pragma mark - NSSecureCoding 706| | 707| 3|- (instancetype)initWithCoder:(NSCoder *)decoder { 708| 3| self = [super initWithCoder:decoder]; 709| 3| if (!self) { 710| 0| return nil; 711| 0| } 712| 3| 713| 3|#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH 714| 3| NSNumber *imageScale = [decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(imageScale))]; 715| 3|#if CGFLOAT_IS_DOUBLE 716| 3| self.imageScale = [imageScale doubleValue]; 717| |#else 718| | self.imageScale = [imageScale floatValue]; 719| |#endif 720| | 721| 3| self.automaticallyInflatesResponseImage = [decoder decodeBoolForKey:NSStringFromSelector(@selector(automaticallyInflatesResponseImage))]; 722| 3|#endif 723| 3| 724| 3| return self; 725| 3|} 726| | 727| 3|- (void)encodeWithCoder:(NSCoder *)coder { 728| 3| [super encodeWithCoder:coder]; 729| 3| 730| 3|#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH 731| 3| [coder encodeObject:@(self.imageScale) forKey:NSStringFromSelector(@selector(imageScale))]; 732| 3| [coder encodeBool:self.automaticallyInflatesResponseImage forKey:NSStringFromSelector(@selector(automaticallyInflatesResponseImage))]; 733| 3|#endif 734| 3|} 735| | 736| |#pragma mark - NSCopying 737| | 738| 1|- (instancetype)copyWithZone:(NSZone *)zone { 739| 1| AFImageResponseSerializer *serializer = [super copyWithZone:zone]; 740| 1| 741| 1|#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH 742| 1| serializer.imageScale = self.imageScale; 743| 1| serializer.automaticallyInflatesResponseImage = self.automaticallyInflatesResponseImage; 744| 1|#endif 745| 1| 746| 1| return serializer; 747| 1|} 748| | 749| |@end 750| | 751| |#pragma mark - 752| | 753| |@interface AFCompoundResponseSerializer () 754| |@property (readwrite, nonatomic, copy) NSArray *responseSerializers; 755| |@end 756| | 757| |@implementation AFCompoundResponseSerializer 758| | 759| 3|+ (instancetype)compoundSerializerWithResponseSerializers:(NSArray *)responseSerializers { 760| 3| AFCompoundResponseSerializer *serializer = [[self alloc] init]; 761| 3| serializer.responseSerializers = responseSerializers; 762| 3| 763| 3| return serializer; 764| 3|} 765| | 766| |#pragma mark - AFURLResponseSerialization 767| | 768| |- (id)responseObjectForResponse:(NSURLResponse *)response 769| | data:(NSData *)data 770| | error:(NSError *__autoreleasing *)error 771| 1|{ 772| 2| for (id serializer in self.responseSerializers) { 773| 2| if (![serializer isKindOfClass:[AFHTTPResponseSerializer class]]) { 774| 0| continue; 775| 0| } 776| 2| 777| 2| NSError *serializerError = nil; 778| 2| id responseObject = [serializer responseObjectForResponse:response data:data error:&serializerError]; 779| 2| if (responseObject) { 780| 1| if (error) { 781| 1| *error = AFErrorWithUnderlyingError(serializerError, *error); 782| 1| } 783| 1| 784| 1| return responseObject; 785| 1| } 786| 2| } 787| 1| 788| 1| return [super responseObjectForResponse:response data:data error:error]; 789| 1|} 790| | 791| |#pragma mark - NSSecureCoding 792| | 793| 1|- (instancetype)initWithCoder:(NSCoder *)decoder { 794| 1| self = [super initWithCoder:decoder]; 795| 1| if (!self) { 796| 0| return nil; 797| 0| } 798| 1| 799| 1| self.responseSerializers = [decoder decodeObjectOfClass:[NSArray class] forKey:NSStringFromSelector(@selector(responseSerializers))]; 800| 1| 801| 1| return self; 802| 1|} 803| | 804| 1|- (void)encodeWithCoder:(NSCoder *)coder { 805| 1| [super encodeWithCoder:coder]; 806| 1| 807| 1| [coder encodeObject:self.responseSerializers forKey:NSStringFromSelector(@selector(responseSerializers))]; 808| 1|} 809| | 810| |#pragma mark - NSCopying 811| | 812| 1|- (instancetype)copyWithZone:(NSZone *)zone { 813| 1| AFCompoundResponseSerializer *serializer = [super copyWithZone:zone]; 814| 1| serializer.responseSerializers = self.responseSerializers; 815| 1| 816| 1| return serializer; 817| 1|} 818| | 819| |@end /Users/travis/build/AFNetworking/AFNetworking/AFNetworking/AFURLSessionManager.m: 1| |// AFURLSessionManager.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "AFURLSessionManager.h" 23| |#import 24| | 25| |#ifndef NSFoundationVersionNumber_iOS_8_0 26| |#define NSFoundationVersionNumber_With_Fixed_5871104061079552_bug 1140.11 27| |#else 28| 195|#define NSFoundationVersionNumber_With_Fixed_5871104061079552_bug NSFoundationVersionNumber_iOS_8_0 29| |#endif 30| | 31| 0|static dispatch_queue_t url_session_manager_creation_queue() { 32| 0| static dispatch_queue_t af_url_session_manager_creation_queue; 33| 0| static dispatch_once_t onceToken; 34| 0| dispatch_once(&onceToken, ^{ 35| 0| af_url_session_manager_creation_queue = dispatch_queue_create("com.alamofire.networking.session.manager.creation", DISPATCH_QUEUE_SERIAL); 36| 0| }); 37| 0| 38| 0| return af_url_session_manager_creation_queue; 39| 0|} 40| | 41| 195|static void url_session_manager_create_task_safely(dispatch_block_t _Nonnull block) { 42| 195| if (block != NULL) { 43| 195| if (NSFoundationVersionNumber < NSFoundationVersionNumber_With_Fixed_5871104061079552_bug) { 44| 0| // Fix of bug 45| 0| // Open Radar:http://openradar.appspot.com/radar?id=5871104061079552 (status: Fixed in iOS8) 46| 0| // Issue about:https://github.com/AFNetworking/AFNetworking/issues/2093 47| 0| dispatch_sync(url_session_manager_creation_queue(), block); 48| 195| } else { 49| 195| block(); 50| 195| } 51| 195| } 52| 195|} 53| | 54| 73|static dispatch_queue_t url_session_manager_processing_queue() { 55| 73| static dispatch_queue_t af_url_session_manager_processing_queue; 56| 73| static dispatch_once_t onceToken; 57| 73| dispatch_once(&onceToken, ^{ 58| 1| af_url_session_manager_processing_queue = dispatch_queue_create("com.alamofire.networking.session.manager.processing", DISPATCH_QUEUE_CONCURRENT); 59| 1| }); 60| 73| 61| 73| return af_url_session_manager_processing_queue; 62| 73|} 63| | 64| 194|static dispatch_group_t url_session_manager_completion_group() { 65| 194| static dispatch_group_t af_url_session_manager_completion_group; 66| 194| static dispatch_once_t onceToken; 67| 194| dispatch_once(&onceToken, ^{ 68| 1| af_url_session_manager_completion_group = dispatch_group_create(); 69| 1| }); 70| 194| 71| 194| return af_url_session_manager_completion_group; 72| 194|} 73| | 74| |NSString * const AFNetworkingTaskDidResumeNotification = @"com.alamofire.networking.task.resume"; 75| |NSString * const AFNetworkingTaskDidCompleteNotification = @"com.alamofire.networking.task.complete"; 76| |NSString * const AFNetworkingTaskDidSuspendNotification = @"com.alamofire.networking.task.suspend"; 77| |NSString * const AFURLSessionDidInvalidateNotification = @"com.alamofire.networking.session.invalidate"; 78| |NSString * const AFURLSessionDownloadTaskDidFailToMoveFileNotification = @"com.alamofire.networking.session.download.file-manager-error"; 79| | 80| |NSString * const AFNetworkingTaskDidCompleteSerializedResponseKey = @"com.alamofire.networking.task.complete.serializedresponse"; 81| |NSString * const AFNetworkingTaskDidCompleteResponseSerializerKey = @"com.alamofire.networking.task.complete.responseserializer"; 82| |NSString * const AFNetworkingTaskDidCompleteResponseDataKey = @"com.alamofire.networking.complete.finish.responsedata"; 83| |NSString * const AFNetworkingTaskDidCompleteErrorKey = @"com.alamofire.networking.task.complete.error"; 84| |NSString * const AFNetworkingTaskDidCompleteAssetPathKey = @"com.alamofire.networking.task.complete.assetpath"; 85| |NSString * const AFNetworkingTaskDidCompleteSessionTaskMetrics = @"com.alamofire.networking.complete.sessiontaskmetrics"; 86| | 87| |static NSString * const AFURLSessionManagerLockName = @"com.alamofire.networking.session.manager.lock"; 88| | 89| |static NSUInteger const AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask = 3; 90| | 91| |typedef void (^AFURLSessionDidBecomeInvalidBlock)(NSURLSession *session, NSError *error); 92| |typedef NSURLSessionAuthChallengeDisposition (^AFURLSessionDidReceiveAuthenticationChallengeBlock)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential); 93| | 94| |typedef NSURLRequest * (^AFURLSessionTaskWillPerformHTTPRedirectionBlock)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request); 95| |typedef NSURLSessionAuthChallengeDisposition (^AFURLSessionTaskDidReceiveAuthenticationChallengeBlock)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential); 96| |typedef void (^AFURLSessionDidFinishEventsForBackgroundURLSessionBlock)(NSURLSession *session); 97| | 98| |typedef NSInputStream * (^AFURLSessionTaskNeedNewBodyStreamBlock)(NSURLSession *session, NSURLSessionTask *task); 99| |typedef void (^AFURLSessionTaskDidSendBodyDataBlock)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend); 100| |typedef void (^AFURLSessionTaskDidCompleteBlock)(NSURLSession *session, NSURLSessionTask *task, NSError *error); 101| |#if AF_CAN_INCLUDE_SESSION_TASK_METRICS 102| |typedef void (^AFURLSessionTaskDidFinishCollectingMetricsBlock)(NSURLSession *session, NSURLSessionTask *task, NSURLSessionTaskMetrics * metrics); 103| |#endif 104| | 105| |typedef NSURLSessionResponseDisposition (^AFURLSessionDataTaskDidReceiveResponseBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response); 106| |typedef void (^AFURLSessionDataTaskDidBecomeDownloadTaskBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask); 107| |typedef void (^AFURLSessionDataTaskDidReceiveDataBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data); 108| |typedef NSCachedURLResponse * (^AFURLSessionDataTaskWillCacheResponseBlock)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse); 109| | 110| |typedef NSURL * (^AFURLSessionDownloadTaskDidFinishDownloadingBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location); 111| |typedef void (^AFURLSessionDownloadTaskDidWriteDataBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite); 112| |typedef void (^AFURLSessionDownloadTaskDidResumeBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes); 113| |typedef void (^AFURLSessionTaskProgressBlock)(NSProgress *); 114| | 115| |typedef void (^AFURLSessionTaskCompletionHandler)(NSURLResponse *response, id responseObject, NSError *error); 116| | 117| | 118| |#pragma mark - 119| | 120| |@interface AFURLSessionManagerTaskDelegate : NSObject 121| |- (instancetype)initWithTask:(NSURLSessionTask *)task; 122| |@property (nonatomic, weak) AFURLSessionManager *manager; 123| |@property (nonatomic, strong) NSMutableData *mutableData; 124| |@property (nonatomic, strong) NSProgress *uploadProgress; 125| |@property (nonatomic, strong) NSProgress *downloadProgress; 126| |@property (nonatomic, copy) NSURL *downloadFileURL; 127| |#if AF_CAN_INCLUDE_SESSION_TASK_METRICS 128| |@property (nonatomic, strong) NSURLSessionTaskMetrics *sessionTaskMetrics; 129| |#endif 130| |@property (nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading; 131| |@property (nonatomic, copy) AFURLSessionTaskProgressBlock uploadProgressBlock; 132| |@property (nonatomic, copy) AFURLSessionTaskProgressBlock downloadProgressBlock; 133| |@property (nonatomic, copy) AFURLSessionTaskCompletionHandler completionHandler; 134| |@end 135| | 136| |@implementation AFURLSessionManagerTaskDelegate 137| | 138| 195|- (instancetype)initWithTask:(NSURLSessionTask *)task { 139| 195| self = [super init]; 140| 195| if (!self) { 141| 0| return nil; 142| 0| } 143| 195| 144| 195| _mutableData = [NSMutableData data]; 145| 195| _uploadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil]; 146| 195| _downloadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil]; 147| 195| 148| 195| __weak __typeof__(task) weakTask = task; 149| 195| for (NSProgress *progress in @[ _uploadProgress, _downloadProgress ]) 150| 390| { 151| 390| progress.totalUnitCount = NSURLSessionTransferSizeUnknown; 152| 390| progress.cancellable = YES; 153| 390| progress.cancellationHandler = ^{ 154| 0| [weakTask cancel]; 155| 0| }; 156| 390| progress.pausable = YES; 157| 390| progress.pausingHandler = ^{ 158| 0| [weakTask suspend]; 159| 0| }; 160| 390|#if AF_CAN_USE_AT_AVAILABLE 161| 390| if (@available(iOS 9, macOS 10.11, *)) 162| |#else 163| | if ([progress respondsToSelector:@selector(setResumingHandler:)]) 164| |#endif 165| 390| { 166| 390| progress.resumingHandler = ^{ 167| 0| [weakTask resume]; 168| 0| }; 169| 390| } 170| 390| 171| 390| [progress addObserver:self 172| 390| forKeyPath:NSStringFromSelector(@selector(fractionCompleted)) 173| 390| options:NSKeyValueObservingOptionNew 174| 390| context:NULL]; 175| 390| } 176| 195| return self; 177| 195|} 178| | 179| 195|- (void)dealloc { 180| 195| [self.downloadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))]; 181| 195| [self.uploadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))]; 182| 195|} 183| | 184| |#pragma mark - NSProgress Tracking 185| | 186| 84|- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context { 187| 84| if ([object isEqual:self.downloadProgress]) { 188| 68| if (self.downloadProgressBlock) { 189| 8| self.downloadProgressBlock(object); 190| 8| } 191| 68| } 192| 16| else if ([object isEqual:self.uploadProgress]) { 193| 16| if (self.uploadProgressBlock) { 194| 5| self.uploadProgressBlock(object); 195| 5| } 196| 16| } 197| 84|} 198| | 199| |#pragma mark - NSURLSessionTaskDelegate 200| | 201| |- (void)URLSession:(__unused NSURLSession *)session 202| | task:(NSURLSessionTask *)task 203| |didCompleteWithError:(NSError *)error 204| 194|{ 205| 194| __strong AFURLSessionManager *manager = self.manager; 206| 194| 207| 194| __block id responseObject = nil; 208| 194| 209| 194| __block NSMutableDictionary *userInfo = [NSMutableDictionary dictionary]; 210| 194| userInfo[AFNetworkingTaskDidCompleteResponseSerializerKey] = manager.responseSerializer; 211| 194| 212| 194| //Performance Improvement from #2672 213| 194| NSData *data = nil; 214| 194| if (self.mutableData) { 215| 194| data = [self.mutableData copy]; 216| 194| //We no longer need the reference, so nil it out to gain back some memory. 217| 194| self.mutableData = nil; 218| 194| } 219| 194| 220| 194|#if AF_CAN_USE_AT_AVAILABLE && AF_CAN_INCLUDE_SESSION_TASK_METRICS 221| 194| if (@available(iOS 10, macOS 10.12, watchOS 3, tvOS 10, *)) { 222| 194| if (self.sessionTaskMetrics) { 223| 87| userInfo[AFNetworkingTaskDidCompleteSessionTaskMetrics] = self.sessionTaskMetrics; 224| 87| } 225| 194| } 226| 194|#endif 227| 194| 228| 194| if (self.downloadFileURL) { 229| 2| userInfo[AFNetworkingTaskDidCompleteAssetPathKey] = self.downloadFileURL; 230| 192| } else if (data) { 231| 192| userInfo[AFNetworkingTaskDidCompleteResponseDataKey] = data; 232| 192| } 233| 194| 234| 194| if (error) { 235| 121| userInfo[AFNetworkingTaskDidCompleteErrorKey] = error; 236| 121| 237| 121| dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{ 238| 121| if (self.completionHandler) { 239| 9| self.completionHandler(task.response, responseObject, error); 240| 9| } 241| 121| 242| 121| dispatch_async(dispatch_get_main_queue(), ^{ 243| 121| [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo]; 244| 121| }); 245| 121| }); 246| 121| } else { 247| 73| dispatch_async(url_session_manager_processing_queue(), ^{ 248| 73| NSError *serializationError = nil; 249| 73| responseObject = [manager.responseSerializer responseObjectForResponse:task.response data:data error:&serializationError]; 250| 73| 251| 73| if (self.downloadFileURL) { 252| 2| responseObject = self.downloadFileURL; 253| 2| } 254| 73| 255| 73| if (responseObject) { 256| 62| userInfo[AFNetworkingTaskDidCompleteSerializedResponseKey] = responseObject; 257| 62| } 258| 73| 259| 73| if (serializationError) { 260| 8| userInfo[AFNetworkingTaskDidCompleteErrorKey] = serializationError; 261| 8| } 262| 73| 263| 73| dispatch_group_async(manager.completionGroup ?: url_session_manager_completion_group(), manager.completionQueue ?: dispatch_get_main_queue(), ^{ 264| 73| if (self.completionHandler) { 265| 71| self.completionHandler(task.response, responseObject, serializationError); 266| 71| } 267| 73| 268| 73| dispatch_async(dispatch_get_main_queue(), ^{ 269| 73| [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidCompleteNotification object:task userInfo:userInfo]; 270| 73| }); 271| 73| }); 272| 73| }); 273| 73| } 274| 194|} 275| | 276| |#if AF_CAN_INCLUDE_SESSION_TASK_METRICS 277| |- (void)URLSession:(NSURLSession *)session 278| | task:(NSURLSessionTask *)task 279| 87|didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics { 280| 87| self.sessionTaskMetrics = metrics; 281| 87|} 282| |#endif 283| | 284| |#pragma mark - NSURLSessionDataDelegate 285| | 286| |- (void)URLSession:(__unused NSURLSession *)session 287| | dataTask:(__unused NSURLSessionDataTask *)dataTask 288| | didReceiveData:(NSData *)data 289| 71|{ 290| 71| self.downloadProgress.totalUnitCount = dataTask.countOfBytesExpectedToReceive; 291| 71| self.downloadProgress.completedUnitCount = dataTask.countOfBytesReceived; 292| 71| 293| 71| [self.mutableData appendData:data]; 294| 71|} 295| | 296| |- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task 297| | didSendBodyData:(int64_t)bytesSent 298| | totalBytesSent:(int64_t)totalBytesSent 299| 16|totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{ 300| 16| 301| 16| self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend; 302| 16| self.uploadProgress.completedUnitCount = task.countOfBytesSent; 303| 16|} 304| | 305| |#pragma mark - NSURLSessionDownloadDelegate 306| | 307| |- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask 308| | didWriteData:(int64_t)bytesWritten 309| | totalBytesWritten:(int64_t)totalBytesWritten 310| 9|totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{ 311| 9| 312| 9| self.downloadProgress.totalUnitCount = totalBytesExpectedToWrite; 313| 9| self.downloadProgress.completedUnitCount = totalBytesWritten; 314| 9|} 315| | 316| |- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask 317| | didResumeAtOffset:(int64_t)fileOffset 318| 0|expectedTotalBytes:(int64_t)expectedTotalBytes{ 319| 0| 320| 0| self.downloadProgress.totalUnitCount = expectedTotalBytes; 321| 0| self.downloadProgress.completedUnitCount = fileOffset; 322| 0|} 323| | 324| |- (void)URLSession:(NSURLSession *)session 325| | downloadTask:(NSURLSessionDownloadTask *)downloadTask 326| |didFinishDownloadingToURL:(NSURL *)location 327| 3|{ 328| 3| self.downloadFileURL = nil; 329| 3| 330| 3| if (self.downloadTaskDidFinishDownloading) { 331| 1| self.downloadFileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location); 332| 1| if (self.downloadFileURL) { 333| 1| NSError *fileManagerError = nil; 334| 1| 335| 1| if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:self.downloadFileURL error:&fileManagerError]) { 336| 0| [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:fileManagerError.userInfo]; 337| 0| } 338| 1| } 339| 1| } 340| 3|} 341| | 342| |@end 343| | 344| |#pragma mark - 345| | 346| |/** 347| | * A workaround for issues related to key-value observing the `state` of an `NSURLSessionTask`. 348| | * 349| | * See: 350| | * - https://github.com/AFNetworking/AFNetworking/issues/1477 351| | * - https://github.com/AFNetworking/AFNetworking/issues/2638 352| | * - https://github.com/AFNetworking/AFNetworking/pull/2702 353| | */ 354| | 355| 4|static inline void af_swizzleSelector(Class theClass, SEL originalSelector, SEL swizzledSelector) { 356| 4| Method originalMethod = class_getInstanceMethod(theClass, originalSelector); 357| 4| Method swizzledMethod = class_getInstanceMethod(theClass, swizzledSelector); 358| 4| method_exchangeImplementations(originalMethod, swizzledMethod); 359| 4|} 360| | 361| 4|static inline BOOL af_addMethod(Class theClass, SEL selector, Method method) { 362| 4| return class_addMethod(theClass, selector, method_getImplementation(method), method_getTypeEncoding(method)); 363| 4|} 364| | 365| |static NSString * const AFNSURLSessionTaskDidResumeNotification = @"com.alamofire.networking.nsurlsessiontask.resume"; 366| |static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofire.networking.nsurlsessiontask.suspend"; 367| | 368| |@interface _AFURLSessionTaskSwizzling : NSObject 369| | 370| |@end 371| | 372| |@implementation _AFURLSessionTaskSwizzling 373| | 374| 1|+ (void)load { 375| 1| /** 376| 1| WARNING: Trouble Ahead 377| 1| https://github.com/AFNetworking/AFNetworking/pull/2702 378| 1| */ 379| 1| 380| 1| if (NSClassFromString(@"NSURLSessionTask")) { 381| 1| /** 382| 1| iOS 7 and iOS 8 differ in NSURLSessionTask implementation, which makes the next bit of code a bit tricky. 383| 1| Many Unit Tests have been built to validate as much of this behavior has possible. 384| 1| Here is what we know: 385| 1| - NSURLSessionTasks are implemented with class clusters, meaning the class you request from the API isn't actually the type of class you will get back. 386| 1| - Simply referencing `[NSURLSessionTask class]` will not work. You need to ask an `NSURLSession` to actually create an object, and grab the class from there. 387| 1| - On iOS 7, `localDataTask` is a `__NSCFLocalDataTask`, which inherits from `__NSCFLocalSessionTask`, which inherits from `__NSCFURLSessionTask`. 388| 1| - On iOS 8, `localDataTask` is a `__NSCFLocalDataTask`, which inherits from `__NSCFLocalSessionTask`, which inherits from `NSURLSessionTask`. 389| 1| - On iOS 7, `__NSCFLocalSessionTask` and `__NSCFURLSessionTask` are the only two classes that have their own implementations of `resume` and `suspend`, and `__NSCFLocalSessionTask` DOES NOT CALL SUPER. This means both classes need to be swizzled. 390| 1| - On iOS 8, `NSURLSessionTask` is the only class that implements `resume` and `suspend`. This means this is the only class that needs to be swizzled. 391| 1| - Because `NSURLSessionTask` is not involved in the class hierarchy for every version of iOS, its easier to add the swizzled methods to a dummy class and manage them there. 392| 1| 393| 1| Some Assumptions: 394| 1| - No implementations of `resume` or `suspend` call super. If this were to change in a future version of iOS, we'd need to handle it. 395| 1| - No background task classes override `resume` or `suspend` 396| 1| 397| 1| The current solution: 398| 1| 1) Grab an instance of `__NSCFLocalDataTask` by asking an instance of `NSURLSession` for a data task. 399| 1| 2) Grab a pointer to the original implementation of `af_resume` 400| 1| 3) Check to see if the current class has an implementation of resume. If so, continue to step 4. 401| 1| 4) Grab the super class of the current class. 402| 1| 5) Grab a pointer for the current class to the current implementation of `resume`. 403| 1| 6) Grab a pointer for the super class to the current implementation of `resume`. 404| 1| 7) If the current class implementation of `resume` is not equal to the super class implementation of `resume` AND the current implementation of `resume` is not equal to the original implementation of `af_resume`, THEN swizzle the methods 405| 1| 8) Set the current class to the super class, and repeat steps 3-8 406| 1| */ 407| 1| NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration]; 408| 1| NSURLSession *session = [NSURLSession sessionWithConfiguration:configuration]; 409| 1|#pragma GCC diagnostic push 410| 1|#pragma GCC diagnostic ignored "-Wnonnull" 411| 1| NSURLSessionDataTask *localDataTask = [session dataTaskWithURL:nil]; 412| 1|#pragma clang diagnostic pop 413| 1| IMP originalAFResumeIMP = method_getImplementation(class_getInstanceMethod([self class], @selector(af_resume))); 414| 1| Class currentClass = [localDataTask class]; 415| 1| 416| 5| while (class_getInstanceMethod(currentClass, @selector(resume))) { 417| 4| Class superClass = [currentClass superclass]; 418| 4| IMP classResumeIMP = method_getImplementation(class_getInstanceMethod(currentClass, @selector(resume))); 419| 4| IMP superclassResumeIMP = method_getImplementation(class_getInstanceMethod(superClass, @selector(resume))); 420| 4| if (classResumeIMP != superclassResumeIMP && 421| 4| originalAFResumeIMP != classResumeIMP) { 422| 2| [self swizzleResumeAndSuspendMethodForClass:currentClass]; 423| 2| } 424| 4| currentClass = [currentClass superclass]; 425| 4| } 426| 1| 427| 1| [localDataTask cancel]; 428| 1| [session finishTasksAndInvalidate]; 429| 1| } 430| 1|} 431| | 432| 2|+ (void)swizzleResumeAndSuspendMethodForClass:(Class)theClass { 433| 2| Method afResumeMethod = class_getInstanceMethod(self, @selector(af_resume)); 434| 2| Method afSuspendMethod = class_getInstanceMethod(self, @selector(af_suspend)); 435| 2| 436| 2| if (af_addMethod(theClass, @selector(af_resume), afResumeMethod)) { 437| 2| af_swizzleSelector(theClass, @selector(resume), @selector(af_resume)); 438| 2| } 439| 2| 440| 2| if (af_addMethod(theClass, @selector(af_suspend), afSuspendMethod)) { 441| 2| af_swizzleSelector(theClass, @selector(suspend), @selector(af_suspend)); 442| 2| } 443| 2|} 444| | 445| 0|- (NSURLSessionTaskState)state { 446| 0| NSAssert(NO, @"State method should never be called in the actual dummy class"); 447| 0| return NSURLSessionTaskStateCanceling; 448| 0|} 449| | 450| 99|- (void)af_resume { 451| 99| NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state"); 452| 99| NSURLSessionTaskState state = [self state]; 453| 99| [self af_resume]; 454| 99| 455| 99| if (state != NSURLSessionTaskStateRunning) { 456| 99| [[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidResumeNotification object:self]; 457| 99| } 458| 99|} 459| | 460| 8|- (void)af_suspend { 461| 8| NSAssert([self respondsToSelector:@selector(state)], @"Does not respond to state"); 462| 8| NSURLSessionTaskState state = [self state]; 463| 8| [self af_suspend]; 464| 8| 465| 8| if (state != NSURLSessionTaskStateSuspended) { 466| 8| [[NSNotificationCenter defaultCenter] postNotificationName:AFNSURLSessionTaskDidSuspendNotification object:self]; 467| 8| } 468| 8|} 469| |@end 470| | 471| |#pragma mark - 472| | 473| |@interface AFURLSessionManager () 474| |@property (readwrite, nonatomic, strong) NSURLSessionConfiguration *sessionConfiguration; 475| |@property (readwrite, nonatomic, strong) NSOperationQueue *operationQueue; 476| |@property (readwrite, nonatomic, strong) NSURLSession *session; 477| |@property (readwrite, nonatomic, strong) NSMutableDictionary *mutableTaskDelegatesKeyedByTaskIdentifier; 478| |@property (readonly, nonatomic, copy) NSString *taskDescriptionForSessionTasks; 479| |@property (readwrite, nonatomic, strong) NSLock *lock; 480| |@property (readwrite, nonatomic, copy) AFURLSessionDidBecomeInvalidBlock sessionDidBecomeInvalid; 481| |@property (readwrite, nonatomic, copy) AFURLSessionDidReceiveAuthenticationChallengeBlock sessionDidReceiveAuthenticationChallenge; 482| |@property (readwrite, nonatomic, copy) AFURLSessionDidFinishEventsForBackgroundURLSessionBlock didFinishEventsForBackgroundURLSession AF_API_UNAVAILABLE(macos); 483| |@property (readwrite, nonatomic, copy) AFURLSessionTaskWillPerformHTTPRedirectionBlock taskWillPerformHTTPRedirection; 484| |@property (readwrite, nonatomic, copy) AFURLSessionTaskDidReceiveAuthenticationChallengeBlock taskDidReceiveAuthenticationChallenge; 485| |@property (readwrite, nonatomic, copy) AFURLSessionTaskNeedNewBodyStreamBlock taskNeedNewBodyStream; 486| |@property (readwrite, nonatomic, copy) AFURLSessionTaskDidSendBodyDataBlock taskDidSendBodyData; 487| |@property (readwrite, nonatomic, copy) AFURLSessionTaskDidCompleteBlock taskDidComplete; 488| |#if AF_CAN_INCLUDE_SESSION_TASK_METRICS 489| |@property (readwrite, nonatomic, copy) AFURLSessionTaskDidFinishCollectingMetricsBlock taskDidFinishCollectingMetrics; 490| |#endif 491| |@property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidReceiveResponseBlock dataTaskDidReceiveResponse; 492| |@property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidBecomeDownloadTaskBlock dataTaskDidBecomeDownloadTask; 493| |@property (readwrite, nonatomic, copy) AFURLSessionDataTaskDidReceiveDataBlock dataTaskDidReceiveData; 494| |@property (readwrite, nonatomic, copy) AFURLSessionDataTaskWillCacheResponseBlock dataTaskWillCacheResponse; 495| |@property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading; 496| |@property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidWriteDataBlock downloadTaskDidWriteData; 497| |@property (readwrite, nonatomic, copy) AFURLSessionDownloadTaskDidResumeBlock downloadTaskDidResume; 498| |@end 499| | 500| |@implementation AFURLSessionManager 501| | 502| 31|- (instancetype)init { 503| 31| return [self initWithSessionConfiguration:nil]; 504| 31|} 505| | 506| 132|- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration { 507| 132| self = [super init]; 508| 132| if (!self) { 509| 0| return nil; 510| 0| } 511| 132| 512| 132| if (!configuration) { 513| 96| configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; 514| 96| } 515| 132| 516| 132| self.sessionConfiguration = configuration; 517| 132| 518| 132| self.operationQueue = [[NSOperationQueue alloc] init]; 519| 132| self.operationQueue.maxConcurrentOperationCount = 1; 520| 132| 521| 132| self.responseSerializer = [AFJSONResponseSerializer serializer]; 522| 132| 523| 132| self.securityPolicy = [AFSecurityPolicy defaultPolicy]; 524| 132| 525| 132|#if !TARGET_OS_WATCH 526| 132| self.reachabilityManager = [AFNetworkReachabilityManager sharedManager]; 527| 132|#endif 528| 132| 529| 132| self.mutableTaskDelegatesKeyedByTaskIdentifier = [[NSMutableDictionary alloc] init]; 530| 132| 531| 132| self.lock = [[NSLock alloc] init]; 532| 132| self.lock.name = AFURLSessionManagerLockName; 533| 132| 534| 132| __weak typeof(self) weakSelf = self; 535| 132| [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) { 536| 132| 537| 132| __strong typeof(weakSelf) strongSelf = weakSelf; 538| 132| for (NSURLSessionDataTask *task in dataTasks) { 539| 0| [strongSelf addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil]; 540| 0| } 541| 132| 542| 132| for (NSURLSessionUploadTask *uploadTask in uploadTasks) { 543| 0| [strongSelf addDelegateForUploadTask:uploadTask progress:nil completionHandler:nil]; 544| 0| } 545| 132| 546| 132| for (NSURLSessionDownloadTask *downloadTask in downloadTasks) { 547| 0| [strongSelf addDelegateForDownloadTask:downloadTask progress:nil destination:nil completionHandler:nil]; 548| 0| } 549| 132| }]; 550| 132| 551| 132| return self; 552| 132|} 553| | 554| 108|- (void)dealloc { 555| 108| [[NSNotificationCenter defaultCenter] removeObserver:self]; 556| 108|} 557| | 558| |#pragma mark - 559| | 560| 521|- (NSURLSession *)session { 561| 521| 562| 521| @synchronized (self) { 563| 521| if (!_session) { 564| 133| _session = [NSURLSession sessionWithConfiguration:self.sessionConfiguration delegate:self delegateQueue:self.operationQueue]; 565| 133| } 566| 521| } 567| 521| return _session; 568| 521|} 569| | 570| |#pragma mark - 571| | 572| | 573| 302|- (NSString *)taskDescriptionForSessionTasks { 574| 302| return [NSString stringWithFormat:@"%p", self]; 575| 302|} 576| | 577| 99|- (void)taskDidResume:(NSNotification *)notification { 578| 99| NSURLSessionTask *task = notification.object; 579| 99| if ([task respondsToSelector:@selector(taskDescription)]) { 580| 99| if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) { 581| 99| dispatch_async(dispatch_get_main_queue(), ^{ 582| 99| [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidResumeNotification object:task]; 583| 99| }); 584| 99| } 585| 99| } 586| 99|} 587| | 588| 8|- (void)taskDidSuspend:(NSNotification *)notification { 589| 8| NSURLSessionTask *task = notification.object; 590| 8| if ([task respondsToSelector:@selector(taskDescription)]) { 591| 8| if ([task.taskDescription isEqualToString:self.taskDescriptionForSessionTasks]) { 592| 8| dispatch_async(dispatch_get_main_queue(), ^{ 593| 8| [[NSNotificationCenter defaultCenter] postNotificationName:AFNetworkingTaskDidSuspendNotification object:task]; 594| 8| }); 595| 8| } 596| 8| } 597| 8|} 598| | 599| |#pragma mark - 600| | 601| 384|- (AFURLSessionManagerTaskDelegate *)delegateForTask:(NSURLSessionTask *)task { 602| 384| NSParameterAssert(task); 603| 384| 604| 384| AFURLSessionManagerTaskDelegate *delegate = nil; 605| 384| [self.lock lock]; 606| 384| delegate = self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)]; 607| 384| [self.lock unlock]; 608| 384| 609| 384| return delegate; 610| 384|} 611| | 612| |- (void)setDelegate:(AFURLSessionManagerTaskDelegate *)delegate 613| | forTask:(NSURLSessionTask *)task 614| 195|{ 615| 195| NSParameterAssert(task); 616| 195| NSParameterAssert(delegate); 617| 195| 618| 195| [self.lock lock]; 619| 195| self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate; 620| 195| [self addNotificationObserverForTask:task]; 621| 195| [self.lock unlock]; 622| 195|} 623| | 624| |- (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask 625| | uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock 626| | downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock 627| | completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler 628| 178|{ 629| 178| AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask]; 630| 178| delegate.manager = self; 631| 178| delegate.completionHandler = completionHandler; 632| 178| 633| 178| dataTask.taskDescription = self.taskDescriptionForSessionTasks; 634| 178| [self setDelegate:delegate forTask:dataTask]; 635| 178| 636| 178| delegate.uploadProgressBlock = uploadProgressBlock; 637| 178| delegate.downloadProgressBlock = downloadProgressBlock; 638| 178|} 639| | 640| |- (void)addDelegateForUploadTask:(NSURLSessionUploadTask *)uploadTask 641| | progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock 642| | completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler 643| 10|{ 644| 10| AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:uploadTask]; 645| 10| delegate.manager = self; 646| 10| delegate.completionHandler = completionHandler; 647| 10| 648| 10| uploadTask.taskDescription = self.taskDescriptionForSessionTasks; 649| 10| 650| 10| [self setDelegate:delegate forTask:uploadTask]; 651| 10| 652| 10| delegate.uploadProgressBlock = uploadProgressBlock; 653| 10|} 654| | 655| |- (void)addDelegateForDownloadTask:(NSURLSessionDownloadTask *)downloadTask 656| | progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock 657| | destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination 658| | completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler 659| 7|{ 660| 7| AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:downloadTask]; 661| 7| delegate.manager = self; 662| 7| delegate.completionHandler = completionHandler; 663| 7| 664| 7| if (destination) { 665| 1| delegate.downloadTaskDidFinishDownloading = ^NSURL * (NSURLSession * __unused session, NSURLSessionDownloadTask *task, NSURL *location) { 666| 1| return destination(location, task.response); 667| 1| }; 668| 1| } 669| 7| 670| 7| downloadTask.taskDescription = self.taskDescriptionForSessionTasks; 671| 7| 672| 7| [self setDelegate:delegate forTask:downloadTask]; 673| 7| 674| 7| delegate.downloadProgressBlock = downloadProgressBlock; 675| 7|} 676| | 677| 194|- (void)removeDelegateForTask:(NSURLSessionTask *)task { 678| 194| NSParameterAssert(task); 679| 194| 680| 194| [self.lock lock]; 681| 194| [self removeNotificationObserverForTask:task]; 682| 194| [self.mutableTaskDelegatesKeyedByTaskIdentifier removeObjectForKey:@(task.taskIdentifier)]; 683| 194| [self.lock unlock]; 684| 194|} 685| | 686| |#pragma mark - 687| | 688| 0|- (NSArray *)tasksForKeyPath:(NSString *)keyPath { 689| 0| __block NSArray *tasks = nil; 690| 0| dispatch_semaphore_t semaphore = dispatch_semaphore_create(0); 691| 0| [self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) { 692| 0| if ([keyPath isEqualToString:NSStringFromSelector(@selector(dataTasks))]) { 693| 0| tasks = dataTasks; 694| 0| } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(uploadTasks))]) { 695| 0| tasks = uploadTasks; 696| 0| } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(downloadTasks))]) { 697| 0| tasks = downloadTasks; 698| 0| } else if ([keyPath isEqualToString:NSStringFromSelector(@selector(tasks))]) { 699| 0| tasks = [@[dataTasks, uploadTasks, downloadTasks] valueForKeyPath:@"@unionOfArrays.self"]; 700| 0| } 701| 0| 702| 0| dispatch_semaphore_signal(semaphore); 703| 0| }]; 704| 0| 705| 0| dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER); 706| 0| 707| 0| return tasks; 708| 0|} 709| | 710| 0|- (NSArray *)tasks { 711| 0| return [self tasksForKeyPath:NSStringFromSelector(_cmd)]; 712| 0|} 713| | 714| 0|- (NSArray *)dataTasks { 715| 0| return [self tasksForKeyPath:NSStringFromSelector(_cmd)]; 716| 0|} 717| | 718| 0|- (NSArray *)uploadTasks { 719| 0| return [self tasksForKeyPath:NSStringFromSelector(_cmd)]; 720| 0|} 721| | 722| 0|- (NSArray *)downloadTasks { 723| 0| return [self tasksForKeyPath:NSStringFromSelector(_cmd)]; 724| 0|} 725| | 726| |#pragma mark - 727| | 728| 0|- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks { 729| 0| [self invalidateSessionCancelingTasks:cancelPendingTasks resetSession:NO]; 730| 0|} 731| | 732| 110|- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks resetSession:(BOOL)resetSession { 733| 110| if (cancelPendingTasks) { 734| 110| [self.session invalidateAndCancel]; 735| 110| } else { 736| 0| [self.session finishTasksAndInvalidate]; 737| 0| } 738| 110| if (resetSession) { 739| 1| self.session = nil; 740| 1| } 741| 110|} 742| | 743| |#pragma mark - 744| | 745| 261|- (void)setResponseSerializer:(id )responseSerializer { 746| 261| NSParameterAssert(responseSerializer); 747| 261| 748| 261| _responseSerializer = responseSerializer; 749| 261|} 750| | 751| |#pragma mark - 752| 195|- (void)addNotificationObserverForTask:(NSURLSessionTask *)task { 753| 195| [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidResume:) name:AFNSURLSessionTaskDidResumeNotification object:task]; 754| 195| [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidSuspend:) name:AFNSURLSessionTaskDidSuspendNotification object:task]; 755| 195|} 756| | 757| 194|- (void)removeNotificationObserverForTask:(NSURLSessionTask *)task { 758| 194| [[NSNotificationCenter defaultCenter] removeObserver:self name:AFNSURLSessionTaskDidSuspendNotification object:task]; 759| 194| [[NSNotificationCenter defaultCenter] removeObserver:self name:AFNSURLSessionTaskDidResumeNotification object:task]; 760| 194|} 761| | 762| |#pragma mark - 763| | 764| |- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request 765| | completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler 766| 0|{ 767| 0| return [self dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:completionHandler]; 768| 0|} 769| | 770| |- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request 771| | uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock 772| | downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock 773| 178| completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler { 774| 178| 775| 178| __block NSURLSessionDataTask *dataTask = nil; 776| 178| url_session_manager_create_task_safely(^{ 777| 178| dataTask = [self.session dataTaskWithRequest:request]; 778| 178| }); 779| 178| 780| 178| [self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler]; 781| 178| 782| 178| return dataTask; 783| 178|} 784| | 785| |#pragma mark - 786| | 787| |- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request 788| | fromFile:(NSURL *)fileURL 789| | progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock 790| | completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler 791| 0|{ 792| 0| __block NSURLSessionUploadTask *uploadTask = nil; 793| 0| url_session_manager_create_task_safely(^{ 794| 0| uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL]; 795| 0| 796| 0| // uploadTask may be nil on iOS7 because uploadTaskWithRequest:fromFile: may return nil despite being documented as nonnull (https://devforums.apple.com/message/926113#926113) 797| 0| if (!uploadTask && self.attemptsToRecreateUploadTasksForBackgroundSessions && self.session.configuration.identifier) { 798| 0| for (NSUInteger attempts = 0; !uploadTask && attempts < AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask; attempts++) { 799| 0| uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL]; 800| 0| } 801| 0| } 802| 0| }); 803| 0| 804| 0| if (uploadTask) { 805| 0| [self addDelegateForUploadTask:uploadTask 806| 0| progress:uploadProgressBlock 807| 0| completionHandler:completionHandler]; 808| 0| } 809| 0| 810| 0| return uploadTask; 811| 0|} 812| | 813| |- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request 814| | fromData:(NSData *)bodyData 815| | progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock 816| | completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler 817| 5|{ 818| 5| __block NSURLSessionUploadTask *uploadTask = nil; 819| 5| url_session_manager_create_task_safely(^{ 820| 5| uploadTask = [self.session uploadTaskWithRequest:request fromData:bodyData]; 821| 5| }); 822| 5| 823| 5| [self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler]; 824| 5| 825| 5| return uploadTask; 826| 5|} 827| | 828| |- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request 829| | progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock 830| | completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler 831| 5|{ 832| 5| __block NSURLSessionUploadTask *uploadTask = nil; 833| 5| url_session_manager_create_task_safely(^{ 834| 5| uploadTask = [self.session uploadTaskWithStreamedRequest:request]; 835| 5| }); 836| 5| 837| 5| [self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler]; 838| 5| 839| 5| return uploadTask; 840| 5|} 841| | 842| |#pragma mark - 843| | 844| |- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request 845| | progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock 846| | destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination 847| | completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler 848| 7|{ 849| 7| __block NSURLSessionDownloadTask *downloadTask = nil; 850| 7| url_session_manager_create_task_safely(^{ 851| 7| downloadTask = [self.session downloadTaskWithRequest:request]; 852| 7| }); 853| 7| 854| 7| [self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler]; 855| 7| 856| 7| return downloadTask; 857| 7|} 858| | 859| |- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData 860| | progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock 861| | destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination 862| | completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler 863| 0|{ 864| 0| __block NSURLSessionDownloadTask *downloadTask = nil; 865| 0| url_session_manager_create_task_safely(^{ 866| 0| downloadTask = [self.session downloadTaskWithResumeData:resumeData]; 867| 0| }); 868| 0| 869| 0| [self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler]; 870| 0| 871| 0| return downloadTask; 872| 0|} 873| | 874| |#pragma mark - 875| 1|- (NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task { 876| 1| return [[self delegateForTask:task] uploadProgress]; 877| 1|} 878| | 879| 1|- (NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task { 880| 1| return [[self delegateForTask:task] downloadProgress]; 881| 1|} 882| | 883| |#pragma mark - 884| | 885| 0|- (void)setSessionDidBecomeInvalidBlock:(void (^)(NSURLSession *session, NSError *error))block { 886| 0| self.sessionDidBecomeInvalid = block; 887| 0|} 888| | 889| 0|- (void)setSessionDidReceiveAuthenticationChallengeBlock:(NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential))block { 890| 0| self.sessionDidReceiveAuthenticationChallenge = block; 891| 0|} 892| | 893| |#if !TARGET_OS_OSX 894| 0|- (void)setDidFinishEventsForBackgroundURLSessionBlock:(void (^)(NSURLSession *session))block { 895| 0| self.didFinishEventsForBackgroundURLSession = block; 896| 0|} 897| |#endif 898| | 899| |#pragma mark - 900| | 901| 0|- (void)setTaskNeedNewBodyStreamBlock:(NSInputStream * (^)(NSURLSession *session, NSURLSessionTask *task))block { 902| 0| self.taskNeedNewBodyStream = block; 903| 0|} 904| | 905| 1|- (void)setTaskWillPerformHTTPRedirectionBlock:(NSURLRequest * (^)(NSURLSession *session, NSURLSessionTask *task, NSURLResponse *response, NSURLRequest *request))block { 906| 1| self.taskWillPerformHTTPRedirection = block; 907| 1|} 908| | 909| 0|- (void)setTaskDidReceiveAuthenticationChallengeBlock:(NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential))block { 910| 0| self.taskDidReceiveAuthenticationChallenge = block; 911| 0|} 912| | 913| 0|- (void)setTaskDidSendBodyDataBlock:(void (^)(NSURLSession *session, NSURLSessionTask *task, int64_t bytesSent, int64_t totalBytesSent, int64_t totalBytesExpectedToSend))block { 914| 0| self.taskDidSendBodyData = block; 915| 0|} 916| | 917| 0|- (void)setTaskDidCompleteBlock:(void (^)(NSURLSession *session, NSURLSessionTask *task, NSError *error))block { 918| 0| self.taskDidComplete = block; 919| 0|} 920| | 921| |#if AF_CAN_INCLUDE_SESSION_TASK_METRICS 922| 1|- (void)setTaskDidFinishCollectingMetricsBlock:(void (^)(NSURLSession * _Nonnull, NSURLSessionTask * _Nonnull, NSURLSessionTaskMetrics * _Nullable))block { 923| 1| self.taskDidFinishCollectingMetrics = block; 924| 1|} 925| |#endif 926| | 927| |#pragma mark - 928| | 929| 0|- (void)setDataTaskDidReceiveResponseBlock:(NSURLSessionResponseDisposition (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLResponse *response))block { 930| 0| self.dataTaskDidReceiveResponse = block; 931| 0|} 932| | 933| 0|- (void)setDataTaskDidBecomeDownloadTaskBlock:(void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSURLSessionDownloadTask *downloadTask))block { 934| 0| self.dataTaskDidBecomeDownloadTask = block; 935| 0|} 936| | 937| 0|- (void)setDataTaskDidReceiveDataBlock:(void (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSData *data))block { 938| 0| self.dataTaskDidReceiveData = block; 939| 0|} 940| | 941| 0|- (void)setDataTaskWillCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLSession *session, NSURLSessionDataTask *dataTask, NSCachedURLResponse *proposedResponse))block { 942| 0| self.dataTaskWillCacheResponse = block; 943| 0|} 944| | 945| |#pragma mark - 946| | 947| 1|- (void)setDownloadTaskDidFinishDownloadingBlock:(NSURL * (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location))block { 948| 1| self.downloadTaskDidFinishDownloading = block; 949| 1|} 950| | 951| 0|- (void)setDownloadTaskDidWriteDataBlock:(void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite))block { 952| 0| self.downloadTaskDidWriteData = block; 953| 0|} 954| | 955| 0|- (void)setDownloadTaskDidResumeBlock:(void (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes))block { 956| 0| self.downloadTaskDidResume = block; 957| 0|} 958| | 959| |#pragma mark - NSObject 960| | 961| 0|- (NSString *)description { 962| 0| return [NSString stringWithFormat:@"<%@: %p, session: %@, operationQueue: %@>", NSStringFromClass([self class]), self, self.session, self.operationQueue]; 963| 0|} 964| | 965| 1.87k|- (BOOL)respondsToSelector:(SEL)selector { 966| 1.87k| if (selector == @selector(URLSession:task:willPerformHTTPRedirection:newRequest:completionHandler:)) { 967| 5| return self.taskWillPerformHTTPRedirection != nil; 968| 1.87k| } else if (selector == @selector(URLSession:dataTask:didReceiveResponse:completionHandler:)) { 969| 71| return self.dataTaskDidReceiveResponse != nil; 970| 1.80k| } else if (selector == @selector(URLSession:dataTask:willCacheResponse:completionHandler:)) { 971| 64| return self.dataTaskWillCacheResponse != nil; 972| 64| } 973| 1.73k|#if !TARGET_OS_OSX 974| 1.73k| else if (selector == @selector(URLSessionDidFinishEventsForBackgroundURLSession:)) { 975| 0| return self.didFinishEventsForBackgroundURLSession != nil; 976| 0| } 977| 1.73k|#endif 978| 1.73k| 979| 1.73k| return [[self class] instancesRespondToSelector:selector]; 980| 1.73k|} 981| | 982| |#pragma mark - NSURLSessionDelegate 983| | 984| |- (void)URLSession:(NSURLSession *)session 985| |didBecomeInvalidWithError:(NSError *)error 986| 109|{ 987| 109| if (self.sessionDidBecomeInvalid) { 988| 0| self.sessionDidBecomeInvalid(session, error); 989| 0| } 990| 109| 991| 109| [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDidInvalidateNotification object:session]; 992| 109|} 993| | 994| |- (void)URLSession:(NSURLSession *)session 995| |didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge 996| | completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler 997| 73|{ 998| 73| NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling; 999| 73| __block NSURLCredential *credential = nil; 1000| 73| 1001| 73| if (self.sessionDidReceiveAuthenticationChallenge) { 1002| 0| disposition = self.sessionDidReceiveAuthenticationChallenge(session, challenge, &credential); 1003| 73| } else { 1004| 73| if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { 1005| 73| if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) { 1006| 71| credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; 1007| 71| if (credential) { 1008| 71| disposition = NSURLSessionAuthChallengeUseCredential; 1009| 71| } else { 1010| 0| disposition = NSURLSessionAuthChallengePerformDefaultHandling; 1011| 0| } 1012| 71| } else { 1013| 2| disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge; 1014| 2| } 1015| 73| } else { 1016| 0| disposition = NSURLSessionAuthChallengePerformDefaultHandling; 1017| 0| } 1018| 73| } 1019| 73| 1020| 73| if (completionHandler) { 1021| 73| completionHandler(disposition, credential); 1022| 73| } 1023| 73|} 1024| | 1025| |#pragma mark - NSURLSessionTaskDelegate 1026| | 1027| |- (void)URLSession:(NSURLSession *)session 1028| | task:(NSURLSessionTask *)task 1029| |willPerformHTTPRedirection:(NSHTTPURLResponse *)response 1030| | newRequest:(NSURLRequest *)request 1031| | completionHandler:(void (^)(NSURLRequest *))completionHandler 1032| 1|{ 1033| 1| NSURLRequest *redirectRequest = request; 1034| 1| 1035| 1| if (self.taskWillPerformHTTPRedirection) { 1036| 1| redirectRequest = self.taskWillPerformHTTPRedirection(session, task, response, request); 1037| 1| } 1038| 1| 1039| 1| if (completionHandler) { 1040| 1| completionHandler(redirectRequest); 1041| 1| } 1042| 1|} 1043| | 1044| |- (void)URLSession:(NSURLSession *)session 1045| | task:(NSURLSessionTask *)task 1046| |didReceiveChallenge:(NSURLAuthenticationChallenge *)challenge 1047| | completionHandler:(void (^)(NSURLSessionAuthChallengeDisposition disposition, NSURLCredential *credential))completionHandler 1048| 0|{ 1049| 0| NSURLSessionAuthChallengeDisposition disposition = NSURLSessionAuthChallengePerformDefaultHandling; 1050| 0| __block NSURLCredential *credential = nil; 1051| 0| 1052| 0| if (self.taskDidReceiveAuthenticationChallenge) { 1053| 0| disposition = self.taskDidReceiveAuthenticationChallenge(session, task, challenge, &credential); 1054| 0| } else { 1055| 0| if ([challenge.protectionSpace.authenticationMethod isEqualToString:NSURLAuthenticationMethodServerTrust]) { 1056| 0| if ([self.securityPolicy evaluateServerTrust:challenge.protectionSpace.serverTrust forDomain:challenge.protectionSpace.host]) { 1057| 0| disposition = NSURLSessionAuthChallengeUseCredential; 1058| 0| credential = [NSURLCredential credentialForTrust:challenge.protectionSpace.serverTrust]; 1059| 0| } else { 1060| 0| disposition = NSURLSessionAuthChallengeCancelAuthenticationChallenge; 1061| 0| } 1062| 0| } else { 1063| 0| disposition = NSURLSessionAuthChallengePerformDefaultHandling; 1064| 0| } 1065| 0| } 1066| 0| 1067| 0| if (completionHandler) { 1068| 0| completionHandler(disposition, credential); 1069| 0| } 1070| 0|} 1071| | 1072| |- (void)URLSession:(NSURLSession *)session 1073| | task:(NSURLSessionTask *)task 1074| | needNewBodyStream:(void (^)(NSInputStream *bodyStream))completionHandler 1075| 0|{ 1076| 0| NSInputStream *inputStream = nil; 1077| 0| 1078| 0| if (self.taskNeedNewBodyStream) { 1079| 0| inputStream = self.taskNeedNewBodyStream(session, task); 1080| 0| } else if (task.originalRequest.HTTPBodyStream && [task.originalRequest.HTTPBodyStream conformsToProtocol:@protocol(NSCopying)]) { 1081| 0| inputStream = [task.originalRequest.HTTPBodyStream copy]; 1082| 0| } 1083| 0| 1084| 0| if (completionHandler) { 1085| 0| completionHandler(inputStream); 1086| 0| } 1087| 0|} 1088| | 1089| |- (void)URLSession:(NSURLSession *)session 1090| | task:(NSURLSessionTask *)task 1091| | didSendBodyData:(int64_t)bytesSent 1092| | totalBytesSent:(int64_t)totalBytesSent 1093| |totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend 1094| 16|{ 1095| 16| 1096| 16| int64_t totalUnitCount = totalBytesExpectedToSend; 1097| 16| if (totalUnitCount == NSURLSessionTransferSizeUnknown) { 1098| 0| NSString *contentLength = [task.originalRequest valueForHTTPHeaderField:@"Content-Length"]; 1099| 0| if (contentLength) { 1100| 0| totalUnitCount = (int64_t) [contentLength longLongValue]; 1101| 0| } 1102| 0| } 1103| 16| 1104| 16| AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task]; 1105| 16| 1106| 16| if (delegate) { 1107| 16| [delegate URLSession:session task:task didSendBodyData:bytesSent totalBytesSent:totalBytesSent totalBytesExpectedToSend:totalBytesExpectedToSend]; 1108| 16| } 1109| 16| 1110| 16| if (self.taskDidSendBodyData) { 1111| 0| self.taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalUnitCount); 1112| 0| } 1113| 16|} 1114| | 1115| |- (void)URLSession:(NSURLSession *)session 1116| | task:(NSURLSessionTask *)task 1117| |didCompleteWithError:(NSError *)error 1118| 194|{ 1119| 194| AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task]; 1120| 194| 1121| 194| // delegate may be nil when completing a task in the background 1122| 194| if (delegate) { 1123| 194| [delegate URLSession:session task:task didCompleteWithError:error]; 1124| 194| 1125| 194| [self removeDelegateForTask:task]; 1126| 194| } 1127| 194| 1128| 194| if (self.taskDidComplete) { 1129| 0| self.taskDidComplete(session, task, error); 1130| 0| } 1131| 194|} 1132| | 1133| |#if AF_CAN_INCLUDE_SESSION_TASK_METRICS 1134| |- (void)URLSession:(NSURLSession *)session 1135| | task:(NSURLSessionTask *)task 1136| |didFinishCollectingMetrics:(NSURLSessionTaskMetrics *)metrics 1137| 88|{ 1138| 88| AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task]; 1139| 88| // Metrics may fire after URLSession:task:didCompleteWithError: is called, delegate may be nil 1140| 88| if (delegate) { 1141| 87| [delegate URLSession:session task:task didFinishCollectingMetrics:metrics]; 1142| 87| } 1143| 88| 1144| 88| if (self.taskDidFinishCollectingMetrics) { 1145| 1| self.taskDidFinishCollectingMetrics(session, task, metrics); 1146| 1| } 1147| 88|} 1148| |#endif 1149| | 1150| |#pragma mark - NSURLSessionDataDelegate 1151| | 1152| |- (void)URLSession:(NSURLSession *)session 1153| | dataTask:(NSURLSessionDataTask *)dataTask 1154| |didReceiveResponse:(NSURLResponse *)response 1155| | completionHandler:(void (^)(NSURLSessionResponseDisposition disposition))completionHandler 1156| 0|{ 1157| 0| NSURLSessionResponseDisposition disposition = NSURLSessionResponseAllow; 1158| 0| 1159| 0| if (self.dataTaskDidReceiveResponse) { 1160| 0| disposition = self.dataTaskDidReceiveResponse(session, dataTask, response); 1161| 0| } 1162| 0| 1163| 0| if (completionHandler) { 1164| 0| completionHandler(disposition); 1165| 0| } 1166| 0|} 1167| | 1168| |- (void)URLSession:(NSURLSession *)session 1169| | dataTask:(NSURLSessionDataTask *)dataTask 1170| |didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask 1171| 0|{ 1172| 0| AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask]; 1173| 0| if (delegate) { 1174| 0| [self removeDelegateForTask:dataTask]; 1175| 0| [self setDelegate:delegate forTask:downloadTask]; 1176| 0| } 1177| 0| 1178| 0| if (self.dataTaskDidBecomeDownloadTask) { 1179| 0| self.dataTaskDidBecomeDownloadTask(session, dataTask, downloadTask); 1180| 0| } 1181| 0|} 1182| | 1183| |- (void)URLSession:(NSURLSession *)session 1184| | dataTask:(NSURLSessionDataTask *)dataTask 1185| | didReceiveData:(NSData *)data 1186| 71|{ 1187| 71| 1188| 71| AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask]; 1189| 71| [delegate URLSession:session dataTask:dataTask didReceiveData:data]; 1190| 71| 1191| 71| if (self.dataTaskDidReceiveData) { 1192| 0| self.dataTaskDidReceiveData(session, dataTask, data); 1193| 0| } 1194| 71|} 1195| | 1196| |- (void)URLSession:(NSURLSession *)session 1197| | dataTask:(NSURLSessionDataTask *)dataTask 1198| | willCacheResponse:(NSCachedURLResponse *)proposedResponse 1199| | completionHandler:(void (^)(NSCachedURLResponse *cachedResponse))completionHandler 1200| 0|{ 1201| 0| NSCachedURLResponse *cachedResponse = proposedResponse; 1202| 0| 1203| 0| if (self.dataTaskWillCacheResponse) { 1204| 0| cachedResponse = self.dataTaskWillCacheResponse(session, dataTask, proposedResponse); 1205| 0| } 1206| 0| 1207| 0| if (completionHandler) { 1208| 0| completionHandler(cachedResponse); 1209| 0| } 1210| 0|} 1211| | 1212| |#if !TARGET_OS_OSX 1213| 0|- (void)URLSessionDidFinishEventsForBackgroundURLSession:(NSURLSession *)session { 1214| 0| if (self.didFinishEventsForBackgroundURLSession) { 1215| 0| dispatch_async(dispatch_get_main_queue(), ^{ 1216| 0| self.didFinishEventsForBackgroundURLSession(session); 1217| 0| }); 1218| 0| } 1219| 0|} 1220| |#endif 1221| | 1222| |#pragma mark - NSURLSessionDownloadDelegate 1223| | 1224| |- (void)URLSession:(NSURLSession *)session 1225| | downloadTask:(NSURLSessionDownloadTask *)downloadTask 1226| |didFinishDownloadingToURL:(NSURL *)location 1227| 4|{ 1228| 4| AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask]; 1229| 4| if (self.downloadTaskDidFinishDownloading) { 1230| 1| NSURL *fileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location); 1231| 1| if (fileURL) { 1232| 1| delegate.downloadFileURL = fileURL; 1233| 1| NSError *error = nil; 1234| 1| 1235| 1| if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:fileURL error:&error]) { 1236| 1| [[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:error.userInfo]; 1237| 1| } 1238| 1| 1239| 1| return; 1240| 1| } 1241| 3| } 1242| 3| 1243| 3| if (delegate) { 1244| 3| [delegate URLSession:session downloadTask:downloadTask didFinishDownloadingToURL:location]; 1245| 3| } 1246| 3|} 1247| | 1248| |- (void)URLSession:(NSURLSession *)session 1249| | downloadTask:(NSURLSessionDownloadTask *)downloadTask 1250| | didWriteData:(int64_t)bytesWritten 1251| | totalBytesWritten:(int64_t)totalBytesWritten 1252| |totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite 1253| 9|{ 1254| 9| 1255| 9| AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask]; 1256| 9| 1257| 9| if (delegate) { 1258| 9| [delegate URLSession:session downloadTask:downloadTask didWriteData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite]; 1259| 9| } 1260| 9| 1261| 9| if (self.downloadTaskDidWriteData) { 1262| 0| self.downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite); 1263| 0| } 1264| 9|} 1265| | 1266| |- (void)URLSession:(NSURLSession *)session 1267| | downloadTask:(NSURLSessionDownloadTask *)downloadTask 1268| | didResumeAtOffset:(int64_t)fileOffset 1269| |expectedTotalBytes:(int64_t)expectedTotalBytes 1270| 0|{ 1271| 0| 1272| 0| AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask]; 1273| 0| 1274| 0| if (delegate) { 1275| 0| [delegate URLSession:session downloadTask:downloadTask didResumeAtOffset:fileOffset expectedTotalBytes:expectedTotalBytes]; 1276| 0| } 1277| 0| 1278| 0| if (self.downloadTaskDidResume) { 1279| 0| self.downloadTaskDidResume(session, downloadTask, fileOffset, expectedTotalBytes); 1280| 0| } 1281| 0|} 1282| | 1283| |#pragma mark - NSSecureCoding 1284| | 1285| 0|+ (BOOL)supportsSecureCoding { 1286| 0| return YES; 1287| 0|} 1288| | 1289| 0|- (instancetype)initWithCoder:(NSCoder *)decoder { 1290| 0| NSURLSessionConfiguration *configuration = [decoder decodeObjectOfClass:[NSURLSessionConfiguration class] forKey:@"sessionConfiguration"]; 1291| 0| 1292| 0| self = [self initWithSessionConfiguration:configuration]; 1293| 0| if (!self) { 1294| 0| return nil; 1295| 0| } 1296| 0| 1297| 0| return self; 1298| 0|} 1299| | 1300| 2|- (void)encodeWithCoder:(NSCoder *)coder { 1301| 2| [coder encodeObject:self.session.configuration forKey:@"sessionConfiguration"]; 1302| 2|} 1303| | 1304| |#pragma mark - NSCopying 1305| | 1306| 0|- (instancetype)copyWithZone:(NSZone *)zone { 1307| 0| return [[[self class] allocWithZone:zone] initWithSessionConfiguration:self.session.configuration]; 1308| 0|} 1309| | 1310| |@end /Users/travis/build/AFNetworking/AFNetworking/UIKit+AFNetworking/AFAutoPurgingImageCache.m: 1| |// AFAutoPurgingImageCache.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import 23| | 24| |#if TARGET_OS_IOS || TARGET_OS_TV 25| | 26| |#import "AFAutoPurgingImageCache.h" 27| | 28| |@interface AFCachedImage : NSObject 29| | 30| |@property (nonatomic, strong) UIImage *image; 31| |@property (nonatomic, copy) NSString *identifier; 32| |@property (nonatomic, assign) UInt64 totalBytes; 33| |@property (nonatomic, strong) NSDate *lastAccessDate; 34| |@property (nonatomic, assign) UInt64 currentMemoryUsage; 35| | 36| |@end 37| | 38| |@implementation AFCachedImage 39| | 40| 60|- (instancetype)initWithImage:(UIImage *)image identifier:(NSString *)identifier { 41| 60| if (self = [self init]) { 42| 60| self.image = image; 43| 60| self.identifier = identifier; 44| 60| 45| 60| CGSize imageSize = CGSizeMake(image.size.width * image.scale, image.size.height * image.scale); 46| 60| CGFloat bytesPerPixel = 4.0; 47| 60| CGFloat bytesPerSize = imageSize.width * imageSize.height; 48| 60| self.totalBytes = (UInt64)bytesPerPixel * (UInt64)bytesPerSize; 49| 60| self.lastAccessDate = [NSDate date]; 50| 60| } 51| 60| return self; 52| 60|} 53| | 54| 17|- (UIImage *)accessImage { 55| 17| self.lastAccessDate = [NSDate date]; 56| 17| return self.image; 57| 17|} 58| | 59| 0|- (NSString *)description { 60| 0| NSString *descriptionString = [NSString stringWithFormat:@"Idenfitier: %@ lastAccessDate: %@ ", self.identifier, self.lastAccessDate]; 61| 0| return descriptionString; 62| 0| 63| 0|} 64| | 65| |@end 66| | 67| |@interface AFAutoPurgingImageCache () 68| |@property (nonatomic, strong) NSMutableDictionary *cachedImages; 69| |@property (nonatomic, assign) UInt64 currentMemoryUsage; 70| |@property (nonatomic, strong) dispatch_queue_t synchronizationQueue; 71| |@end 72| | 73| |@implementation AFAutoPurgingImageCache 74| | 75| 31|- (instancetype)init { 76| 31| return [self initWithMemoryCapacity:100 * 1024 * 1024 preferredMemoryCapacity:60 * 1024 * 1024]; 77| 31|} 78| | 79| 49|- (instancetype)initWithMemoryCapacity:(UInt64)memoryCapacity preferredMemoryCapacity:(UInt64)preferredMemoryCapacity { 80| 49| if (self = [super init]) { 81| 49| self.memoryCapacity = memoryCapacity; 82| 49| self.preferredMemoryUsageAfterPurge = preferredMemoryCapacity; 83| 49| self.cachedImages = [[NSMutableDictionary alloc] init]; 84| 49| 85| 49| NSString *queueName = [NSString stringWithFormat:@"com.alamofire.autopurgingimagecache-%@", [[NSUUID UUID] UUIDString]]; 86| 49| self.synchronizationQueue = dispatch_queue_create([queueName cStringUsingEncoding:NSASCIIStringEncoding], DISPATCH_QUEUE_CONCURRENT); 87| 49| 88| 49| [[NSNotificationCenter defaultCenter] 89| 49| addObserver:self 90| 49| selector:@selector(removeAllImages) 91| 49| name:UIApplicationDidReceiveMemoryWarningNotification 92| 49| object:nil]; 93| 49| 94| 49| } 95| 49| return self; 96| 49|} 97| | 98| 46|- (void)dealloc { 99| 46| [[NSNotificationCenter defaultCenter] removeObserver:self]; 100| 46|} 101| | 102| 17|- (UInt64)memoryUsage { 103| 17| __block UInt64 result = 0; 104| 17| dispatch_sync(self.synchronizationQueue, ^{ 105| 17| result = self.currentMemoryUsage; 106| 17| }); 107| 17| return result; 108| 17|} 109| | 110| 60|- (void)addImage:(UIImage *)image withIdentifier:(NSString *)identifier { 111| 60| dispatch_barrier_async(self.synchronizationQueue, ^{ 112| 60| AFCachedImage *cacheImage = [[AFCachedImage alloc] initWithImage:image identifier:identifier]; 113| 60| 114| 60| AFCachedImage *previousCachedImage = self.cachedImages[identifier]; 115| 60| if (previousCachedImage != nil) { 116| 2| self.currentMemoryUsage -= previousCachedImage.totalBytes; 117| 2| } 118| 60| 119| 60| self.cachedImages[identifier] = cacheImage; 120| 60| self.currentMemoryUsage += cacheImage.totalBytes; 121| 60| }); 122| 60| 123| 60| dispatch_barrier_async(self.synchronizationQueue, ^{ 124| 60| if (self.currentMemoryUsage > self.memoryCapacity) { 125| 2| UInt64 bytesToPurge = self.currentMemoryUsage - self.preferredMemoryUsageAfterPurge; 126| 2| NSMutableArray *sortedImages = [NSMutableArray arrayWithArray:self.cachedImages.allValues]; 127| 2| NSSortDescriptor *sortDescriptor = [[NSSortDescriptor alloc] initWithKey:@"lastAccessDate" 128| 2| ascending:YES]; 129| 2| [sortedImages sortUsingDescriptors:@[sortDescriptor]]; 130| 2| 131| 2| UInt64 bytesPurged = 0; 132| 2| 133| 10| for (AFCachedImage *cachedImage in sortedImages) { 134| 10| [self.cachedImages removeObjectForKey:cachedImage.identifier]; 135| 10| bytesPurged += cachedImage.totalBytes; 136| 10| if (bytesPurged >= bytesToPurge) { 137| 2| break; 138| 2| } 139| 10| } 140| 2| self.currentMemoryUsage -= bytesPurged; 141| 2| } 142| 60| }); 143| 60|} 144| | 145| 9|- (BOOL)removeImageWithIdentifier:(NSString *)identifier { 146| 9| __block BOOL removed = NO; 147| 9| dispatch_barrier_sync(self.synchronizationQueue, ^{ 148| 9| AFCachedImage *cachedImage = self.cachedImages[identifier]; 149| 9| if (cachedImage != nil) { 150| 4| [self.cachedImages removeObjectForKey:identifier]; 151| 4| self.currentMemoryUsage -= cachedImage.totalBytes; 152| 4| removed = YES; 153| 4| } 154| 9| }); 155| 9| return removed; 156| 9|} 157| | 158| 44|- (BOOL)removeAllImages { 159| 44| __block BOOL removed = NO; 160| 44| dispatch_barrier_sync(self.synchronizationQueue, ^{ 161| 44| if (self.cachedImages.count > 0) { 162| 17| [self.cachedImages removeAllObjects]; 163| 17| self.currentMemoryUsage = 0; 164| 17| removed = YES; 165| 17| } 166| 44| }); 167| 44| return removed; 168| 44|} 169| | 170| 68|- (nullable UIImage *)imageWithIdentifier:(NSString *)identifier { 171| 68| __block UIImage *image = nil; 172| 68| dispatch_sync(self.synchronizationQueue, ^{ 173| 68| AFCachedImage *cachedImage = self.cachedImages[identifier]; 174| 68| image = [cachedImage accessImage]; 175| 68| }); 176| 68| return image; 177| 68|} 178| | 179| 34|- (void)addImage:(UIImage *)image forRequest:(NSURLRequest *)request withAdditionalIdentifier:(NSString *)identifier { 180| 34| [self addImage:image withIdentifier:[self imageCacheKeyFromURLRequest:request withAdditionalIdentifier:identifier]]; 181| 34|} 182| | 183| 6|- (BOOL)removeImageforRequest:(NSURLRequest *)request withAdditionalIdentifier:(NSString *)identifier { 184| 6| return [self removeImageWithIdentifier:[self imageCacheKeyFromURLRequest:request withAdditionalIdentifier:identifier]]; 185| 6|} 186| | 187| 54|- (nullable UIImage *)imageforRequest:(NSURLRequest *)request withAdditionalIdentifier:(NSString *)identifier { 188| 54| return [self imageWithIdentifier:[self imageCacheKeyFromURLRequest:request withAdditionalIdentifier:identifier]]; 189| 54|} 190| | 191| 94|- (NSString *)imageCacheKeyFromURLRequest:(NSURLRequest *)request withAdditionalIdentifier:(NSString *)additionalIdentifier { 192| 94| NSString *key = request.URL.absoluteString; 193| 94| if (additionalIdentifier != nil) { 194| 12| key = [key stringByAppendingString:additionalIdentifier]; 195| 12| } 196| 94| return key; 197| 94|} 198| | 199| 24|- (BOOL)shouldCacheImage:(UIImage *)image forRequest:(NSURLRequest *)request withAdditionalIdentifier:(nullable NSString *)identifier { 200| 24| return YES; 201| 24|} 202| | 203| |@end 204| | 205| |#endif /Users/travis/build/AFNetworking/AFNetworking/UIKit+AFNetworking/AFImageDownloader.m: 1| |// AFImageDownloader.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import 23| | 24| |#if TARGET_OS_IOS || TARGET_OS_TV 25| | 26| |#import "AFImageDownloader.h" 27| |#import "AFHTTPSessionManager.h" 28| | 29| |@interface AFImageDownloaderResponseHandler : NSObject 30| |@property (nonatomic, strong) NSUUID *uuid; 31| |@property (nonatomic, copy) void (^successBlock)(NSURLRequest *, NSHTTPURLResponse *, UIImage *); 32| |@property (nonatomic, copy) void (^failureBlock)(NSURLRequest *, NSHTTPURLResponse *, NSError *); 33| |@end 34| | 35| |@implementation AFImageDownloaderResponseHandler 36| | 37| |- (instancetype)initWithUUID:(NSUUID *)uuid 38| | success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *responseObject))success 39| 41| failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure { 40| 41| if (self = [self init]) { 41| 41| self.uuid = uuid; 42| 41| self.successBlock = success; 43| 41| self.failureBlock = failure; 44| 41| } 45| 41| return self; 46| 41|} 47| | 48| 0|- (NSString *)description { 49| 0| return [NSString stringWithFormat: @"UUID: %@", [self.uuid UUIDString]]; 50| 0|} 51| | 52| |@end 53| | 54| |@interface AFImageDownloaderMergedTask : NSObject 55| |@property (nonatomic, strong) NSString *URLIdentifier; 56| |@property (nonatomic, strong) NSUUID *identifier; 57| |@property (nonatomic, strong) NSURLSessionDataTask *task; 58| |@property (nonatomic, strong) NSMutableArray *responseHandlers; 59| | 60| |@end 61| | 62| |@implementation AFImageDownloaderMergedTask 63| | 64| 32|- (instancetype)initWithURLIdentifier:(NSString *)URLIdentifier identifier:(NSUUID *)identifier task:(NSURLSessionDataTask *)task { 65| 32| if (self = [self init]) { 66| 32| self.URLIdentifier = URLIdentifier; 67| 32| self.task = task; 68| 32| self.identifier = identifier; 69| 32| self.responseHandlers = [[NSMutableArray alloc] init]; 70| 32| } 71| 32| return self; 72| 32|} 73| | 74| 41|- (void)addResponseHandler:(AFImageDownloaderResponseHandler *)handler { 75| 41| [self.responseHandlers addObject:handler]; 76| 41|} 77| | 78| 11|- (void)removeResponseHandler:(AFImageDownloaderResponseHandler *)handler { 79| 11| [self.responseHandlers removeObject:handler]; 80| 11|} 81| | 82| |@end 83| | 84| |@implementation AFImageDownloadReceipt 85| | 86| 41|- (instancetype)initWithReceiptID:(NSUUID *)receiptID task:(NSURLSessionDataTask *)task { 87| 41| if (self = [self init]) { 88| 41| self.receiptID = receiptID; 89| 41| self.task = task; 90| 41| } 91| 41| return self; 92| 41|} 93| | 94| |@end 95| | 96| |@interface AFImageDownloader () 97| | 98| |@property (nonatomic, strong) dispatch_queue_t synchronizationQueue; 99| |@property (nonatomic, strong) dispatch_queue_t responseQueue; 100| | 101| |@property (nonatomic, assign) NSInteger maximumActiveDownloads; 102| |@property (nonatomic, assign) NSInteger activeRequestCount; 103| | 104| |@property (nonatomic, strong) NSMutableArray *queuedMergedTasks; 105| |@property (nonatomic, strong) NSMutableDictionary *mergedTasks; 106| | 107| |@end 108| | 109| |@implementation AFImageDownloader 110| | 111| 47|+ (NSURLCache *)defaultURLCache { 112| 47| 113| 47| // It's been discovered that a crash will occur on certain versions 114| 47| // of iOS if you customize the cache. 115| 47| // 116| 47| // More info can be found here: https://devforums.apple.com/message/1102182#1102182 117| 47| // 118| 47| // When iOS 7 support is dropped, this should be modified to use 119| 47| // NSProcessInfo methods instead. 120| 47| if ([[[UIDevice currentDevice] systemVersion] compare:@"8.2" options:NSNumericSearch] == NSOrderedAscending) { 121| 0| return [NSURLCache sharedURLCache]; 122| 0| } 123| 47| return [[NSURLCache alloc] initWithMemoryCapacity:20 * 1024 * 1024 124| 47| diskCapacity:150 * 1024 * 1024 125| 47| diskPath:@"com.alamofire.imagedownloader"]; 126| 47|} 127| | 128| 29|+ (NSURLSessionConfiguration *)defaultURLSessionConfiguration { 129| 29| NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration]; 130| 29| 131| 29| //TODO set the default HTTP headers 132| 29| 133| 29| configuration.HTTPShouldSetCookies = YES; 134| 29| configuration.HTTPShouldUsePipelining = NO; 135| 29| 136| 29| configuration.requestCachePolicy = NSURLRequestUseProtocolCachePolicy; 137| 29| configuration.allowsCellularAccess = YES; 138| 29| configuration.timeoutIntervalForRequest = 60.0; 139| 29| configuration.URLCache = [AFImageDownloader defaultURLCache]; 140| 29| 141| 29| return configuration; 142| 29|} 143| | 144| 29|- (instancetype)init { 145| 29| NSURLSessionConfiguration *defaultConfiguration = [self.class defaultURLSessionConfiguration]; 146| 29| return [self initWithSessionConfiguration:defaultConfiguration]; 147| 29|} 148| | 149| 29|- (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration { 150| 29| AFHTTPSessionManager *sessionManager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:configuration]; 151| 29| sessionManager.responseSerializer = [AFImageResponseSerializer serializer]; 152| 29| 153| 29| return [self initWithSessionManager:sessionManager 154| 29| downloadPrioritization:AFImageDownloadPrioritizationFIFO 155| 29| maximumActiveDownloads:4 156| 29| imageCache:[[AFAutoPurgingImageCache alloc] init]]; 157| 29|} 158| | 159| |- (instancetype)initWithSessionManager:(AFHTTPSessionManager *)sessionManager 160| | downloadPrioritization:(AFImageDownloadPrioritization)downloadPrioritization 161| | maximumActiveDownloads:(NSInteger)maximumActiveDownloads 162| 29| imageCache:(id )imageCache { 163| 29| if (self = [super init]) { 164| 29| self.sessionManager = sessionManager; 165| 29| 166| 29| self.downloadPrioritizaton = downloadPrioritization; 167| 29| self.maximumActiveDownloads = maximumActiveDownloads; 168| 29| self.imageCache = imageCache; 169| 29| 170| 29| self.queuedMergedTasks = [[NSMutableArray alloc] init]; 171| 29| self.mergedTasks = [[NSMutableDictionary alloc] init]; 172| 29| self.activeRequestCount = 0; 173| 29| 174| 29| NSString *name = [NSString stringWithFormat:@"com.alamofire.imagedownloader.synchronizationqueue-%@", [[NSUUID UUID] UUIDString]]; 175| 29| self.synchronizationQueue = dispatch_queue_create([name cStringUsingEncoding:NSASCIIStringEncoding], DISPATCH_QUEUE_SERIAL); 176| 29| 177| 29| name = [NSString stringWithFormat:@"com.alamofire.imagedownloader.responsequeue-%@", [[NSUUID UUID] UUIDString]]; 178| 29| self.responseQueue = dispatch_queue_create([name cStringUsingEncoding:NSASCIIStringEncoding], DISPATCH_QUEUE_CONCURRENT); 179| 29| } 180| 29| 181| 29| return self; 182| 29|} 183| | 184| 23|+ (instancetype)defaultInstance { 185| 23| static AFImageDownloader *sharedInstance = nil; 186| 23| static dispatch_once_t onceToken; 187| 23| dispatch_once(&onceToken, ^{ 188| 1| sharedInstance = [[self alloc] init]; 189| 1| }); 190| 23| return sharedInstance; 191| 23|} 192| | 193| |- (nullable AFImageDownloadReceipt *)downloadImageForURLRequest:(NSURLRequest *)request 194| | success:(void (^)(NSURLRequest * _Nonnull, NSHTTPURLResponse * _Nullable, UIImage * _Nonnull))success 195| 34| failure:(void (^)(NSURLRequest * _Nonnull, NSHTTPURLResponse * _Nullable, NSError * _Nonnull))failure { 196| 34| return [self downloadImageForURLRequest:request withReceiptID:[NSUUID UUID] success:success failure:failure]; 197| 34|} 198| | 199| |- (nullable AFImageDownloadReceipt *)downloadImageForURLRequest:(NSURLRequest *)request 200| | withReceiptID:(nonnull NSUUID *)receiptID 201| | success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *responseObject))success 202| 45| failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure { 203| 45| __block NSURLSessionDataTask *task = nil; 204| 45| dispatch_sync(self.synchronizationQueue, ^{ 205| 45| NSString *URLIdentifier = request.URL.absoluteString; 206| 45| if (URLIdentifier == nil) { 207| 1| if (failure) { 208| 1| NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadURL userInfo:nil]; 209| 1| dispatch_async(dispatch_get_main_queue(), ^{ 210| 1| failure(request, nil, error); 211| 1| }); 212| 1| } 213| 1| return; 214| 1| } 215| 44| 216| 44| // 1) Append the success and failure blocks to a pre-existing request if it already exists 217| 44| AFImageDownloaderMergedTask *existingMergedTask = self.mergedTasks[URLIdentifier]; 218| 44| if (existingMergedTask != nil) { 219| 9| AFImageDownloaderResponseHandler *handler = [[AFImageDownloaderResponseHandler alloc] initWithUUID:receiptID success:success failure:failure]; 220| 9| [existingMergedTask addResponseHandler:handler]; 221| 9| task = existingMergedTask.task; 222| 9| return; 223| 9| } 224| 35| 225| 35| // 2) Attempt to load the image from the image cache if the cache policy allows it 226| 35| switch (request.cachePolicy) { 227| 35| case NSURLRequestUseProtocolCachePolicy: 228| 34| case NSURLRequestReturnCacheDataElseLoad: 229| 34| case NSURLRequestReturnCacheDataDontLoad: { 230| 34| UIImage *cachedImage = [self.imageCache imageforRequest:request withAdditionalIdentifier:nil]; 231| 34| if (cachedImage != nil) { 232| 3| if (success) { 233| 3| dispatch_async(dispatch_get_main_queue(), ^{ 234| 3| success(request, nil, cachedImage); 235| 3| }); 236| 3| } 237| 3| return; 238| 3| } 239| 31| break; 240| 31| } 241| 31| default: 242| 1| break; 243| 32| } 244| 32| 245| 32| // 3) Create the request and set up authentication, validation and response serialization 246| 32| NSUUID *mergedTaskIdentifier = [NSUUID UUID]; 247| 32| NSURLSessionDataTask *createdTask; 248| 32| __weak __typeof__(self) weakSelf = self; 249| 32| 250| 32| createdTask = [self.sessionManager 251| 32| dataTaskWithRequest:request 252| 32| uploadProgress:nil 253| 32| downloadProgress:nil 254| 32| completionHandler:^(NSURLResponse * _Nonnull response, id _Nullable responseObject, NSError * _Nullable error) { 255| 32| dispatch_async(self.responseQueue, ^{ 256| 32| __strong __typeof__(weakSelf) strongSelf = weakSelf; 257| 32| AFImageDownloaderMergedTask *mergedTask = [strongSelf safelyGetMergedTask:URLIdentifier]; 258| 32| if ([mergedTask.identifier isEqual:mergedTaskIdentifier]) { 259| 28| mergedTask = [strongSelf safelyRemoveMergedTaskWithURLIdentifier:URLIdentifier]; 260| 28| if (error) { 261| 2| for (AFImageDownloaderResponseHandler *handler in mergedTask.responseHandlers) { 262| 2| if (handler.failureBlock) { 263| 2| dispatch_async(dispatch_get_main_queue(), ^{ 264| 2| handler.failureBlock(request, (NSHTTPURLResponse *)response, error); 265| 2| }); 266| 2| } 267| 2| } 268| 26| } else { 269| 26| if ([strongSelf.imageCache shouldCacheImage:responseObject forRequest:request withAdditionalIdentifier:nil]) { 270| 24| [strongSelf.imageCache addImage:responseObject forRequest:request withAdditionalIdentifier:nil]; 271| 24| } 272| 26| 273| 27| for (AFImageDownloaderResponseHandler *handler in mergedTask.responseHandlers) { 274| 27| if (handler.successBlock) { 275| 27| dispatch_async(dispatch_get_main_queue(), ^{ 276| 27| handler.successBlock(request, (NSHTTPURLResponse *)response, responseObject); 277| 27| }); 278| 27| } 279| 27| } 280| 26| 281| 26| } 282| 28| } 283| 32| [strongSelf safelyDecrementActiveTaskCount]; 284| 32| [strongSelf safelyStartNextTaskIfNecessary]; 285| 32| }); 286| 32| }]; 287| 32| 288| 32| // 4) Store the response handler for use when the request completes 289| 32| AFImageDownloaderResponseHandler *handler = [[AFImageDownloaderResponseHandler alloc] initWithUUID:receiptID 290| 32| success:success 291| 32| failure:failure]; 292| 32| AFImageDownloaderMergedTask *mergedTask = [[AFImageDownloaderMergedTask alloc] 293| 32| initWithURLIdentifier:URLIdentifier 294| 32| identifier:mergedTaskIdentifier 295| 32| task:createdTask]; 296| 32| [mergedTask addResponseHandler:handler]; 297| 32| self.mergedTasks[URLIdentifier] = mergedTask; 298| 32| 299| 32| // 5) Either start the request or enqueue it depending on the current active request count 300| 32| if ([self isActiveRequestCountBelowMaximumLimit]) { 301| 30| [self startMergedTask:mergedTask]; 302| 30| } else { 303| 2| [self enqueueMergedTask:mergedTask]; 304| 2| } 305| 32| 306| 32| task = mergedTask.task; 307| 32| }); 308| 45| if (task) { 309| 41| return [[AFImageDownloadReceipt alloc] initWithReceiptID:receiptID task:task]; 310| 41| } else { 311| 4| return nil; 312| 4| } 313| 45|} 314| | 315| 11|- (void)cancelTaskForImageDownloadReceipt:(AFImageDownloadReceipt *)imageDownloadReceipt { 316| 11| dispatch_sync(self.synchronizationQueue, ^{ 317| 11| NSString *URLIdentifier = imageDownloadReceipt.task.originalRequest.URL.absoluteString; 318| 11| AFImageDownloaderMergedTask *mergedTask = self.mergedTasks[URLIdentifier]; 319| 12| NSUInteger index = [mergedTask.responseHandlers indexOfObjectPassingTest:^BOOL(AFImageDownloaderResponseHandler * _Nonnull handler, __unused NSUInteger idx, __unused BOOL * _Nonnull stop) { 320| 12| return handler.uuid == imageDownloadReceipt.receiptID; 321| 12| }]; 322| 11| 323| 11| if (index != NSNotFound) { 324| 11| AFImageDownloaderResponseHandler *handler = mergedTask.responseHandlers[index]; 325| 11| [mergedTask removeResponseHandler:handler]; 326| 11| NSString *failureReason = [NSString stringWithFormat:@"ImageDownloader cancelled URL request: %@",imageDownloadReceipt.task.originalRequest.URL.absoluteString]; 327| 11| NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey:failureReason}; 328| 11| NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorCancelled userInfo:userInfo]; 329| 11| if (handler.failureBlock) { 330| 10| dispatch_async(dispatch_get_main_queue(), ^{ 331| 10| handler.failureBlock(imageDownloadReceipt.task.originalRequest, nil, error); 332| 10| }); 333| 10| } 334| 11| } 335| 11| 336| 11| if (mergedTask.responseHandlers.count == 0 && mergedTask.task.state == NSURLSessionTaskStateSuspended) { 337| 1| [mergedTask.task cancel]; 338| 1| [self removeMergedTaskWithURLIdentifier:URLIdentifier]; 339| 1| } 340| 11| }); 341| 11|} 342| | 343| 28|- (AFImageDownloaderMergedTask *)safelyRemoveMergedTaskWithURLIdentifier:(NSString *)URLIdentifier { 344| 28| __block AFImageDownloaderMergedTask *mergedTask = nil; 345| 28| dispatch_sync(self.synchronizationQueue, ^{ 346| 28| mergedTask = [self removeMergedTaskWithURLIdentifier:URLIdentifier]; 347| 28| }); 348| 28| return mergedTask; 349| 28|} 350| | 351| |//This method should only be called from safely within the synchronizationQueue 352| 29|- (AFImageDownloaderMergedTask *)removeMergedTaskWithURLIdentifier:(NSString *)URLIdentifier { 353| 29| AFImageDownloaderMergedTask *mergedTask = self.mergedTasks[URLIdentifier]; 354| 29| [self.mergedTasks removeObjectForKey:URLIdentifier]; 355| 29| return mergedTask; 356| 29|} 357| | 358| 29|- (void)safelyDecrementActiveTaskCount { 359| 29| dispatch_sync(self.synchronizationQueue, ^{ 360| 29| if (self.activeRequestCount > 0) { 361| 28| self.activeRequestCount -= 1; 362| 28| } 363| 29| }); 364| 29|} 365| | 366| 29|- (void)safelyStartNextTaskIfNecessary { 367| 29| dispatch_sync(self.synchronizationQueue, ^{ 368| 29| if ([self isActiveRequestCountBelowMaximumLimit]) { 369| 30| while (self.queuedMergedTasks.count > 0) { 370| 2| AFImageDownloaderMergedTask *mergedTask = [self dequeueMergedTask]; 371| 2| if (mergedTask.task.state == NSURLSessionTaskStateSuspended) { 372| 1| [self startMergedTask:mergedTask]; 373| 1| break; 374| 1| } 375| 2| } 376| 29| } 377| 29| }); 378| 29|} 379| | 380| 31|- (void)startMergedTask:(AFImageDownloaderMergedTask *)mergedTask { 381| 31| [mergedTask.task resume]; 382| 31| ++self.activeRequestCount; 383| 31|} 384| | 385| 2|- (void)enqueueMergedTask:(AFImageDownloaderMergedTask *)mergedTask { 386| 2| switch (self.downloadPrioritizaton) { 387| 2| case AFImageDownloadPrioritizationFIFO: 388| 2| [self.queuedMergedTasks addObject:mergedTask]; 389| 2| break; 390| 2| case AFImageDownloadPrioritizationLIFO: 391| 0| [self.queuedMergedTasks insertObject:mergedTask atIndex:0]; 392| 0| break; 393| 2| } 394| 2|} 395| | 396| 2|- (AFImageDownloaderMergedTask *)dequeueMergedTask { 397| 2| AFImageDownloaderMergedTask *mergedTask = nil; 398| 2| mergedTask = [self.queuedMergedTasks firstObject]; 399| 2| [self.queuedMergedTasks removeObject:mergedTask]; 400| 2| return mergedTask; 401| 2|} 402| | 403| 61|- (BOOL)isActiveRequestCountBelowMaximumLimit { 404| 61| return self.activeRequestCount < self.maximumActiveDownloads; 405| 61|} 406| | 407| 29|- (AFImageDownloaderMergedTask *)safelyGetMergedTask:(NSString *)URLIdentifier { 408| 29| __block AFImageDownloaderMergedTask *mergedTask; 409| 29| dispatch_sync(self.synchronizationQueue, ^(){ 410| 29| mergedTask = self.mergedTasks[URLIdentifier]; 411| 29| }); 412| 29| return mergedTask; 413| 29|} 414| | 415| |@end 416| | 417| |#endif /Users/travis/build/AFNetworking/AFNetworking/UIKit+AFNetworking/AFNetworkActivityIndicatorManager.m: 1| |// AFNetworkActivityIndicatorManager.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "AFNetworkActivityIndicatorManager.h" 23| | 24| |#if TARGET_OS_IOS 25| |#import "AFURLSessionManager.h" 26| | 27| |typedef NS_ENUM(NSInteger, AFNetworkActivityManagerState) { 28| | AFNetworkActivityManagerStateNotActive, 29| | AFNetworkActivityManagerStateDelayingStart, 30| | AFNetworkActivityManagerStateActive, 31| | AFNetworkActivityManagerStateDelayingEnd 32| |}; 33| | 34| |static NSTimeInterval const kDefaultAFNetworkActivityManagerActivationDelay = 1.0; 35| |static NSTimeInterval const kDefaultAFNetworkActivityManagerCompletionDelay = 0.17; 36| | 37| 10|static NSURLRequest * AFNetworkRequestFromNotification(NSNotification *notification) { 38| 10| if ([[notification object] respondsToSelector:@selector(originalRequest)]) { 39| 10| return [(NSURLSessionTask *)[notification object] originalRequest]; 40| 10| } else { 41| 0| return nil; 42| 0| } 43| 10|} 44| | 45| |typedef void (^AFNetworkActivityActionBlock)(BOOL networkActivityIndicatorVisible); 46| | 47| |@interface AFNetworkActivityIndicatorManager () 48| |@property (readwrite, nonatomic, assign) NSInteger activityCount; 49| |@property (readwrite, nonatomic, strong) NSTimer *activationDelayTimer; 50| |@property (readwrite, nonatomic, strong) NSTimer *completionDelayTimer; 51| |@property (readonly, nonatomic, getter = isNetworkActivityOccurring) BOOL networkActivityOccurring; 52| |@property (nonatomic, copy) AFNetworkActivityActionBlock networkActivityActionBlock; 53| |@property (nonatomic, assign) AFNetworkActivityManagerState currentState; 54| |@property (nonatomic, assign, getter=isNetworkActivityIndicatorVisible) BOOL networkActivityIndicatorVisible; 55| | 56| |- (void)updateCurrentStateForNetworkActivityChange; 57| |@end 58| | 59| |@implementation AFNetworkActivityIndicatorManager 60| | 61| 0|+ (instancetype)sharedManager { 62| 0| static AFNetworkActivityIndicatorManager *_sharedManager = nil; 63| 0| static dispatch_once_t oncePredicate; 64| 0| dispatch_once(&oncePredicate, ^{ 65| 0| _sharedManager = [[self alloc] init]; 66| 0| }); 67| 0| 68| 0| return _sharedManager; 69| 0|} 70| | 71| 4|- (instancetype)init { 72| 4| self = [super init]; 73| 4| if (!self) { 74| 0| return nil; 75| 0| } 76| 4| self.currentState = AFNetworkActivityManagerStateNotActive; 77| 4| [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidStart:) name:AFNetworkingTaskDidResumeNotification object:nil]; 78| 4| [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidFinish:) name:AFNetworkingTaskDidSuspendNotification object:nil]; 79| 4| [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(networkRequestDidFinish:) name:AFNetworkingTaskDidCompleteNotification object:nil]; 80| 4| self.activationDelay = kDefaultAFNetworkActivityManagerActivationDelay; 81| 4| self.completionDelay = kDefaultAFNetworkActivityManagerCompletionDelay; 82| 4| 83| 4| return self; 84| 4|} 85| | 86| 4|- (void)dealloc { 87| 4| [[NSNotificationCenter defaultCenter] removeObserver:self]; 88| 4| 89| 4| [_activationDelayTimer invalidate]; 90| 4| [_completionDelayTimer invalidate]; 91| 4|} 92| | 93| 4|- (void)setEnabled:(BOOL)enabled { 94| 4| _enabled = enabled; 95| 4| if (enabled == NO) { 96| 0| [self setCurrentState:AFNetworkActivityManagerStateNotActive]; 97| 0| } 98| 4|} 99| | 100| 4|- (void)setNetworkingActivityActionWithBlock:(void (^)(BOOL networkActivityIndicatorVisible))block { 101| 4| self.networkActivityActionBlock = block; 102| 4|} 103| | 104| 13|- (BOOL)isNetworkActivityOccurring { 105| 13| @synchronized(self) { 106| 13| return self.activityCount > 0; 107| 13| } 108| 13|} 109| | 110| 8|- (void)setNetworkActivityIndicatorVisible:(BOOL)networkActivityIndicatorVisible { 111| 8| if (_networkActivityIndicatorVisible != networkActivityIndicatorVisible) { 112| 8| [self willChangeValueForKey:@"networkActivityIndicatorVisible"]; 113| 8| @synchronized(self) { 114| 8| _networkActivityIndicatorVisible = networkActivityIndicatorVisible; 115| 8| } 116| 8| [self didChangeValueForKey:@"networkActivityIndicatorVisible"]; 117| 8| if (self.networkActivityActionBlock) { 118| 8| self.networkActivityActionBlock(networkActivityIndicatorVisible); 119| 8| } else { 120| 0| [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:networkActivityIndicatorVisible]; 121| 0| } 122| 8| } 123| 8|} 124| | 125| 0|- (void)setActivityCount:(NSInteger)activityCount { 126| 0| @synchronized(self) { 127| 0| _activityCount = activityCount; 128| 0| } 129| 0| 130| 0| dispatch_async(dispatch_get_main_queue(), ^{ 131| 0| [self updateCurrentStateForNetworkActivityChange]; 132| 0| }); 133| 0|} 134| | 135| 5|- (void)incrementActivityCount { 136| 5| [self willChangeValueForKey:@"activityCount"]; 137| 5| @synchronized(self) { 138| 5| _activityCount++; 139| 5| } 140| 5| [self didChangeValueForKey:@"activityCount"]; 141| 5| 142| 5| dispatch_async(dispatch_get_main_queue(), ^{ 143| 5| [self updateCurrentStateForNetworkActivityChange]; 144| 5| }); 145| 5|} 146| | 147| 5|- (void)decrementActivityCount { 148| 5| [self willChangeValueForKey:@"activityCount"]; 149| 5| @synchronized(self) { 150| 5| _activityCount = MAX(_activityCount - 1, 0); 151| 5| } 152| 5| [self didChangeValueForKey:@"activityCount"]; 153| 5| 154| 5| dispatch_async(dispatch_get_main_queue(), ^{ 155| 5| [self updateCurrentStateForNetworkActivityChange]; 156| 5| }); 157| 5|} 158| | 159| 5|- (void)networkRequestDidStart:(NSNotification *)notification { 160| 5| if ([AFNetworkRequestFromNotification(notification) URL]) { 161| 5| [self incrementActivityCount]; 162| 5| } 163| 5|} 164| | 165| 5|- (void)networkRequestDidFinish:(NSNotification *)notification { 166| 5| if ([AFNetworkRequestFromNotification(notification) URL]) { 167| 5| [self decrementActivityCount]; 168| 5| } 169| 5|} 170| | 171| |#pragma mark - Internal State Management 172| 20|- (void)setCurrentState:(AFNetworkActivityManagerState)currentState { 173| 20| @synchronized(self) { 174| 20| if (_currentState != currentState) { 175| 16| [self willChangeValueForKey:@"currentState"]; 176| 16| _currentState = currentState; 177| 16| switch (currentState) { 178| 16| case AFNetworkActivityManagerStateNotActive: 179| 4| [self cancelActivationDelayTimer]; 180| 4| [self cancelCompletionDelayTimer]; 181| 4| [self setNetworkActivityIndicatorVisible:NO]; 182| 4| break; 183| 16| case AFNetworkActivityManagerStateDelayingStart: 184| 4| [self startActivationDelayTimer]; 185| 4| break; 186| 16| case AFNetworkActivityManagerStateActive: 187| 4| [self cancelCompletionDelayTimer]; 188| 4| [self setNetworkActivityIndicatorVisible:YES]; 189| 4| break; 190| 16| case AFNetworkActivityManagerStateDelayingEnd: 191| 4| [self startCompletionDelayTimer]; 192| 4| break; 193| 16| } 194| 16| [self didChangeValueForKey:@"currentState"]; 195| 16| } 196| 20| 197| 20| } 198| 20|} 199| | 200| 10|- (void)updateCurrentStateForNetworkActivityChange { 201| 10| if (self.enabled) { 202| 10| switch (self.currentState) { 203| 10| case AFNetworkActivityManagerStateNotActive: 204| 4| if (self.isNetworkActivityOccurring) { 205| 4| [self setCurrentState:AFNetworkActivityManagerStateDelayingStart]; 206| 4| } 207| 4| break; 208| 10| case AFNetworkActivityManagerStateDelayingStart: 209| 1| //No op. Let the delay timer finish out. 210| 1| break; 211| 10| case AFNetworkActivityManagerStateActive: 212| 5| if (!self.isNetworkActivityOccurring) { 213| 4| [self setCurrentState:AFNetworkActivityManagerStateDelayingEnd]; 214| 4| } 215| 5| break; 216| 10| case AFNetworkActivityManagerStateDelayingEnd: 217| 0| if (self.isNetworkActivityOccurring) { 218| 0| [self setCurrentState:AFNetworkActivityManagerStateActive]; 219| 0| } 220| 0| break; 221| 10| } 222| 10| } 223| 10|} 224| | 225| 4|- (void)startActivationDelayTimer { 226| 4| self.activationDelayTimer = [NSTimer 227| 4| timerWithTimeInterval:self.activationDelay target:self selector:@selector(activationDelayTimerFired) userInfo:nil repeats:NO]; 228| 4| [[NSRunLoop mainRunLoop] addTimer:self.activationDelayTimer forMode:NSRunLoopCommonModes]; 229| 4|} 230| | 231| 4|- (void)activationDelayTimerFired { 232| 4| if (self.networkActivityOccurring) { 233| 4| [self setCurrentState:AFNetworkActivityManagerStateActive]; 234| 4| } else { 235| 0| [self setCurrentState:AFNetworkActivityManagerStateNotActive]; 236| 0| } 237| 4|} 238| | 239| 4|- (void)startCompletionDelayTimer { 240| 4| [self.completionDelayTimer invalidate]; 241| 4| self.completionDelayTimer = [NSTimer timerWithTimeInterval:self.completionDelay target:self selector:@selector(completionDelayTimerFired) userInfo:nil repeats:NO]; 242| 4| [[NSRunLoop mainRunLoop] addTimer:self.completionDelayTimer forMode:NSRunLoopCommonModes]; 243| 4|} 244| | 245| 4|- (void)completionDelayTimerFired { 246| 4| [self setCurrentState:AFNetworkActivityManagerStateNotActive]; 247| 4|} 248| | 249| 4|- (void)cancelActivationDelayTimer { 250| 4| [self.activationDelayTimer invalidate]; 251| 4|} 252| | 253| 8|- (void)cancelCompletionDelayTimer { 254| 8| [self.completionDelayTimer invalidate]; 255| 8|} 256| | 257| |@end 258| | 259| |#endif /Users/travis/build/AFNetworking/AFNetworking/UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.m: 1| |// UIActivityIndicatorView+AFNetworking.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "UIActivityIndicatorView+AFNetworking.h" 23| |#import 24| | 25| |#if TARGET_OS_IOS || TARGET_OS_TV 26| | 27| |#import "AFURLSessionManager.h" 28| | 29| |@interface AFActivityIndicatorViewNotificationObserver : NSObject 30| |@property (readonly, nonatomic, weak) UIActivityIndicatorView *activityIndicatorView; 31| |- (instancetype)initWithActivityIndicatorView:(UIActivityIndicatorView *)activityIndicatorView; 32| | 33| |- (void)setAnimatingWithStateOfTask:(NSURLSessionTask *)task; 34| | 35| |@end 36| | 37| |@implementation UIActivityIndicatorView (AFNetworking) 38| | 39| 3|- (AFActivityIndicatorViewNotificationObserver *)af_notificationObserver { 40| 3| AFActivityIndicatorViewNotificationObserver *notificationObserver = objc_getAssociatedObject(self, @selector(af_notificationObserver)); 41| 3| if (notificationObserver == nil) { 42| 3| notificationObserver = [[AFActivityIndicatorViewNotificationObserver alloc] initWithActivityIndicatorView:self]; 43| 3| objc_setAssociatedObject(self, @selector(af_notificationObserver), notificationObserver, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 44| 3| } 45| 3| return notificationObserver; 46| 3|} 47| | 48| 3|- (void)setAnimatingWithStateOfTask:(NSURLSessionTask *)task { 49| 3| [[self af_notificationObserver] setAnimatingWithStateOfTask:task]; 50| 3|} 51| | 52| |@end 53| | 54| |@implementation AFActivityIndicatorViewNotificationObserver 55| | 56| |- (instancetype)initWithActivityIndicatorView:(UIActivityIndicatorView *)activityIndicatorView 57| 3|{ 58| 3| self = [super init]; 59| 3| if (self) { 60| 3| _activityIndicatorView = activityIndicatorView; 61| 3| } 62| 3| return self; 63| 3|} 64| | 65| 3|- (void)setAnimatingWithStateOfTask:(NSURLSessionTask *)task { 66| 3| NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 67| 3| 68| 3| [notificationCenter removeObserver:self name:AFNetworkingTaskDidResumeNotification object:nil]; 69| 3| [notificationCenter removeObserver:self name:AFNetworkingTaskDidSuspendNotification object:nil]; 70| 3| [notificationCenter removeObserver:self name:AFNetworkingTaskDidCompleteNotification object:nil]; 71| 3| 72| 3| if (task) { 73| 3| if (task.state != NSURLSessionTaskStateCompleted) { 74| 3| UIActivityIndicatorView *activityIndicatorView = self.activityIndicatorView; 75| 3| if (task.state == NSURLSessionTaskStateRunning) { 76| 0| [activityIndicatorView startAnimating]; 77| 3| } else { 78| 3| [activityIndicatorView stopAnimating]; 79| 3| } 80| 3| 81| 3| [notificationCenter addObserver:self selector:@selector(af_startAnimating) name:AFNetworkingTaskDidResumeNotification object:task]; 82| 3| [notificationCenter addObserver:self selector:@selector(af_stopAnimating) name:AFNetworkingTaskDidCompleteNotification object:task]; 83| 3| [notificationCenter addObserver:self selector:@selector(af_stopAnimating) name:AFNetworkingTaskDidSuspendNotification object:task]; 84| 3| } 85| 3| } 86| 3|} 87| | 88| |#pragma mark - 89| | 90| 4|- (void)af_startAnimating { 91| 4| dispatch_async(dispatch_get_main_queue(), ^{ 92| 4| [self.activityIndicatorView startAnimating]; 93| 4| }); 94| 4|} 95| | 96| 3|- (void)af_stopAnimating { 97| 3| dispatch_async(dispatch_get_main_queue(), ^{ 98| 3| [self.activityIndicatorView stopAnimating]; 99| 3| }); 100| 3|} 101| | 102| |#pragma mark - 103| | 104| 3|- (void)dealloc { 105| 3| NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 106| 3| 107| 3| [notificationCenter removeObserver:self name:AFNetworkingTaskDidCompleteNotification object:nil]; 108| 3| [notificationCenter removeObserver:self name:AFNetworkingTaskDidResumeNotification object:nil]; 109| 3| [notificationCenter removeObserver:self name:AFNetworkingTaskDidSuspendNotification object:nil]; 110| 3|} 111| | 112| |@end 113| | 114| |#endif /Users/travis/build/AFNetworking/AFNetworking/UIKit+AFNetworking/UIButton+AFNetworking.m: 1| |// UIButton+AFNetworking.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "UIButton+AFNetworking.h" 23| | 24| |#import 25| | 26| |#if TARGET_OS_IOS || TARGET_OS_TV 27| | 28| |#import "UIImageView+AFNetworking.h" 29| |#import "AFImageDownloader.h" 30| | 31| |@interface UIButton (_AFNetworking) 32| |@end 33| | 34| |@implementation UIButton (_AFNetworking) 35| | 36| |#pragma mark - 37| | 38| |static char AFImageDownloadReceiptNormal; 39| |static char AFImageDownloadReceiptHighlighted; 40| |static char AFImageDownloadReceiptSelected; 41| |static char AFImageDownloadReceiptDisabled; 42| | 43| 11|static const char * af_imageDownloadReceiptKeyForState(UIControlState state) { 44| 11| switch (state) { 45| 11| case UIControlStateHighlighted: 46| 0| return &AFImageDownloadReceiptHighlighted; 47| 11| case UIControlStateSelected: 48| 0| return &AFImageDownloadReceiptSelected; 49| 11| case UIControlStateDisabled: 50| 0| return &AFImageDownloadReceiptDisabled; 51| 11| case UIControlStateNormal: 52| 11| default: 53| 11| return &AFImageDownloadReceiptNormal; 54| 11| } 55| 11|} 56| | 57| 7|- (AFImageDownloadReceipt *)af_imageDownloadReceiptForState:(UIControlState)state { 58| 7| return (AFImageDownloadReceipt *)objc_getAssociatedObject(self, af_imageDownloadReceiptKeyForState(state)); 59| 7|} 60| | 61| |- (void)af_setImageDownloadReceipt:(AFImageDownloadReceipt *)imageDownloadReceipt 62| | forState:(UIControlState)state 63| 4|{ 64| 4| objc_setAssociatedObject(self, af_imageDownloadReceiptKeyForState(state), imageDownloadReceipt, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 65| 4|} 66| | 67| |#pragma mark - 68| | 69| |static char AFBackgroundImageDownloadReceiptNormal; 70| |static char AFBackgroundImageDownloadReceiptHighlighted; 71| |static char AFBackgroundImageDownloadReceiptSelected; 72| |static char AFBackgroundImageDownloadReceiptDisabled; 73| | 74| 16|static const char * af_backgroundImageDownloadReceiptKeyForState(UIControlState state) { 75| 16| switch (state) { 76| 16| case UIControlStateHighlighted: 77| 0| return &AFBackgroundImageDownloadReceiptHighlighted; 78| 16| case UIControlStateSelected: 79| 0| return &AFBackgroundImageDownloadReceiptSelected; 80| 16| case UIControlStateDisabled: 81| 0| return &AFBackgroundImageDownloadReceiptDisabled; 82| 16| case UIControlStateNormal: 83| 16| default: 84| 16| return &AFBackgroundImageDownloadReceiptNormal; 85| 16| } 86| 16|} 87| | 88| 10|- (AFImageDownloadReceipt *)af_backgroundImageDownloadReceiptForState:(UIControlState)state { 89| 10| return (AFImageDownloadReceipt *)objc_getAssociatedObject(self, af_backgroundImageDownloadReceiptKeyForState(state)); 90| 10|} 91| | 92| |- (void)af_setBackgroundImageDownloadReceipt:(AFImageDownloadReceipt *)imageDownloadReceipt 93| | forState:(UIControlState)state 94| 6|{ 95| 6| objc_setAssociatedObject(self, af_backgroundImageDownloadReceiptKeyForState(state), imageDownloadReceipt, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 96| 6|} 97| | 98| |@end 99| | 100| |#pragma mark - 101| | 102| |@implementation UIButton (AFNetworking) 103| | 104| 13|+ (AFImageDownloader *)sharedImageDownloader { 105| 13| 106| 13| return objc_getAssociatedObject(self, @selector(sharedImageDownloader)) ?: [AFImageDownloader defaultInstance]; 107| 13|} 108| | 109| 3|+ (void)setSharedImageDownloader:(AFImageDownloader *)imageDownloader { 110| 3| objc_setAssociatedObject(self, @selector(sharedImageDownloader), imageDownloader, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 111| 3|} 112| | 113| |#pragma mark - 114| | 115| |- (void)setImageForState:(UIControlState)state 116| | withURL:(NSURL *)url 117| 1|{ 118| 1| [self setImageForState:state withURL:url placeholderImage:nil]; 119| 1|} 120| | 121| |- (void)setImageForState:(UIControlState)state 122| | withURL:(NSURL *)url 123| | placeholderImage:(UIImage *)placeholderImage 124| 1|{ 125| 1| NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; 126| 1| [request addValue:@"image/*" forHTTPHeaderField:@"Accept"]; 127| 1| 128| 1| [self setImageForState:state withURLRequest:request placeholderImage:placeholderImage success:nil failure:nil]; 129| 1|} 130| | 131| |- (void)setImageForState:(UIControlState)state 132| | withURLRequest:(NSURLRequest *)urlRequest 133| | placeholderImage:(nullable UIImage *)placeholderImage 134| | success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success 135| | failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure 136| 2|{ 137| 2| if ([self isActiveTaskURLEqualToURLRequest:urlRequest forState:state]) { 138| 0| return; 139| 0| } 140| 2| 141| 2| [self cancelImageDownloadTaskForState:state]; 142| 2| 143| 2| AFImageDownloader *downloader = [[self class] sharedImageDownloader]; 144| 2| id imageCache = downloader.imageCache; 145| 2| 146| 2| //Use the image from the image cache if it exists 147| 2| UIImage *cachedImage = [imageCache imageforRequest:urlRequest withAdditionalIdentifier:nil]; 148| 2| if (cachedImage) { 149| 0| if (success) { 150| 0| success(urlRequest, nil, cachedImage); 151| 0| } else { 152| 0| [self setImage:cachedImage forState:state]; 153| 0| } 154| 0| [self af_setImageDownloadReceipt:nil forState:state]; 155| 2| } else { 156| 2| if (placeholderImage) { 157| 0| [self setImage:placeholderImage forState:state]; 158| 0| } 159| 2| 160| 2| __weak __typeof(self)weakSelf = self; 161| 2| NSUUID *downloadID = [NSUUID UUID]; 162| 2| AFImageDownloadReceipt *receipt; 163| 2| receipt = [downloader 164| 2| downloadImageForURLRequest:urlRequest 165| 2| withReceiptID:downloadID 166| 2| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 167| 1| __strong __typeof(weakSelf)strongSelf = weakSelf; 168| 1| if ([[strongSelf af_imageDownloadReceiptForState:state].receiptID isEqual:downloadID]) { 169| 1| if (success) { 170| 1| success(request, response, responseObject); 171| 1| } else if (responseObject) { 172| 0| [strongSelf setImage:responseObject forState:state]; 173| 0| } 174| 1| [strongSelf af_setImageDownloadReceipt:nil forState:state]; 175| 1| } 176| 1| 177| 1| } 178| 2| failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) { 179| 1| __strong __typeof(weakSelf)strongSelf = weakSelf; 180| 1| if ([[strongSelf af_imageDownloadReceiptForState:state].receiptID isEqual:downloadID]) { 181| 0| if (failure) { 182| 0| failure(request, response, error); 183| 0| } 184| 0| [strongSelf af_setImageDownloadReceipt:nil forState:state]; 185| 0| } 186| 1| }]; 187| 2| 188| 2| [self af_setImageDownloadReceipt:receipt forState:state]; 189| 2| } 190| 2|} 191| | 192| |#pragma mark - 193| | 194| |- (void)setBackgroundImageForState:(UIControlState)state 195| | withURL:(NSURL *)url 196| 2|{ 197| 2| [self setBackgroundImageForState:state withURL:url placeholderImage:nil]; 198| 2|} 199| | 200| |- (void)setBackgroundImageForState:(UIControlState)state 201| | withURL:(NSURL *)url 202| | placeholderImage:(nullable UIImage *)placeholderImage 203| 2|{ 204| 2| NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; 205| 2| [request addValue:@"image/*" forHTTPHeaderField:@"Accept"]; 206| 2| 207| 2| [self setBackgroundImageForState:state withURLRequest:request placeholderImage:placeholderImage success:nil failure:nil]; 208| 2|} 209| | 210| |- (void)setBackgroundImageForState:(UIControlState)state 211| | withURLRequest:(NSURLRequest *)urlRequest 212| | placeholderImage:(nullable UIImage *)placeholderImage 213| | success:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success 214| | failure:(nullable void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure 215| 3|{ 216| 3| if ([self isActiveBackgroundTaskURLEqualToURLRequest:urlRequest forState:state]) { 217| 0| return; 218| 0| } 219| 3| 220| 3| [self cancelBackgroundImageDownloadTaskForState:state]; 221| 3| 222| 3| AFImageDownloader *downloader = [[self class] sharedImageDownloader]; 223| 3| id imageCache = downloader.imageCache; 224| 3| 225| 3| //Use the image from the image cache if it exists 226| 3| UIImage *cachedImage = [imageCache imageforRequest:urlRequest withAdditionalIdentifier:nil]; 227| 3| if (cachedImage) { 228| 0| if (success) { 229| 0| success(urlRequest, nil, cachedImage); 230| 0| } else { 231| 0| [self setBackgroundImage:cachedImage forState:state]; 232| 0| } 233| 0| [self af_setBackgroundImageDownloadReceipt:nil forState:state]; 234| 3| } else { 235| 3| if (placeholderImage) { 236| 0| [self setBackgroundImage:placeholderImage forState:state]; 237| 0| } 238| 3| 239| 3| __weak __typeof(self)weakSelf = self; 240| 3| NSUUID *downloadID = [NSUUID UUID]; 241| 3| AFImageDownloadReceipt *receipt; 242| 3| receipt = [downloader 243| 3| downloadImageForURLRequest:urlRequest 244| 3| withReceiptID:downloadID 245| 3| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 246| 2| __strong __typeof(weakSelf)strongSelf = weakSelf; 247| 2| if ([[strongSelf af_backgroundImageDownloadReceiptForState:state].receiptID isEqual:downloadID]) { 248| 2| if (success) { 249| 1| success(request, response, responseObject); 250| 1| } else if (responseObject) { 251| 1| [strongSelf setBackgroundImage:responseObject forState:state]; 252| 1| } 253| 2| [strongSelf af_setBackgroundImageDownloadReceipt:nil forState:state]; 254| 2| } 255| 2| 256| 2| } 257| 3| failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) { 258| 1| __strong __typeof(weakSelf)strongSelf = weakSelf; 259| 1| if ([[strongSelf af_backgroundImageDownloadReceiptForState:state].receiptID isEqual:downloadID]) { 260| 0| if (failure) { 261| 0| failure(request, response, error); 262| 0| } 263| 0| [strongSelf af_setBackgroundImageDownloadReceipt:nil forState:state]; 264| 0| } 265| 1| }]; 266| 3| 267| 3| [self af_setBackgroundImageDownloadReceipt:receipt forState:state]; 268| 3| } 269| 3|} 270| | 271| |#pragma mark - 272| | 273| 3|- (void)cancelImageDownloadTaskForState:(UIControlState)state { 274| 3| AFImageDownloadReceipt *receipt = [self af_imageDownloadReceiptForState:state]; 275| 3| if (receipt != nil) { 276| 1| [[self.class sharedImageDownloader] cancelTaskForImageDownloadReceipt:receipt]; 277| 1| [self af_setImageDownloadReceipt:nil forState:state]; 278| 1| } 279| 3|} 280| | 281| 4|- (void)cancelBackgroundImageDownloadTaskForState:(UIControlState)state { 282| 4| AFImageDownloadReceipt *receipt = [self af_backgroundImageDownloadReceiptForState:state]; 283| 4| if (receipt != nil) { 284| 1| [[self.class sharedImageDownloader] cancelTaskForImageDownloadReceipt:receipt]; 285| 1| [self af_setBackgroundImageDownloadReceipt:nil forState:state]; 286| 1| } 287| 4|} 288| | 289| 2|- (BOOL)isActiveTaskURLEqualToURLRequest:(NSURLRequest *)urlRequest forState:(UIControlState)state { 290| 2| AFImageDownloadReceipt *receipt = [self af_imageDownloadReceiptForState:state]; 291| 2| return [receipt.task.originalRequest.URL.absoluteString isEqualToString:urlRequest.URL.absoluteString]; 292| 2|} 293| | 294| 3|- (BOOL)isActiveBackgroundTaskURLEqualToURLRequest:(NSURLRequest *)urlRequest forState:(UIControlState)state { 295| 3| AFImageDownloadReceipt *receipt = [self af_backgroundImageDownloadReceiptForState:state]; 296| 3| return [receipt.task.originalRequest.URL.absoluteString isEqualToString:urlRequest.URL.absoluteString]; 297| 3|} 298| | 299| | 300| |@end 301| | 302| |#endif /Users/travis/build/AFNetworking/AFNetworking/UIKit+AFNetworking/UIImageView+AFNetworking.m: 1| |// UIImageView+AFNetworking.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "UIImageView+AFNetworking.h" 23| | 24| |#import 25| | 26| |#if TARGET_OS_IOS || TARGET_OS_TV 27| | 28| |#import "AFImageDownloader.h" 29| | 30| |@interface UIImageView (_AFNetworking) 31| |@property (readwrite, nonatomic, strong, setter = af_setActiveImageDownloadReceipt:) AFImageDownloadReceipt *af_activeImageDownloadReceipt; 32| |@end 33| | 34| |@implementation UIImageView (_AFNetworking) 35| | 36| 20|- (AFImageDownloadReceipt *)af_activeImageDownloadReceipt { 37| 20| return (AFImageDownloadReceipt *)objc_getAssociatedObject(self, @selector(af_activeImageDownloadReceipt)); 38| 20|} 39| | 40| 11|- (void)af_setActiveImageDownloadReceipt:(AFImageDownloadReceipt *)imageDownloadReceipt { 41| 11| objc_setAssociatedObject(self, @selector(af_activeImageDownloadReceipt), imageDownloadReceipt, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 42| 11|} 43| | 44| |@end 45| | 46| |#pragma mark - 47| | 48| |@implementation UIImageView (AFNetworking) 49| | 50| 22|+ (AFImageDownloader *)sharedImageDownloader { 51| 22| return objc_getAssociatedObject(self, @selector(sharedImageDownloader)) ?: [AFImageDownloader defaultInstance]; 52| 22|} 53| | 54| 7|+ (void)setSharedImageDownloader:(AFImageDownloader *)imageDownloader { 55| 7| objc_setAssociatedObject(self, @selector(sharedImageDownloader), imageDownloader, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 56| 7|} 57| | 58| |#pragma mark - 59| | 60| 5|- (void)setImageWithURL:(NSURL *)url { 61| 5| [self setImageWithURL:url placeholderImage:nil]; 62| 5|} 63| | 64| |- (void)setImageWithURL:(NSURL *)url 65| | placeholderImage:(UIImage *)placeholderImage 66| 5|{ 67| 5| NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; 68| 5| [request addValue:@"image/*" forHTTPHeaderField:@"Accept"]; 69| 5| 70| 5| [self setImageWithURLRequest:request placeholderImage:placeholderImage success:nil failure:nil]; 71| 5|} 72| | 73| |- (void)setImageWithURLRequest:(NSURLRequest *)urlRequest 74| | placeholderImage:(UIImage *)placeholderImage 75| | success:(void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, UIImage *image))success 76| | failure:(void (^)(NSURLRequest *request, NSHTTPURLResponse * _Nullable response, NSError *error))failure 77| 9|{ 78| 9| if ([urlRequest URL] == nil) { 79| 2| self.image = placeholderImage; 80| 2| if (failure) { 81| 1| NSError *error = [NSError errorWithDomain:NSURLErrorDomain code:NSURLErrorBadURL userInfo:nil]; 82| 1| failure(urlRequest, nil, error); 83| 1| } 84| 2| return; 85| 2| } 86| 7| 87| 7| if ([self isActiveTaskURLEqualToURLRequest:urlRequest]) { 88| 1| return; 89| 1| } 90| 6| 91| 6| [self cancelImageDownloadTask]; 92| 6| 93| 6| AFImageDownloader *downloader = [[self class] sharedImageDownloader]; 94| 6| id imageCache = downloader.imageCache; 95| 6| 96| 6| //Use the image from the image cache if it exists 97| 6| UIImage *cachedImage = [imageCache imageforRequest:urlRequest withAdditionalIdentifier:nil]; 98| 6| if (cachedImage) { 99| 1| if (success) { 100| 1| success(urlRequest, nil, cachedImage); 101| 1| } else { 102| 0| self.image = cachedImage; 103| 0| } 104| 1| [self clearActiveDownloadInformation]; 105| 5| } else { 106| 5| if (placeholderImage) { 107| 0| self.image = placeholderImage; 108| 0| } 109| 5| 110| 5| __weak __typeof(self)weakSelf = self; 111| 5| NSUUID *downloadID = [NSUUID UUID]; 112| 5| AFImageDownloadReceipt *receipt; 113| 5| receipt = [downloader 114| 5| downloadImageForURLRequest:urlRequest 115| 5| withReceiptID:downloadID 116| 5| success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, UIImage * _Nonnull responseObject) { 117| 3| __strong __typeof(weakSelf)strongSelf = weakSelf; 118| 3| if ([strongSelf.af_activeImageDownloadReceipt.receiptID isEqual:downloadID]) { 119| 3| if (success) { 120| 1| success(request, response, responseObject); 121| 2| } else if (responseObject) { 122| 2| strongSelf.image = responseObject; 123| 2| } 124| 3| [strongSelf clearActiveDownloadInformation]; 125| 3| } 126| 3| 127| 3| } 128| 5| failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) { 129| 2| __strong __typeof(weakSelf)strongSelf = weakSelf; 130| 2| if ([strongSelf.af_activeImageDownloadReceipt.receiptID isEqual:downloadID]) { 131| 1| if (failure) { 132| 1| failure(request, response, error); 133| 1| } 134| 1| [strongSelf clearActiveDownloadInformation]; 135| 1| } 136| 2| }]; 137| 5| 138| 5| self.af_activeImageDownloadReceipt = receipt; 139| 5| } 140| 6|} 141| | 142| 7|- (void)cancelImageDownloadTask { 143| 7| if (self.af_activeImageDownloadReceipt != nil) { 144| 1| [[self.class sharedImageDownloader] cancelTaskForImageDownloadReceipt:self.af_activeImageDownloadReceipt]; 145| 1| [self clearActiveDownloadInformation]; 146| 1| } 147| 7|} 148| | 149| 6|- (void)clearActiveDownloadInformation { 150| 6| self.af_activeImageDownloadReceipt = nil; 151| 6|} 152| | 153| 7|- (BOOL)isActiveTaskURLEqualToURLRequest:(NSURLRequest *)urlRequest { 154| 7| return [self.af_activeImageDownloadReceipt.task.originalRequest.URL.absoluteString isEqualToString:urlRequest.URL.absoluteString]; 155| 7|} 156| | 157| |@end 158| | 159| |#endif /Users/travis/build/AFNetworking/AFNetworking/UIKit+AFNetworking/UIProgressView+AFNetworking.m: 1| |// UIProgressView+AFNetworking.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "UIProgressView+AFNetworking.h" 23| | 24| |#import 25| | 26| |#if TARGET_OS_IOS || TARGET_OS_TV 27| | 28| |#import "AFURLSessionManager.h" 29| | 30| |static void * AFTaskCountOfBytesSentContext = &AFTaskCountOfBytesSentContext; 31| |static void * AFTaskCountOfBytesReceivedContext = &AFTaskCountOfBytesReceivedContext; 32| | 33| |#pragma mark - 34| | 35| |@implementation UIProgressView (AFNetworking) 36| | 37| 0|- (BOOL)af_uploadProgressAnimated { 38| 0| return [(NSNumber *)objc_getAssociatedObject(self, @selector(af_uploadProgressAnimated)) boolValue]; 39| 0|} 40| | 41| 0|- (void)af_setUploadProgressAnimated:(BOOL)animated { 42| 0| objc_setAssociatedObject(self, @selector(af_uploadProgressAnimated), @(animated), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 43| 0|} 44| | 45| 0|- (BOOL)af_downloadProgressAnimated { 46| 0| return [(NSNumber *)objc_getAssociatedObject(self, @selector(af_downloadProgressAnimated)) boolValue]; 47| 0|} 48| | 49| 0|- (void)af_setDownloadProgressAnimated:(BOOL)animated { 50| 0| objc_setAssociatedObject(self, @selector(af_downloadProgressAnimated), @(animated), OBJC_ASSOCIATION_RETAIN_NONATOMIC); 51| 0|} 52| | 53| |#pragma mark - 54| | 55| |- (void)setProgressWithUploadProgressOfTask:(NSURLSessionUploadTask *)task 56| | animated:(BOOL)animated 57| 0|{ 58| 0| if (task.state == NSURLSessionTaskStateCompleted) { 59| 0| return; 60| 0| } 61| 0| 62| 0| [task addObserver:self forKeyPath:@"state" options:(NSKeyValueObservingOptions)0 context:AFTaskCountOfBytesSentContext]; 63| 0| [task addObserver:self forKeyPath:@"countOfBytesSent" options:(NSKeyValueObservingOptions)0 context:AFTaskCountOfBytesSentContext]; 64| 0| 65| 0| [self af_setUploadProgressAnimated:animated]; 66| 0|} 67| | 68| |- (void)setProgressWithDownloadProgressOfTask:(NSURLSessionDownloadTask *)task 69| | animated:(BOOL)animated 70| 0|{ 71| 0| if (task.state == NSURLSessionTaskStateCompleted) { 72| 0| return; 73| 0| } 74| 0| 75| 0| [task addObserver:self forKeyPath:@"state" options:(NSKeyValueObservingOptions)0 context:AFTaskCountOfBytesReceivedContext]; 76| 0| [task addObserver:self forKeyPath:@"countOfBytesReceived" options:(NSKeyValueObservingOptions)0 context:AFTaskCountOfBytesReceivedContext]; 77| 0| 78| 0| [self af_setDownloadProgressAnimated:animated]; 79| 0|} 80| | 81| |#pragma mark - NSKeyValueObserving 82| | 83| |- (void)observeValueForKeyPath:(NSString *)keyPath 84| | ofObject:(id)object 85| | change:(__unused NSDictionary *)change 86| | context:(void *)context 87| 0|{ 88| 0| if (context == AFTaskCountOfBytesSentContext || context == AFTaskCountOfBytesReceivedContext) { 89| 0| if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesSent))]) { 90| 0| if ([object countOfBytesExpectedToSend] > 0) { 91| 0| dispatch_async(dispatch_get_main_queue(), ^{ 92| 0| [self setProgress:[object countOfBytesSent] / ([object countOfBytesExpectedToSend] * 1.0f) animated:self.af_uploadProgressAnimated]; 93| 0| }); 94| 0| } 95| 0| } 96| 0| 97| 0| if ([keyPath isEqualToString:NSStringFromSelector(@selector(countOfBytesReceived))]) { 98| 0| if ([object countOfBytesExpectedToReceive] > 0) { 99| 0| dispatch_async(dispatch_get_main_queue(), ^{ 100| 0| [self setProgress:[object countOfBytesReceived] / ([object countOfBytesExpectedToReceive] * 1.0f) animated:self.af_downloadProgressAnimated]; 101| 0| }); 102| 0| } 103| 0| } 104| 0| 105| 0| if ([keyPath isEqualToString:NSStringFromSelector(@selector(state))]) { 106| 0| if ([(NSURLSessionTask *)object state] == NSURLSessionTaskStateCompleted) { 107| 0| @try { 108| 0| [object removeObserver:self forKeyPath:NSStringFromSelector(@selector(state))]; 109| 0| 110| 0| if (context == AFTaskCountOfBytesSentContext) { 111| 0| [object removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesSent))]; 112| 0| } 113| 0| 114| 0| if (context == AFTaskCountOfBytesReceivedContext) { 115| 0| [object removeObserver:self forKeyPath:NSStringFromSelector(@selector(countOfBytesReceived))]; 116| 0| } 117| 0| } 118| 0| @catch (NSException * __unused exception) {} 119| 0| } 120| 0| } 121| 0| } 122| 0|} 123| | 124| |@end 125| | 126| |#endif /Users/travis/build/AFNetworking/AFNetworking/UIKit+AFNetworking/UIRefreshControl+AFNetworking.m: 1| |// UIRefreshControl+AFNetworking.m 2| |// 3| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 4| |// 5| |// Permission is hereby granted, free of charge, to any person obtaining a copy 6| |// of this software and associated documentation files (the "Software"), to deal 7| |// in the Software without restriction, including without limitation the rights 8| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9| |// copies of the Software, and to permit persons to whom the Software is 10| |// furnished to do so, subject to the following conditions: 11| |// 12| |// The above copyright notice and this permission notice shall be included in 13| |// all copies or substantial portions of the Software. 14| |// 15| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21| |// THE SOFTWARE. 22| | 23| |#import "UIRefreshControl+AFNetworking.h" 24| |#import 25| | 26| |#if TARGET_OS_IOS 27| | 28| |#import "AFURLSessionManager.h" 29| | 30| |@interface AFRefreshControlNotificationObserver : NSObject 31| |@property (readonly, nonatomic, weak) UIRefreshControl *refreshControl; 32| |- (instancetype)initWithActivityRefreshControl:(UIRefreshControl *)refreshControl; 33| | 34| |- (void)setRefreshingWithStateOfTask:(NSURLSessionTask *)task; 35| | 36| |@end 37| | 38| |@implementation UIRefreshControl (AFNetworking) 39| | 40| 3|- (AFRefreshControlNotificationObserver *)af_notificationObserver { 41| 3| AFRefreshControlNotificationObserver *notificationObserver = objc_getAssociatedObject(self, @selector(af_notificationObserver)); 42| 3| if (notificationObserver == nil) { 43| 3| notificationObserver = [[AFRefreshControlNotificationObserver alloc] initWithActivityRefreshControl:self]; 44| 3| objc_setAssociatedObject(self, @selector(af_notificationObserver), notificationObserver, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 45| 3| } 46| 3| return notificationObserver; 47| 3|} 48| | 49| 3|- (void)setRefreshingWithStateOfTask:(NSURLSessionTask *)task { 50| 3| [[self af_notificationObserver] setRefreshingWithStateOfTask:task]; 51| 3|} 52| | 53| |@end 54| | 55| |@implementation AFRefreshControlNotificationObserver 56| | 57| |- (instancetype)initWithActivityRefreshControl:(UIRefreshControl *)refreshControl 58| 3|{ 59| 3| self = [super init]; 60| 3| if (self) { 61| 3| _refreshControl = refreshControl; 62| 3| } 63| 3| return self; 64| 3|} 65| | 66| 3|- (void)setRefreshingWithStateOfTask:(NSURLSessionTask *)task { 67| 3| NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 68| 3| 69| 3| [notificationCenter removeObserver:self name:AFNetworkingTaskDidResumeNotification object:nil]; 70| 3| [notificationCenter removeObserver:self name:AFNetworkingTaskDidSuspendNotification object:nil]; 71| 3| [notificationCenter removeObserver:self name:AFNetworkingTaskDidCompleteNotification object:nil]; 72| 3| 73| 3| if (task) { 74| 3| UIRefreshControl *refreshControl = self.refreshControl; 75| 3| if (task.state == NSURLSessionTaskStateRunning) { 76| 0| [refreshControl beginRefreshing]; 77| 0| 78| 0| [notificationCenter addObserver:self selector:@selector(af_beginRefreshing) name:AFNetworkingTaskDidResumeNotification object:task]; 79| 0| [notificationCenter addObserver:self selector:@selector(af_endRefreshing) name:AFNetworkingTaskDidCompleteNotification object:task]; 80| 0| [notificationCenter addObserver:self selector:@selector(af_endRefreshing) name:AFNetworkingTaskDidSuspendNotification object:task]; 81| 3| } else { 82| 3| [refreshControl endRefreshing]; 83| 3| } 84| 3| } 85| 3|} 86| | 87| |#pragma mark - 88| | 89| 0|- (void)af_beginRefreshing { 90| 0| dispatch_async(dispatch_get_main_queue(), ^{ 91| 0| [self.refreshControl beginRefreshing]; 92| 0| }); 93| 0|} 94| | 95| 0|- (void)af_endRefreshing { 96| 0| dispatch_async(dispatch_get_main_queue(), ^{ 97| 0| [self.refreshControl endRefreshing]; 98| 0| }); 99| 0|} 100| | 101| |#pragma mark - 102| | 103| 3|- (void)dealloc { 104| 3| NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 105| 3| 106| 3| [notificationCenter removeObserver:self name:AFNetworkingTaskDidCompleteNotification object:nil]; 107| 3| [notificationCenter removeObserver:self name:AFNetworkingTaskDidResumeNotification object:nil]; 108| 3| [notificationCenter removeObserver:self name:AFNetworkingTaskDidSuspendNotification object:nil]; 109| 3|} 110| | 111| |@end 112| | 113| |#endif /Users/travis/build/AFNetworking/AFNetworking/UIKit+AFNetworking/UIWebView+AFNetworking.m: 1| |// UIWebView+AFNetworking.m 2| |// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ ) 3| |// 4| |// Permission is hereby granted, free of charge, to any person obtaining a copy 5| |// of this software and associated documentation files (the "Software"), to deal 6| |// in the Software without restriction, including without limitation the rights 7| |// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8| |// copies of the Software, and to permit persons to whom the Software is 9| |// furnished to do so, subject to the following conditions: 10| |// 11| |// The above copyright notice and this permission notice shall be included in 12| |// all copies or substantial portions of the Software. 13| |// 14| |// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15| |// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16| |// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17| |// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18| |// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19| |// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20| |// THE SOFTWARE. 21| | 22| |#import "UIWebView+AFNetworking.h" 23| | 24| |#import 25| | 26| |#if TARGET_OS_IOS 27| | 28| |#import "AFHTTPSessionManager.h" 29| |#import "AFURLResponseSerialization.h" 30| |#import "AFURLRequestSerialization.h" 31| | 32| |@interface UIWebView (_AFNetworking) 33| |@property (readwrite, nonatomic, strong, setter = af_setURLSessionTask:) NSURLSessionDataTask *af_URLSessionTask; 34| |@end 35| | 36| |@implementation UIWebView (_AFNetworking) 37| | 38| 9|- (NSURLSessionDataTask *)af_URLSessionTask { 39| 9| return (NSURLSessionDataTask *)objc_getAssociatedObject(self, @selector(af_URLSessionTask)); 40| 9|} 41| | 42| 6|- (void)af_setURLSessionTask:(NSURLSessionDataTask *)af_URLSessionTask { 43| 6| objc_setAssociatedObject(self, @selector(af_URLSessionTask), af_URLSessionTask, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 44| 6|} 45| | 46| |@end 47| | 48| |#pragma mark - 49| | 50| |@implementation UIWebView (AFNetworking) 51| | 52| 3|- (AFHTTPSessionManager *)sessionManager { 53| 3| static AFHTTPSessionManager *_af_defaultHTTPSessionManager = nil; 54| 3| static dispatch_once_t onceToken; 55| 3| dispatch_once(&onceToken, ^{ 56| 1| _af_defaultHTTPSessionManager = [[AFHTTPSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; 57| 1| _af_defaultHTTPSessionManager.requestSerializer = [AFHTTPRequestSerializer serializer]; 58| 1| _af_defaultHTTPSessionManager.responseSerializer = [AFHTTPResponseSerializer serializer]; 59| 1| }); 60| 3| 61| 3| return objc_getAssociatedObject(self, @selector(sessionManager)) ?: _af_defaultHTTPSessionManager; 62| 3|} 63| | 64| 0|- (void)setSessionManager:(AFHTTPSessionManager *)sessionManager { 65| 0| objc_setAssociatedObject(self, @selector(sessionManager), sessionManager, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 66| 0|} 67| | 68| 0|- (AFHTTPResponseSerializer *)responseSerializer { 69| 0| static AFHTTPResponseSerializer *_af_defaultResponseSerializer = nil; 70| 0| static dispatch_once_t onceToken; 71| 0| dispatch_once(&onceToken, ^{ 72| 0| _af_defaultResponseSerializer = [AFHTTPResponseSerializer serializer]; 73| 0| }); 74| 0| 75| 0| return objc_getAssociatedObject(self, @selector(responseSerializer)) ?: _af_defaultResponseSerializer; 76| 0|} 77| | 78| 0|- (void)setResponseSerializer:(AFHTTPResponseSerializer *)responseSerializer { 79| 0| objc_setAssociatedObject(self, @selector(responseSerializer), responseSerializer, OBJC_ASSOCIATION_RETAIN_NONATOMIC); 80| 0|} 81| | 82| |#pragma mark - 83| | 84| |- (void)loadRequest:(NSURLRequest *)request 85| | progress:(NSProgress * _Nullable __autoreleasing * _Nullable)progress 86| | success:(NSString * (^)(NSHTTPURLResponse *response, NSString *HTML))success 87| | failure:(void (^)(NSError *error))failure 88| 3|{ 89| 3| [self loadRequest:request MIMEType:nil textEncodingName:nil progress:progress success:^NSData *(NSHTTPURLResponse *response, NSData *data) { 90| 3| NSStringEncoding stringEncoding = NSUTF8StringEncoding; 91| 3| if (response.textEncodingName) { 92| 2| CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)response.textEncodingName); 93| 2| if (encoding != kCFStringEncodingInvalidId) { 94| 2| stringEncoding = CFStringConvertEncodingToNSStringEncoding(encoding); 95| 2| } 96| 2| } 97| 3| 98| 3| NSString *string = [[NSString alloc] initWithData:data encoding:stringEncoding]; 99| 3| if (success) { 100| 3| string = success(response, string); 101| 3| } 102| 3| 103| 3| return [string dataUsingEncoding:stringEncoding]; 104| 3| } failure:failure]; 105| 3|} 106| | 107| |- (void)loadRequest:(NSURLRequest *)request 108| | MIMEType:(NSString *)MIMEType 109| | textEncodingName:(NSString *)textEncodingName 110| | progress:(NSProgress * _Nullable __autoreleasing * _Nullable)progress 111| | success:(NSData * (^)(NSHTTPURLResponse *response, NSData *data))success 112| | failure:(void (^)(NSError *error))failure 113| 3|{ 114| 3| NSParameterAssert(request); 115| 3| 116| 3| if (self.af_URLSessionTask.state == NSURLSessionTaskStateRunning || self.af_URLSessionTask.state == NSURLSessionTaskStateSuspended) { 117| 3| [self.af_URLSessionTask cancel]; 118| 3| } 119| 3| self.af_URLSessionTask = nil; 120| 3| 121| 3| __weak __typeof(self)weakSelf = self; 122| 3| __block NSURLSessionDataTask *dataTask; 123| 3| dataTask = [self.sessionManager 124| 3| dataTaskWithRequest:request 125| 3| uploadProgress:nil 126| 3| downloadProgress:nil 127| 3| completionHandler:^(NSURLResponse * _Nonnull response, id _Nonnull responseObject, NSError * _Nullable error) { 128| 3| __strong __typeof(weakSelf) strongSelf = weakSelf; 129| 3| if (error) { 130| 0| if (failure) { 131| 0| failure(error); 132| 0| } 133| 3| } else { 134| 3| if (success) { 135| 3| success((NSHTTPURLResponse *)response, responseObject); 136| 3| } 137| 3| [strongSelf loadData:responseObject MIMEType:MIMEType textEncodingName:textEncodingName baseURL:[dataTask.currentRequest URL]]; 138| 3| 139| 3| if ([strongSelf.delegate respondsToSelector:@selector(webViewDidFinishLoad:)]) { 140| 0| [strongSelf.delegate webViewDidFinishLoad:strongSelf]; 141| 0| } 142| 3| } 143| 3| }]; 144| 3| self.af_URLSessionTask = dataTask; 145| 3| if (progress != nil) { 146| 0| *progress = [self.sessionManager downloadProgressForTask:dataTask]; 147| 0| } 148| 3| [self.af_URLSessionTask resume]; 149| 3| 150| 3| if ([self.delegate respondsToSelector:@selector(webViewDidStartLoad:)]) { 151| 0| [self.delegate webViewDidStartLoad:self]; 152| 0| } 153| 3|} 154| | 155| |@end 156| | 157| |#endif <<<<<< EOF # path=fixes ./Framework/AFNetworking.h:21,23,26,29,31,34,37,42,46,49,59,65,66 ./Example/Today Extension Example/TodayViewController.m:22,28,35,37,40,44,45,48,49,53,56,59,60,64,65,67,68,71,75,78,79,83,84,86,91,92,96,97,102,103,105,106 ./Example/Today Extension Example/TodayViewController.h:22,24,26 ./Example/macOS Example/AppDelegate.h:22,24,26,30 ./Example/macOS Example/main.m:21,23,26 ./Example/macOS Example/AppDelegate.m:22,25,28,30,34,36,44,45,48,52,53,56,58,60,61 ./Example/Classes/Models/Post.h:22,24,26,28,31,33,35,37,39 ./Example/Classes/Models/User.m:22,27,29,34,39,41,46,47,51,53,54,57,58,60,62,73,99,100,102,104,106,111,112,117,118,122,124,125,128,129 ./Example/Classes/Models/Post.m:22,25,27,29,34,35,38,40,42,43,45,53,54,57,61,63,64,66,68,73,74,79,80,84,86,87,90,91 ./Example/Classes/Models/User.h:22,24,26,28,32,36,38,40 ./Example/Classes/Networking Extensions/AFAppDotNetAPIClient.m:22,24,26,28,36,38,39 ./Example/Classes/Networking Extensions/AFAppDotNetAPIClient.h:22,25,27,29 ./Example/iOS Example/AppDelegate.h:22,24,26,29 ./Example/iOS Example/AppDelegate.m:22,25,27,29,31,34,36,40,45,47,48 ./Example/iOS Example/Controllers/GlobalTimelineViewController.m:22,24,26,28,30,34,36,39,44,46,48,49,51,54,56,60,62,64,65,67,70,72,73,76,78,82,83,85,87,88,90,93,95,96,99,101,102 ./Example/iOS Example/Controllers/GlobalTimelineViewController.h:22,24,26 ./Example/iOS Example/Views/PostTableViewCell.m:22,24,27,29,31,34,38,39,45,47,48,51,55,57,58,61,62,66,67,69,72,75,80,81 ./Example/iOS Example/Views/PostTableViewCell.h:22,24,26,28,30,32 ./Example/main.m:21,25,30,31,34,37 ./Example/tvOS Example/AFNetworking tvOS Example-Bridging-Header.h:4 ./Example/watchOS Example Extension/ExtensionDelegate.m:21,23,25,28,29,32,33,37,38 ./Example/watchOS Example Extension/InterfaceController.m:21,23,24,26,28,29,31,34,36,37,41,42,46,47,49,50,51 ./Example/watchOS Example Extension/ExtensionDelegate.h:21,23,25 ./Example/watchOS Example Extension/InterfaceController.h:21,24,26 ./Tests/Tests/AFImageResponseSerializerTests.m:21,25,27,29,31,33,38,48,49,50,52,55,56,60,68,73,74,75,79,85,91,96,97 ./Tests/Tests/AFHTTPRequestSerializationTests.m:21,23,25,29,32,36,48,52,54,58,60,64,65,67,71,74,77,80,81,85,88,91,94,95,99,101,102,107,108,112,114,115,119,121,122,129,132,135,137,138,143,145,147,149,151,152,154,159,160,164,165,168,170,174,177,182,183,192,193,202,204,209,212,213,214,215,217,220,221,224,225,228,234,235,242,243 ./Tests/Tests/AFPropertyListRequestSerializerTests.m:21,23,25,29,31,35,36,38,43,45,46,51,54,55 ./Tests/Tests/AFUIButtonTests.m:21,26,31,33,36,38,44,46,48,50,51,55,56,57,64,68,70,71,85,89,90,104,108,109 ./Tests/Tests/AFHTTPResponseSerializationTests.m:21,23,25,29,31,35,36,38,43,45,48,51,52,56,58,61,64,66,67,71,73,76,79,80,85,87,90,93,94,103,104,111,112,115,116 ./Tests/Tests/AFNetworkActivityManagerTests.m:21,23,26,31,33,35,38,40,43,44,48,51,52,54,58,66,68,77,80,81,85,93,95,107,108,110,113,127,129,139,144,145,149,157,159,168,170,178,180,182,184,185,186 ./Tests/Tests/AFNetworkReachabilityManagerTests.m:21,23,27,32,34,37,41,42,44,47,49,50,54,56,57,60,63,64,68,69,73,74,76,86,88,90,91,94,95,98,99,101,103,110,112,114,117,118,119,122,123,126,127,135,137,139,140 ./Tests/Tests/AFImageDownloaderTests.m:21,24,29,35,37,45,46,53,54,56,60,61,68,69,71,90,91,94,97,104,106,108,111,112,117,124,126,130,137,139,141,144,147,148,153,160,162,166,173,175,177,180,181,186,189,196,201,202,203,209,216,218,220,224,231,233,235,240,241,245,255,259,266,268,270,274,281,283,285,290,291,294,304,308,315,317,319,323,325,330,337,339,341,346,347,355,357,359,361,367,369,371,374,375,378,388,390,392,396,406,408,410,414,417,420,422,423,425,439,442,443,448,455,457,470,475,476,485,492,499,500,510,511,513,514,524,528,529,543,544,546,556,557,559,561,563,567,570,571,572,577,578 ./Tests/Tests/AFXMLDocumentResponseSerializerTests.m:21,23,26,28,31,32,34,38,40,42,46,47,52,54,55,60,62,63,68,70,71,76,79,80,85,87,88,92,99,100 ./Tests/Tests/AFURLSessionManagerTests.m:21,23,25,27,33,34,39,41,46,47,52,64,67,68,69,75,78,79,81,84,92,93,95,98,99,102,108,118,119,128,129,134,135,141,145,152,159,160,162,165,167,168,170,172,174,175,180,181,185,187,196,197,201,202,207,208,212,219,222,225,226,228,251,253,254,257,264,265,272,273,281,282,283,291,292,293,300,301,308,309,320,321,322,333,334,335,342,343,350,351,359,360,361,369,370,371,378,379,387,388,396,397,405,406,413,414,421,422,429,430,441,442,443,457,458,459,470,471,472,474,484,485,495,496,499,500,503,504,507,508,513,514,517,518,521,522,526,531,538,540 ./Tests/Tests/AFTestCase.h:21,23,25,31,33,36 ./Tests/Tests/AFAutoPurgingImageCacheTests.m:21,24,29,31,36,39,40,41,42,48,49,51,55,58,59,64,67,68,74,77,78,84,87,88,93,98,99,104,107,109,113,114,116,124,125,134,135,145,146,155,156,166,167,174,175,182,183,199,201,202,203,212,213,221,229,230,231,232,240 ./Tests/Tests/AFCompoundResponseSerializerTests.m:21,25,27,29,31,35,36,40,41,43,45,49,55,58,61,62,69,78,79,92,93 ./Tests/Tests/AFXMLParserResponseSerializerTests.m:21,23,26,29,30,32,36,38,40,44,45,50,52,53,58,60,61,66,68,69,74,77,78,82,87,88 ./Tests/Tests/AFPropertyListResponseSerializerTests.m:21,23,25,29,31,35,36,38,41,45,47,48,51,55,58,59,64,67,68,74,82,83,92,93 ./Tests/Tests/AFHTTPSessionManagerTests.m:21,23,26,30,32,36,37,42,43,47,48,50,54,56,64,66,68,72,73,76,78,85,87,89,92,93,97,99,106,110,111,114,116,118,122,123,129,135,151,152,158,165,176,177,180,184,187,201,202,204,207,208,212,213,223,224,226,230,231,233,243,244,248,249,254,255,257,265,266,270,271,276,277,279,286,290,291,295,296,298,309,310,315,316,321,322,332,333,338,339,344,345,354,358,359,364,365,367,377,380,381,394,395,407,411,412,414,425,428,429,439,442,443,455,458,459,471,478,481,482,493,496,497,508,511,512,523,525,527,528,530,541,545,546,557,561,562,575,580,584,585,586,598,602,603,614,618,619,631,635,636,649,655,659,660,671,675,676,687,691,692,703,707,708,710,726,727,729,734,735,740,741,746,747,752,753,758,759,764,765,770,771,776,777,779,795,803,804,820,828,829 ./Tests/Tests/AFSecurityPolicyTests.m:21,24,26,28,36,37,42,44,45,49,51,52,56,58,59,64,66,67,72,74,75,80,82,83,88,90,91,96,98,99,104,106,107,112,114,115,118,123,125,126,128,131,135,136,140,141,145,146,150,151,153,158,159,164,165,167,173,174,179,180,183,187,188,192,199,201,202,206,210,211,214,218,219,222,226,227,230,240,241,242,245,251,252,255,259,260,262,267,268,271,275,276,279,283,284,287,293,294,297,301,302,306,313,315,316,320,324,325,328,332,333,336,340,341,344,354,355,356,359,365,366,369,373,374,376,381,382,385,389,390,393,397,398,401,407,408,411,416,417,420,425,427,428,431,436,438,439,441,445,446,449,454,456,457,460,464,467,469,470,477,479,480,485,488,490,491,493,496,499,501,502,509,511,512,519,521,522,527,530,532,533,540,547,548,554,559,562,568,569 ./Tests/Tests/AFJSONSerializationTests.m:21,23,26,29,30,32,36,38,41,42,44,49,51,53,55,56,61,63,65,67,68,71,75,78,79,84,90,91,93,95,99,101,105,106,108,111,114,116,117,122,124,125,130,132,133,138,140,141,146,149,150,155,157,158,166,167,175,176,183,193,194,200,207,208 ./Tests/Tests/AFUIImageViewTests.m:21,25,30,32,34,36,38,44,46,48,50,51,55,56,57,65,66,75,76,80,89,90,100,103,114,120,121,134,138,139,162,163,169,170,171,172,173 ./Tests/Tests/AFUIRefreshControlTests.m:21,25,31,33,39,40,45,46,57,60,64,65,81,84,88,89,105,108,114,115 ./Tests/Tests/AFTestCase.m:21,23,25,29,30,33,34,36,40,41,44,45,48,49,52,53,56,57,60,61,64,65 ./Tests/Tests/AFUIActivityIndicatorViewTests.m:21,25,31,33,39,40,45,46,57,60,64,65,66,82,85,89,90,106,109,115,116 ./Tests/Tests/AFUIWebViewTests.m:21,25,27,30,32,34,39,40,49,52,53,62,65,66,83,94,99,102,103 ./UIKit+AFNetworking/UIProgressView+AFNetworking.m:21,23,25,27,29,32,34,36,39,40,43,44,47,48,51,52,54,57,60,61,64,66,67,70,73,74,77,79,80,82,87,94,95,96,102,103,104,109,112,113,116,117,119,120,121,122,123,125 ./UIKit+AFNetworking/UIButton+AFNetworking.h:21,23,25,27,29,31,33,36,40,44,47,51,56,60,63,65,71,74,76,84,87,89,91,103,104,108,111,113,119,122,124,132,135,137,139,151,152,156,159,163,166,170,172,174 ./UIKit+AFNetworking/UIRefreshControl+AFNetworking.m:22,25,27,29,33,35,37,39,45,47,48,51,52,54,56,58,62,64,65,68,72,77,83,84,85,86,88,93,94,99,100,102,105,109,110,112 ./UIKit+AFNetworking/UIImageView+AFNetworking.h:21,23,25,27,29,31,33,38,42,45,49,54,58,61,63,65,69,72,74,76,82,85,87,89,99,104,106,108 ./UIKit+AFNetworking/AFImageDownloader.h:21,23,25,29,31,36,41,46,52,56,61,66,71,76,79,83,88,91,95,98,100,104,107,112,119,122,126,130,137,140,144,149,157,160,162,166,168,170 ./UIKit+AFNetworking/AFNetworkActivityIndicatorManager.m:21,23,26,33,36,42,43,44,46,55,58,60,67,69,70,75,82,84,85,88,91,92,97,98,99,102,103,107,108,109,115,121,122,123,124,128,129,133,134,139,141,145,146,151,153,157,158,162,163,164,168,169,170,193,195,196,197,198,199,206,214,219,221,222,223,224,229,230,236,237,238,243,244,247,248,251,252,255,256,258 ./UIKit+AFNetworking/AFAutoPurgingImageCache.h:21,24,27,29,34,37,42,45,47,51,54,58,61,63,68,69,74,77,81,85,88,94,97,100,104,107,110,114,116,121,126,131,136,139,143,147,150,154,156,158,160 ./UIKit+AFNetworking/UIWebView+AFNetworking.h:21,23,25,27,29,31,33,36,40,45,48,58,61,75,77,79 ./UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.h:21,23,25,27,29,34,38,41,45,47 ./UIKit+AFNetworking/UIImage+AFNetworking.h:24,26,28,30,32,34 ./UIKit+AFNetworking/UIProgressView+AFNetworking.h:21,23,25,27,29,31,32,37,41,44,50,53,59,61,63 ./UIKit+AFNetworking/UIImageView+AFNetworking.m:21,23,25,27,29,33,35,38,39,42,43,45,47,49,52,53,56,57,59,62,63,66,69,71,72,77,83,85,86,89,90,92,95,103,108,109,123,125,126,127,133,135,137,139,140,141,146,147,148,151,152,155,156,158 ./UIKit+AFNetworking/UIKit+AFNetworking.h:22,25,28,36 ./UIKit+AFNetworking/UIRefreshControl+AFNetworking.h:22,24,26,28,30,32,37,41,44,48,50,52 ./UIKit+AFNetworking/UIButton+AFNetworking.m:21,23,25,27,30,33,35,37,42,54,55,56,59,60,63,65,66,68,73,85,86,87,90,91,94,96,97,99,101,103,105,107,108,111,112,114,117,119,120,124,127,129,130,136,139,140,142,145,153,158,159,173,175,176,177,183,185,187,189,190,191,193,196,198,199,203,206,208,209,215,218,219,221,224,232,237,238,252,254,255,256,262,264,266,268,269,270,272,278,279,280,286,287,288,292,293,297,298,299,301 ./UIKit+AFNetworking/UIActivityIndicatorView+AFNetworking.m:21,24,26,28,32,34,36,38,44,46,47,50,51,53,55,57,61,63,64,67,71,79,80,84,85,86,87,89,94,95,100,101,103,106,110,111,113 ./UIKit+AFNetworking/UIWebView+AFNetworking.m:21,23,25,27,31,35,37,40,41,44,45,47,49,51,60,62,63,66,67,74,76,77,80,81,83,88,95,96,97,101,102,105,106,113,115,118,120,132,136,138,141,142,147,149,152,153,154,156 ./UIKit+AFNetworking/AFAutoPurgingImageCache.m:21,23,25,27,29,35,37,39,44,50,52,53,57,58,62,63,64,66,72,74,77,78,84,87,93,94,96,97,100,101,108,109,113,117,118,122,130,132,138,139,141,143,144,153,156,157,165,168,169,177,178,181,182,185,186,189,190,195,197,198,201,202,204 ./UIKit+AFNetworking/AFNetworkActivityIndicatorManager.h:21,23,25,27,29,31,34,36,38,40,46,49,53,58,61,63,65,68,72,74,77,81,86,91,94,98,100,102 ./UIKit+AFNetworking/AFImageDownloader.m:21,23,25,28,34,36,44,46,47,50,51,53,59,61,63,70,72,73,76,77,80,81,83,85,90,92,93,95,97,100,103,106,108,110,112,122,126,127,130,132,135,140,142,143,147,148,152,157,158,165,169,173,176,179,180,182,183,191,192,197,198,212,214,215,223,224,236,238,240,243,244,249,266,267,271,272,278,279,280,281,282,287,298,304,305,312,313,314,322,333,334,335,339,341,342,349,350,356,357,362,364,365,374,375,376,378,379,383,384,393,394,395,401,402,405,406,413,414,416 ./AFNetworking/AFSecurityPolicy.h:21,24,30,33,36,38,40,45,48,50,54,59,64,68,71,75,79,82,86,90,93,95,99,102,105,109,113,116,118,121,126,128,130,134,137,139,144,145,148,151 ./AFNetworking/AFNetworkReachabilityManager.h:21,23,26,33,35,38,40,42,46,51,56,61,66,70,75,78,82,85,87,91,94,96,100,103,105,109,114,119,123,128,133,137,142,146,149,153,155,159,162,164,170,171,174,177,180,183,185,187,192,196,200,205,209,214 ./AFNetworking/AFURLSessionManager.h:21,22,24,32,35,37,39,41,43,45,49,51,57,59,64,66,70,72,74,76,78,80,82,85,88,90,92,97,102,105,109,113,118,123,129,133,138,143,148,153,157,162,167,171,174,176,180,184,187,189,193,196,200,203,208,212,215,221,224,234,238,241,246,253,256,266,269,277,281,284,289,296,299,309,313,316,318,322,325,327,331,335,338,342,345,349,353,356,360,363,367,370,374,377,381,384,388,391,400,403,407,410,414,417,421,424,428,431,435,439,442,446,449,453,456,460,462,466,471,476,481,486,491,496,501,506,511,516,521 ./AFNetworking/AFURLRequestSerialization.h:21,24,30,32,38,42,44,48,51,53,57,60,64,67,71,77,79,81,83,88,90,93,97,102,105,109,112,116,119,123,126,130,133,137,140,144,148,151,154,158,163,166,172,175,177,181,184,190,195,199,204,207,209,213,216,220,224,227,229,234,241,244,246,252,260,263,267,269,275,277,279,284,287,289,293,299,302,308,316,319,331,334,344,347,351,354,355,358,364,367,369,375,377,379,384,389,392,396,398,400,405,410,415,418,421,426,428,430,434,437,439,441,443,448,451,453,455,457,462,465,467,469,472,478 ./AFNetworking/AFURLResponseSerialization.m:21,23,25,33,37,41,42,45,46,49,51,52,58,59,61,62,69,70,71,81,82,83,85,86,88,89,91,94,95,100,101,104,106,107,109,113,116,120,129,130,132,133,135,136,143,146,147,149,151,152,153,156,157,159,160,162,166,168,170,171,173,176,177,182,183,186,188,189,193,194,196,201,203,204,206,208,210,213,214,218,220,221,226,227,229,231,232,234,238,242,243,244,248,251,252,254,256,258,261,263,264,267,268,270,271,273,278,279,282,284,285,288,291,292,294,299,301,302,304,306,308,311,313,314,319,320,322,324,325,327,331,335,336,337,339,340,342,344,346,348,351,352,356,358,359,364,365,367,369,370,372,376,380,381,382,385,387,390,392,393,395,396,398,403,404,406,408,409,412,414,415,417,421,423,424,426,428,430,432,435,436,439,443,445,446,451,452,454,456,457,459,463,467,468,469,472,473,475,477,479,482,484,485,487,488,490,495,496,499,501,502,505,508,509,511,516,518,519,521,523,527,531,533,535,542,547,548,550,555,556,558,559,563,564,567,572,576,581,582,583,584,586,591,592,596,597,598,602,605,607,608,614,625,627,628,630,632,635,637,638,641,643,645,648,650,652,653,655,660,661,663,671,673,674,676,680,684,685,686,692,698,701,703,704,706,711,712,720,723,725,726,729,734,735,737,740,745,747,748,750,752,756,758,762,764,765,767,771,775,776,782,783,785,786,787,789,790,792,797,798,800,802,803,806,808,809,811,815,817,818 ./AFNetworking/AFHTTPSessionManager.m:21,23,26,30,36,42,46,49,52,53,56,57,60,61,64,65,68,72,73,77,78,80,83,85,86,88,91,93,94,97,99,100,102,110,113,114,116,117,119,124,125,127,128,134,135,137,138,145,146,155,157,159,160,165,167,168,174,178,180,182,184,185,190,192,193,199,201,202,209,211,213,215,216,222,224,225,232,234,235,242,247,253,254,256,257,262,266,267,269,271,273,274,279,281,282,288,290,292,294,295,300,302,303,309,311,313,315,316,321,323,324,330,332,334,336,337,346,351,357,358,360,361,370,374,375,377,379,380,382,385,386,388,391,392,404,405,406,410,411,417,418,420,421,424,430,434,435,437,440,445,446 ./AFNetworking/AFURLResponseSerialization.h:21,24,26,31,34,38,41,45,51,53,55,58,62,64,66,71,75,78,82,87,90,92,96,102,104,106,107,110,112,116,120,122,127,132,135,139,141,143,146,148,153,155,157,159,162,164,169,171,176,179,183,185,187,189,192,194,198,200,205,210,213,219,221,223,226,228,241,247,253,255,257,262,267,270,274,276,280,283,285,287,289,294,297,299,302,304,307,312,314 ./AFNetworking/AFURLSessionManager.m:21,24,30,37,39,40,50,51,52,53,60,62,63,70,72,73,79,86,88,90,93,97,104,109,114,116,117,119,135,137,142,143,147,150,165,169,170,175,177,178,182,183,185,190,191,195,196,197,198,200,204,206,208,211,218,219,224,225,227,232,233,236,240,241,250,253,254,257,258,261,262,266,267,273,274,275,281,283,285,289,292,294,295,300,303,304,306,311,314,315,319,322,323,327,329,334,337,338,339,340,341,343,345,354,359,360,363,364,367,369,371,373,379,392,396,415,423,425,426,429,430,431,435,438,439,442,443,444,448,449,454,457,458,459,464,467,468,470,472,499,501,504,505,510,511,514,515,517,520,522,524,528,530,533,536,540,541,544,545,548,550,552,553,556,557,559,561,565,566,568,569,571,572,575,576,584,585,586,587,595,596,597,598,600,603,608,610,611,614,617,622,623,628,632,635,638,639,643,647,649,651,653,654,659,663,668,669,671,673,675,676,679,684,685,687,700,701,704,706,708,709,712,713,716,717,720,721,724,725,727,730,731,737,740,741,742,744,747,749,750,755,756,760,761,763,766,768,769,774,779,781,783,784,786,791,795,800,801,803,808,809,811,812,817,822,824,826,827,831,836,838,840,841,843,848,853,855,857,858,863,868,870,872,873,877,878,881,882,884,887,888,891,892,896,898,900,903,904,907,908,911,912,915,916,919,920,924,926,928,931,932,935,936,939,940,943,944,946,949,950,953,954,957,958,960,963,964,972,976,978,980,981,983,986,989,990,992,993,997,1000,1011,1014,1017,1018,1019,1022,1023,1024,1026,1032,1034,1037,1038,1041,1042,1043,1048,1051,1061,1064,1065,1066,1069,1070,1071,1075,1077,1082,1083,1086,1087,1088,1094,1095,1101,1102,1103,1105,1108,1109,1112,1113,1114,1118,1120,1124,1126,1127,1130,1131,1132,1137,1142,1143,1146,1147,1149,1151,1156,1158,1161,1162,1165,1166,1167,1171,1176,1177,1180,1181,1182,1186,1187,1190,1193,1194,1195,1200,1202,1205,1206,1209,1210,1211,1218,1219,1221,1223,1227,1234,1237,1238,1240,1241,1242,1245,1246,1247,1253,1254,1256,1259,1260,1263,1264,1265,1270,1271,1273,1276,1277,1280,1281,1282,1284,1287,1288,1291,1295,1296,1298,1299,1302,1303,1305,1308,1309 ./AFNetworking/AFURLRequestSerialization.m:21,23,29,32,34,40,50,53,56,58,61,65,68,72,74,75,77,78,80,84,86,89,91,96,97,100,102,103,109,110,111,113,115,118,123,124,126,127,130,131,134,136,144,145,150,155,158,159,161,162,164,168,171,173,180,182,183,185,193,195,198,199,204,205,207,210,219,236,237,239,240,243,248,249,250,252,253,258,259,260,261,263,266,271,272,277,278,283,284,289,290,295,296,301,302,304,311,312,315,319,320,327,328,331,335,336,341,342,344,348,349,352,353,355,360,363,365,367,370,374,375,376,378,380,381,387,390,392,394,404,405,408,409,410,411,414,415,417,418,422,425,429,433,436,439,444,445,450,451,454,455,456,459,464,466,469,471,472,474,478,480,482,486,488,494,498,499,501,507,508,509,510,514,519,522,524,525,527,528,530,534,535,537,538,543,549,550,551,552,554,557,558,563,564,567,569,570,576,577,579,587,589,590,592,594,597,598,600,603,604,607,608,611,612,620,621,622,625,633,636,639,643,650,655,657,664,666,669,673,674,679,681,682,684,686,687,691,694,697,699,700,706,711,716,717,723,724,726,727,731,732,736,744,746,747,753,757,761,767,769,771,772,777,781,785,787,788,791,793,796,798,799,802,804,811,813,814,817,820,821,825,826,830,833,835,836,838,840,845,854,861,866,867,871,873,874,880,881,884,885,886,889,890,893,894,896,899,902,903,905,910,919,922,923,924,925,926,928,929,932,934,935,938,939,941,945,946,948,951,952,955,956,959,960,963,965,966,970,974,979,980,982,983,985,989,993,998,999,1001,1004,1007,1008,1010,1012,1013,1015,1017,1024,1029,1030,1036,1038,1043,1044,1046,1048,1049,1054,1055,1056,1067,1068,1069,1071,1072,1077,1079,1081,1082,1085,1088,1091,1093,1096,1098,1099,1104,1105,1118,1119,1120,1123,1125,1129,1130,1134,1135,1138,1144,1147,1148,1149,1150,1154,1155,1157,1158,1162,1165,1167,1170,1171,1173,1174,1181,1182,1200,1202,1204,1205,1207,1210,1216,1218,1219,1221,1223,1225,1228,1229,1231,1234,1236,1237,1239,1243,1245,1248,1249,1251,1255,1257,1261,1262,1267,1269,1270,1272,1275,1276,1278,1279,1281,1282,1284,1289,1290,1292,1294,1295,1298,1300,1301,1303,1307,1309,1310,1312,1314,1316,1319,1320,1323,1327,1329,1330,1332,1336,1338,1341,1342,1344,1348,1350,1354,1355,1357,1360,1361,1363,1364,1366,1367,1369,1374,1375,1378,1380,1381,1384,1387,1388,1390,1395,1397,1398 ./AFNetworking/AFNetworking.h:22,26,29,33,37,40 ./AFNetworking/AFNetworkReachabilityManager.m:21,24,30,33,36,48,49,50,57,61,65,69,70,72,73,88,93,94,97,98,99,102,103,107,108,109,115,117,124,126,127,130,132,134,136,137,141,143,145,146,148,161,162,167,168,171,173,174,176,181,182,185,188,189,190,192,195,196,199,200,203,204,206,209,212,213,217,221,222,225,229,234,236,237,241,242,244,245,247,250,251,253,256,257,259,263,264,266,267 ./AFNetworking/AFSecurityPolicy.m:21,23,25,29,31,33,37,38,40,42,49,50,57,60,64,66,70,71,74,75,78,79,81,82,87,89,92,93,97,101,102,104,105,112,115,118,121,123,127,128,131,132,134,136,138,139,141,146,148,151,156,157,159,160,168,170,171,175,177,178,181,182,186,188,190,191,196,197,199,201,202,205,212,214,218,219,220,222,225,237,238,244,245,247,252,253,259,261,264,265,268,272,273,274,276,280,285,286,287,289,290,293,294,296,297,299,302,303,305,308,309,311,315,316,321,323,324,330,331,333,340,342,343 ./AFNetworking/AFCompatibilityMacros.h:21,24,30,36,42 ./AFNetworking/AFHTTPSessionManager.h:21,27,33,35,38,40,42,44,46,48,50,52,54,56,58,60,68,70,73,75,77,82,85,89,92,96,100,105,109,114,117,119,123,126,128,131,136,140,143,148,155,156,159,165,173,176,183,192,195,200,207,210,216,224,227,232,239,242,248,256,259,266,275,278,284,292,295,302,313,321,331,334,339,346,349,355,363,366,371,378,381,387,395,398,403,410,413,419,427,429 ./build/AFNetworking.build/Debug-iphonesimulator/AFNetworking iOS.build/DerivedSources/AFNetworking_vers.c:3 ./build/AFNetworking.build/Debug-iphonesimulator/AFNetworking iOS Tests.build/DerivedSources/AFNetworking iOS Tests_vers.c:3 <<<<<< EOF