├── .gitignore ├── .travis.yml ├── CHANGELOG.md ├── Categories ├── NSString+Qiniu.h └── NSString+Qiniu.m ├── Qiniu.podspec ├── QiniuDemo ├── QiniuDemo.xcodeproj │ └── project.pbxproj └── QiniuDemo │ ├── Base.lproj │ └── Main.storyboard │ ├── Images.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ └── LaunchImage.launchimage │ │ └── Contents.json │ ├── QiniuDemo-Info.plist │ ├── QiniuDemo-Prefix.pch │ ├── QiniuDemoAppDelegate.h │ ├── QiniuDemoAppDelegate.m │ ├── QiniuDemoViewController.h │ ├── QiniuDemoViewController.m │ ├── en.lproj │ └── InfoPlist.strings │ └── main.m ├── QiniuSDK.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ └── contents.xcworkspacedata └── xcshareddata │ └── xcschemes │ └── QiniuSDKTests.xcscheme ├── QiniuSDK ├── AFNetworking │ ├── AFHTTPRequestOperation.h │ ├── AFHTTPRequestOperation.m │ ├── AFHTTPRequestOperationManager.h │ ├── AFHTTPRequestOperationManager.m │ ├── AFHTTPSessionManager.h │ ├── AFHTTPSessionManager.m │ ├── AFNetworkReachabilityManager.h │ ├── AFNetworkReachabilityManager.m │ ├── AFNetworking.h │ ├── AFSecurityPolicy.h │ ├── AFSecurityPolicy.m │ ├── AFURLConnectionOperation.h │ ├── AFURLConnectionOperation.m │ ├── AFURLRequestSerialization.h │ ├── AFURLRequestSerialization.m │ ├── AFURLResponseSerialization.h │ ├── AFURLResponseSerialization.m │ ├── AFURLSessionManager.h │ └── AFURLSessionManager.m ├── QiniuBlkputRet.h ├── QiniuBlkputRet.m ├── QiniuConfig.h ├── QiniuConfig.m ├── QiniuHttpClient.h ├── QiniuHttpClient.m ├── QiniuResumableClient.h ├── QiniuResumableClient.m ├── QiniuResumableUploader.h ├── QiniuResumableUploader.m ├── QiniuSDK-Prefix.pch ├── QiniuSimpleUploader.h ├── QiniuSimpleUploader.m ├── QiniuUploadDelegate.h ├── QiniuUtils.h └── QiniuUtils.m ├── QiniuSDKTests ├── QiniuSDKTests-Info.plist ├── QiniuSDKTests.h ├── QiniuSDKTests.m └── en.lproj │ └── InfoPlist.strings └── README.md /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | .DS_Store 3 | */build/* 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | profile 14 | *.moved-aside 15 | DerivedData 16 | .idea/ 17 | *.hmap 18 | *.xccheckout 19 | 20 | #CocoaPods 21 | Pods 22 | 23 | # Go Compiled Object files, Static and Dynamic libs (Shared Objects) 24 | *.o 25 | *.a 26 | *.so 27 | 28 | # Folders 29 | _obj 30 | _test 31 | 32 | # Architecture specific extensions/prefixes 33 | *.[568vq] 34 | [568vq].out 35 | 36 | *.out 37 | *.pyc 38 | *.jar 39 | *.cgo1.go 40 | *.cgo2.c 41 | _cgo_defun.c 42 | _cgo_gotypes.go 43 | _cgo_export.* 44 | 45 | _testmain.go 46 | 47 | *.exe 48 | *.class 49 | python/qbox/config.weico.py 50 | fopext/go/demo/fopext_demo 51 | 2_output_s.jpg 52 | 2_thumb_s.jpg 53 | 2.jpg 54 | 55 | # rcov generated 56 | coverage 57 | 58 | # rdoc generated 59 | rdoc 60 | 61 | # bundler 62 | .bundle 63 | 64 | # jeweler generated 65 | pkg 66 | 67 | # Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore: 68 | # 69 | # * Create a file at ~/.gitignore 70 | # * Include files you want ignored 71 | # * Run: git config --global core.excludesfile ~/.gitignore 72 | # 73 | # After doing this, these files will be ignored in all your git projects, 74 | # saving you from having to 'pollute' every project you touch with them 75 | # 76 | # Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line) 77 | # 78 | # For MacOS: 79 | # 80 | .DS_Store 81 | 82 | # For vim: 83 | *.swp 84 | QiniuDemo/QiniuDemo.xcodeproj/xcuserdata 85 | QiniuSDK.xcworkspace 86 | QiniuSDK/QiniuSDK.xcodeproj/xcuserdata 87 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | xcode_project: QiniuSDK.xcodeproj 3 | xcode_scheme: QiniuSDKTests 4 | xcode_sdk: 5 | - iphonesimulator7.1 6 | before_install: 7 | - brew update 8 | - brew upgrade xctool 9 | - gem install cocoapods 10 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## CHANGE LOG 2 | 3 | ### v6.3.3 4 | 5 | - [#101] 升级AFNetworking 6 | 7 | ### v6.3.2 8 | 9 | - [#94] 上传进度指示调整 10 | 11 | ### v6.3.1 12 | 13 | - [#81] uploadfiledatawithoutkey 14 | - [#85] UA 增加client id 15 | - [#86] 使用自带base64库,解决iOS6 兼容问题 16 | - [#87] 升级到AFNetworking 2.3.1 17 | - [#89] 修正demo未下载就上传崩溃问题 18 | 19 | ### v6.3.0 20 | 21 | - [#77] 多host上传重试 22 | - [#79] 支持NSData 上传 23 | 24 | ### v6.2.8 25 | 26 | - [#74] fop url escape 27 | - [#75] 统一user agent 格式 28 | 29 | ### v6.2.7 30 | 31 | - [#63] 添加额外错误信息 32 | - [#64] mkfile 支持 key 为 nil 33 | - [#65] 修正 传入的blockComplete在第一次运行的退出时被释放,如果失败重试会变成nil,导致出错 34 | - [#70] 修改上传域名为upload.qiniu.com 35 | - [#72] operation.responseObject 返回增加nil 判断 36 | 37 | ### v6.2.6 38 | 39 | - [#61] 错误信息增加reqid 40 | 41 | ### v6.2.5 42 | 43 | - [#50] update AFN 2.2.3 44 | - [#52] bugfix: 701 retry 45 | 46 | ### v6.2.2 47 | 48 | 2014-04-09 issue [#44](https://github.com/qiniu/ios-sdk/pull/44) 49 | 50 | - [#43] AFNetworking升级到2.2.1 51 | 52 | ### v6.2.1 53 | 54 | 2014-04-03 issue [#41](https://github.com/qiniu/ios-sdk/pull/41) 55 | 56 | - [#28] NSString qiniu category 57 | - [#38] 更新配置,引入Travis 58 | - [#39] bugfix 增加@optional 调用时的判断 59 | 60 | ### v6.2.0 61 | 62 | 2014-03-04 issue [#37](https://github.com/qiniu/ios-sdk/pull/37) 63 | 64 | - Replace ASIHttpRequest with AFNetwork2.0.3 65 | - 老的基于 ASIHttpRequest 的代码,建立了 ASIHttpRequest 分支,独立演化。 66 | 67 | 68 | ### v6.0.0 69 | 70 | 2013-07-04 issue [#17](https://github.com/qiniu/ios-sdk/pull/17) 71 | 72 | - 遵循 [sdkspec v6.0.3](https://github.com/qiniu/sdkspec/tree/v6.0.3)。 73 | 74 | 75 | ### v3.3.0 76 | 77 | 2013-06-28 issue [#14](https://github.com/qiniu/ios-sdk/pull/14) 78 | 79 | - error 类型增加 `X-Log`, `X-Reqid`。 80 | 81 | -------------------------------------------------------------------------------- /Categories/NSString+Qiniu.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Qiniu.h 3 | // find 4 | // 5 | // Created by qq30135878 on 11/1/13. 6 | // Copyright (c) 2013 zhangbin. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | //注意Qiniu的width,height,size是用的px,不是pt,Retina屏幕需要乘2,假设需要请求填满当前view的一张图片,需要CGSizeMake(self.view.bounds.size.width * 2, self.view.bounds.size.height * 2) 12 | 13 | @interface NSString (Qiniu) 14 | 15 | - (NSString *)qnImageInfo; 16 | - (NSString *)qnEXIF; 17 | 18 | //基于原图大小,按照指定的百分比进行缩放。 19 | //http://qiniuphotos.qiniudn.com/gogopher.jpg?imageMogr/v2/thumbnail/!50p 20 | - (NSString *)qnScaleToPercent:(CGFloat)percent; 21 | 22 | //限定缩略图宽度,高度等比自适应。 23 | //http://qiniuphotos.qiniudn.com/gogopher.jpg?imageMogr/v2/thumbnail/200 24 | - (NSString *)qnScaleFitWidth:(CGFloat)width; 25 | 26 | //限定缩略图高度,宽度等比自适应。 27 | //http://qiniuphotos.qiniudn.com/gogopher.jpg?imageMogr/v2/thumbnail/x100 28 | - (NSString *)qnScaleFitHeight:(CGFloat)height; 29 | 30 | //限定长边,短边自适应,将缩略图的大小限定在指定的宽高矩形内。若指定的宽度大于指定的高度,以指定的高度为基准,宽度自适应等比缩放;若指定的宽度小于指定的高度,以指定的宽度为基准,高度自适应等比缩放。 31 | //http://qiniuphotos.qiniudn.com/gogopher.jpg?imageMogr/v2/thumbnail/100x200 32 | - (NSString *)qnScaleAspectFit:(CGSize)size; 33 | 34 | 35 | //限定短边,长边自适应,目标缩略图大小会超出指定的宽高矩形。若指定的宽度大于指定的高度,以指定的宽度为基准,高度自适应等比缩放;若指定的宽度小于指定的高度,以指定的高度为基准,宽度自适应等比缩放。 36 | //http://qiniuphotos.qiniudn.com/gogopher.jpg?imageMogr/v2/thumbnail/100x200^ 37 | - (NSString *)qnScaleAspectFill:(CGSize)size; 38 | 39 | 40 | //限定缩略图宽和高。缩略图按照指定的宽和高强行缩略,忽略原图宽和高的比例,可能会变形。 41 | //http://qiniuphotos.qiniudn.com/gogopher.jpg?imageMogr/v2/thumbnail/100x200! 42 | - (NSString *)qnScaleToFill:(CGSize)size; 43 | 44 | //从图片中心裁剪成size大小 45 | //http://qiniuphotos.qiniudn.com/gogopher.jpg?imageMogr/v2/gravity/center/crop/!256x256 46 | - (NSString *)qnCropFromCenterToSize:(CGSize)size; 47 | @end 48 | -------------------------------------------------------------------------------- /Categories/NSString+Qiniu.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSString+Qiniu.m 3 | // find 4 | // 5 | // Created by qq30135878 on 11/1/13. 6 | // Copyright (c) 2013 zhangbin. All rights reserved. 7 | // 8 | 9 | #import "NSString+Qiniu.h" 10 | 11 | @implementation NSString (Qiniu) 12 | 13 | - (NSString *)qnImageInfo 14 | { 15 | return [[NSString stringWithFormat:@"%@?imageInfo", self] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 16 | } 17 | 18 | - (NSString *)qnEXIF 19 | { 20 | return [[NSString stringWithFormat:@"%@?exif", self] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 21 | } 22 | 23 | - (NSString *)qnScaleToPercent:(CGFloat)percent 24 | { 25 | return [[NSString stringWithFormat:@"%@?imageMogr/v2/thumbnail/!%fp", self, percent] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 26 | } 27 | 28 | - (NSString *)qnScaleFitWidth:(CGFloat)width 29 | { 30 | return [[NSString stringWithFormat:@"%@?imageMogr/v2/thumbnail/%f", self, width] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 31 | } 32 | 33 | - (NSString *)qnScaleFitHeight:(CGFloat)height 34 | { 35 | return [[NSString stringWithFormat:@"%@?imageMogr/v2/thumbnail/x%f", self, height] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 36 | } 37 | 38 | - (NSString *)qnScaleAspectFit:(CGSize)size 39 | { 40 | return [[NSString stringWithFormat:@"%@?imageMogr/v2/thumbnail/%fx%f", self, size.width, size.height] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 41 | } 42 | 43 | - (NSString *)qnScaleAspectFill:(CGSize)size 44 | { 45 | return [[NSString stringWithFormat:@"%@?imageMogr/v2/thumbnail/%fx%f^", self, size.width, size.height] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 46 | } 47 | 48 | - (NSString *)qnScaleToFill:(CGSize)size 49 | { 50 | return [[NSString stringWithFormat:@"%@?imageMogr/v2/thumbnail/%fx%f!", self, size.width, size.height] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 51 | } 52 | 53 | - (NSString *)qnCropFromCenterToSize:(CGSize)size 54 | { 55 | return [[NSString stringWithFormat:@"%@?imageMogr/v2/gravity/center/crop/!%fx%f", self, size.width, size.height] stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]; 56 | } 57 | 58 | @end 59 | -------------------------------------------------------------------------------- /Qiniu.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | s.name = 'Qiniu' 3 | s.version = '6.3.3.1' 4 | s.summary = 'Qiniu Resource Storage SDK for iOS' 5 | s.homepage = 'https://github.com/qiniu/legacy-ios-sdk' 6 | s.social_media_url = 'http://weibo.com/qiniutek' 7 | s.author = 'Qiniu => sdk@qiniu.com' 8 | s.documentation_url = 'http://developer.qiniu.com/docs/v6/sdk/ios-sdk.html' 9 | s.source = {:git => 'https://github.com/qiniu/ios-sdk.git', :tag => 'v6.3.3.1'} 10 | 11 | s.platform = :ios, '6.0' 12 | s.ios.deployment_target = '6.0' 13 | 14 | s.source_files = 'QiniuSDK/**/*.{h,m}' 15 | s.requires_arc = true 16 | 17 | s.license = { :type => 'MIT', :text => <<-LICENSE 18 | The MIT License (MIT) 19 | 20 | Copyright (c) 2012-2014 qiniu.com 21 | 22 | Permission is hereby granted, free of charge, to any person obtaining a copy 23 | of this software and associated documentation files (the "Software"), to deal 24 | in the Software without restriction, including without limitation the rights 25 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 26 | copies of the Software, and to permit persons to whom the Software is 27 | furnished to do so, subject to the following conditions: 28 | 29 | The above copyright notice and this permission notice shall be included in 30 | all copies or substantial portions of the Software. 31 | 32 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 33 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 34 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 35 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 36 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 37 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 38 | THE SOFTWARE. 39 | LICENSE 40 | } 41 | 42 | end 43 | -------------------------------------------------------------------------------- /QiniuDemo/QiniuDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 29 | 39 | 49 | 50 | 51 | 52 | 53 | Lorem ipsum dolor sit er elit lamet, consectetaur cillium adipisicing pecu, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Nam liber te conscient to factor tum poen legum odioque civiuda. 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 71 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | -------------------------------------------------------------------------------- /QiniuDemo/QiniuDemo/Images.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /QiniuDemo/QiniuDemo/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | } 18 | ], 19 | "info" : { 20 | "version" : 1, 21 | "author" : "xcode" 22 | } 23 | } -------------------------------------------------------------------------------- /QiniuDemo/QiniuDemo/QiniuDemo-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | Qiniu.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /QiniuDemo/QiniuDemo/QiniuDemo-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_5_0 10 | #warning "This project uses features only available in iOS SDK 5.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /QiniuDemo/QiniuDemo/QiniuDemoAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // QiniuDemoAppDelegate.h 3 | // QiniuDemo 4 | // 5 | // Created by ltz on 14-2-28. 6 | // Copyright (c) 2014年 Qiniu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface QiniuDemoAppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /QiniuDemo/QiniuDemo/QiniuDemoAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // QiniuDemoAppDelegate.m 3 | // QiniuDemo 4 | // 5 | // Created by ltz on 14-2-28. 6 | // Copyright (c) 2014年 Qiniu. All rights reserved. 7 | // 8 | 9 | #import "QiniuDemoAppDelegate.h" 10 | 11 | @implementation QiniuDemoAppDelegate 12 | 13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions 14 | { 15 | // Override point for customization after application launch. 16 | return YES; 17 | } 18 | 19 | - (void)applicationWillResignActive:(UIApplication *)application 20 | { 21 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 22 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 23 | } 24 | 25 | - (void)applicationDidEnterBackground:(UIApplication *)application 26 | { 27 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 28 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 29 | } 30 | 31 | - (void)applicationWillEnterForeground:(UIApplication *)application 32 | { 33 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | - (void)applicationDidBecomeActive:(UIApplication *)application 37 | { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application 42 | { 43 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 44 | } 45 | 46 | @end 47 | -------------------------------------------------------------------------------- /QiniuDemo/QiniuDemo/QiniuDemoViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // QiniuDemoViewController.h 3 | // QiniuDemo 4 | // 5 | // Created by ltz on 14-2-28. 6 | // Copyright (c) 2014年 Qiniu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "QiniuSimpleUploader.h" 11 | #import "QiniuResumableUploader.h" 12 | 13 | @interface QiniuDemoViewController : UIViewController 14 | 15 | 16 | @property (retain, nonatomic)QiniuRioPutExtra *extra; 17 | @property (retain, nonatomic)QiniuResumableUploader *rUploader; 18 | @property (retain, nonatomic)QiniuSimpleUploader *sUploader; 19 | @property (copy, nonatomic)NSString *filePath; 20 | @property (copy, nonatomic)NSString *lastResumableKey; 21 | @property (copy, nonatomic)NSString *token; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /QiniuDemo/QiniuDemo/QiniuDemoViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // QiniuDemoViewController.m 3 | // QiniuDemo 4 | // 5 | // Created by ltz on 14-2-28. 6 | // Copyright (c) 2014年 Qiniu. All rights reserved. 7 | // 8 | 9 | #import "QiniuDemoViewController.h" 10 | 11 | @interface QiniuDemoViewController () 12 | 13 | @property (weak, nonatomic) IBOutlet UITextField *downloadUrl; 14 | 15 | @property (strong, nonatomic) IBOutlet UIView *progress; 16 | @property (weak, nonatomic) IBOutlet UITextView *msg; 17 | 18 | @end 19 | 20 | @implementation QiniuDemoViewController 21 | 22 | - (IBAction)resumeUpload:(id)sender { 23 | if (self.extra != nil) { 24 | [self.rUploader uploadFile:self.filePath key:self.lastResumableKey extra:self.extra]; 25 | } 26 | } 27 | 28 | - (IBAction)stopResumableUpload:(id)sender { 29 | if (self.extra != nil) { 30 | [self.extra cancelTasks]; 31 | } 32 | } 33 | 34 | 35 | - (IBAction)resumableUpload:(id)sender { 36 | 37 | self.extra = [QiniuRioPutExtra extraWithParams:[NSDictionary dictionaryWithObject:@"haha" forKey:@"x:cus"]]; 38 | self.lastResumableKey = [NSString stringWithFormat:@"test-%@", [self timeString]]; 39 | [self.rUploader uploadFile:self.filePath key: self.lastResumableKey extra:self.extra]; 40 | } 41 | 42 | - (IBAction)simpleUpload:(id)sender { 43 | if (_filePath == nil) { 44 | return; 45 | } 46 | 47 | [self.sUploader uploadFile:_filePath key:[NSString stringWithFormat:@"test-%@.png", [self timeString]] extra:nil]; 48 | } 49 | 50 | - (IBAction)download:(id)sender { 51 | 52 | self.filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:[self timeString]]; 53 | NSLog(@"%@", self.filePath); 54 | NSFileManager *fileManager = [NSFileManager defaultManager]; 55 | if (![fileManager fileExistsAtPath:self.filePath]) 56 | { 57 | self.msg.text = [@"start download\n" stringByAppendingString:self.msg.text]; 58 | NSURL *url = [NSURL URLWithString:self.downloadUrl.text]; 59 | NSData *data = [NSData dataWithContentsOfURL:url]; 60 | [data writeToFile:self.filePath atomically:TRUE]; 61 | } 62 | NSString *msg = [NSString stringWithFormat:@"Download %@ success\n", self.downloadUrl.text]; 63 | self.msg.text = [msg stringByAppendingString:self.msg.text]; 64 | } 65 | 66 | // Upload progress 67 | - (void)uploadProgressUpdated:(NSString *)theFilePath percent:(float)percent 68 | { 69 | NSString *progressStr = [NSString stringWithFormat:@"Progress Updated: - %f\n", percent]; 70 | 71 | self.msg.text = [progressStr stringByAppendingString:self.msg.text]; 72 | } 73 | 74 | - (void)uploadSucceeded:(NSString *)theFilePath ret:(NSDictionary *)ret 75 | { 76 | NSString *succeedMsg = [NSString stringWithFormat:@"Upload Succeeded: - Ret: %@\n", ret]; 77 | 78 | self.msg.text = [succeedMsg stringByAppendingString:self.msg.text]; 79 | } 80 | 81 | // Upload failed 82 | - (void)uploadFailed:(NSString *)theFilePath error:(NSError *)error 83 | { 84 | NSString *failMsg = [NSString stringWithFormat:@"Upload Failed: %@ - Reason: %@", theFilePath, error]; 85 | 86 | self.msg.text = [failMsg stringByAppendingString:self.msg.text]; 87 | } 88 | 89 | - (void)setProgressPercent:(float)percent 90 | { 91 | 92 | } 93 | 94 | - (BOOL)textFieldShouldReturn:(UITextField *)textField 95 | { 96 | [textField resignFirstResponder]; 97 | 98 | return YES; 99 | } 100 | 101 | - (NSString *) timeString { 102 | NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 103 | [formatter setDateFormat: @"yyyy-MM-dd-HH-mm-ss-zzz"]; 104 | return [formatter stringFromDate:[NSDate date]]; 105 | } 106 | 107 | - (void)viewDidLoad 108 | { 109 | [super viewDidLoad]; 110 | // Do any additional setup after loading the view, typically from a nib. 111 | self.msg.text = @"OK, let's start\nPlease download first"; 112 | self.msg.scrollEnabled = YES; 113 | self.msg.editable = NO; 114 | 115 | self.token = @"6UOyH0xzsnOF-uKmsHgpi7AhGWdfvI8glyYV3uPg:m-8jeXMWC-4kstLEHEMCfZAZnWc=:eyJkZWFkbGluZSI6MTQyNDY4ODYxOCwic2NvcGUiOiJ0ZXN0MzY5In0="; 116 | 117 | self.sUploader = [QiniuSimpleUploader uploaderWithToken:self.token]; 118 | self.sUploader.delegate = self; 119 | 120 | self.rUploader = [[QiniuResumableUploader alloc] initWithToken:self.token]; 121 | self.rUploader.delegate = self; 122 | 123 | self.downloadUrl.delegate = self; 124 | 125 | //self.downloadUrl.text = @"http://127.0.0.1:9200/ori.mp4"; 126 | self.downloadUrl.text = @"http://qiniuphotos.qiniudn.com/gogopher.jpg"; 127 | } 128 | 129 | - (void)didReceiveMemoryWarning 130 | { 131 | [super didReceiveMemoryWarning]; 132 | // Dispose of any resources that can be recreated. 133 | } 134 | 135 | @end 136 | -------------------------------------------------------------------------------- /QiniuDemo/QiniuDemo/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /QiniuDemo/QiniuDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // QiniuDemo 4 | // 5 | // Created by ltz on 14-2-28. 6 | // Copyright (c) 2014年 Qiniu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "QiniuDemoAppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([QiniuDemoAppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /QiniuSDK.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /QiniuSDK.xcodeproj/xcshareddata/xcschemes/QiniuSDKTests.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 52 | 53 | 54 | 55 | 61 | 62 | 64 | 65 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /QiniuSDK/AFNetworking/AFHTTPRequestOperation.h: -------------------------------------------------------------------------------- 1 | // AFHTTPRequestOperation.h 2 | // 3 | // Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) 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 24 | #import "AFURLConnectionOperation.h" 25 | 26 | /** 27 | `AFHTTPRequestOperation` is a subclass of `AFURLConnectionOperation` for requests using the HTTP or HTTPS protocols. It encapsulates the concept of acceptable status codes and content types, which determine the success or failure of a request. 28 | */ 29 | @interface AFHTTPRequestOperation : AFURLConnectionOperation 30 | 31 | ///------------------------------------------------ 32 | /// @name Getting HTTP URL Connection Information 33 | ///------------------------------------------------ 34 | 35 | /** 36 | The last HTTP response received by the operation's connection. 37 | */ 38 | @property (readonly, nonatomic, strong) NSHTTPURLResponse *response; 39 | 40 | /** 41 | Responses sent from the server in data tasks created with `dataTaskWithRequest:success:failure:` and run using the `GET` / `POST` / et al. convenience methods are automatically validated and serialized by the response serializer. By default, this property is set to an AFHTTPResponse serializer, which uses the raw data as its response object. The serializer validates the status code to be in the `2XX` range, denoting success. If the response serializer generates an error in `-responseObjectForResponse:data:error:`, the `failure` callback of the session task or request operation will be executed; otherwise, the `success` callback will be executed. 42 | 43 | @warning `responseSerializer` must not be `nil`. Setting a response serializer will clear out any cached value 44 | */ 45 | @property (nonatomic, strong) AFHTTPResponseSerializer * responseSerializer; 46 | 47 | /** 48 | An object constructed by the `responseSerializer` from the response and response data. Returns `nil` unless the operation `isFinished`, has a `response`, and has `responseData` with non-zero content length. If an error occurs during serialization, `nil` will be returned, and the `error` property will be populated with the serialization error. 49 | */ 50 | @property (readonly, nonatomic, strong) id responseObject; 51 | 52 | ///----------------------------------------------------------- 53 | /// @name Setting Completion Block Success / Failure Callbacks 54 | ///----------------------------------------------------------- 55 | 56 | /** 57 | Sets the `completionBlock` property with a block that executes either the specified success or failure block, depending on the state of the request on completion. If `error` returns a value, which can be caused by an unacceptable status code or content type, then `failure` is executed. Otherwise, `success` is executed. 58 | 59 | This method should be overridden in subclasses in order to specify the response object passed into the success block. 60 | 61 | @param success The block to be executed on the completion of a successful request. This block has no return value and takes two arguments: the receiver operation and the object constructed from the response data of the request. 62 | @param failure The block to be executed on the completion of an unsuccessful request. This block has no return value and takes two arguments: the receiver operation and the error that occurred during the request. 63 | */ 64 | - (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success 65 | failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure; 66 | 67 | @end 68 | -------------------------------------------------------------------------------- /QiniuSDK/AFNetworking/AFHTTPRequestOperation.m: -------------------------------------------------------------------------------- 1 | // AFHTTPRequestOperation.m 2 | // 3 | // Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) 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 "AFHTTPRequestOperation.h" 24 | 25 | static dispatch_queue_t http_request_operation_processing_queue() { 26 | static dispatch_queue_t af_http_request_operation_processing_queue; 27 | static dispatch_once_t onceToken; 28 | dispatch_once(&onceToken, ^{ 29 | af_http_request_operation_processing_queue = dispatch_queue_create("com.alamofire.networking.http-request.processing", DISPATCH_QUEUE_CONCURRENT); 30 | }); 31 | 32 | return af_http_request_operation_processing_queue; 33 | } 34 | 35 | static dispatch_group_t http_request_operation_completion_group() { 36 | static dispatch_group_t af_http_request_operation_completion_group; 37 | static dispatch_once_t onceToken; 38 | dispatch_once(&onceToken, ^{ 39 | af_http_request_operation_completion_group = dispatch_group_create(); 40 | }); 41 | 42 | return af_http_request_operation_completion_group; 43 | } 44 | 45 | #pragma mark - 46 | 47 | @interface AFURLConnectionOperation () 48 | @property (readwrite, nonatomic, strong) NSURLRequest *request; 49 | @property (readwrite, nonatomic, strong) NSURLResponse *response; 50 | @end 51 | 52 | @interface AFHTTPRequestOperation () 53 | @property (readwrite, nonatomic, strong) NSHTTPURLResponse *response; 54 | @property (readwrite, nonatomic, strong) id responseObject; 55 | @property (readwrite, nonatomic, strong) NSError *responseSerializationError; 56 | @property (readwrite, nonatomic, strong) NSRecursiveLock *lock; 57 | @end 58 | 59 | @implementation AFHTTPRequestOperation 60 | @dynamic lock; 61 | 62 | - (instancetype)initWithRequest:(NSURLRequest *)urlRequest { 63 | self = [super initWithRequest:urlRequest]; 64 | if (!self) { 65 | return nil; 66 | } 67 | 68 | self.responseSerializer = [AFHTTPResponseSerializer serializer]; 69 | 70 | return self; 71 | } 72 | 73 | - (void)setResponseSerializer:(AFHTTPResponseSerializer *)responseSerializer { 74 | NSParameterAssert(responseSerializer); 75 | 76 | [self.lock lock]; 77 | _responseSerializer = responseSerializer; 78 | self.responseObject = nil; 79 | self.responseSerializationError = nil; 80 | [self.lock unlock]; 81 | } 82 | 83 | - (id)responseObject { 84 | [self.lock lock]; 85 | if (!_responseObject && [self isFinished] && !self.error) { 86 | NSError *error = nil; 87 | self.responseObject = [self.responseSerializer responseObjectForResponse:self.response data:self.responseData error:&error]; 88 | if (error) { 89 | self.responseSerializationError = error; 90 | } 91 | } 92 | [self.lock unlock]; 93 | 94 | return _responseObject; 95 | } 96 | 97 | - (NSError *)error { 98 | if (_responseSerializationError) { 99 | return _responseSerializationError; 100 | } else { 101 | return [super error]; 102 | } 103 | } 104 | 105 | #pragma mark - AFHTTPRequestOperation 106 | 107 | - (void)setCompletionBlockWithSuccess:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success 108 | failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure 109 | { 110 | // completionBlock is manually nilled out in AFURLConnectionOperation to break the retain cycle. 111 | #pragma clang diagnostic push 112 | #pragma clang diagnostic ignored "-Warc-retain-cycles" 113 | #pragma clang diagnostic ignored "-Wgnu" 114 | self.completionBlock = ^{ 115 | if (self.completionGroup) { 116 | dispatch_group_enter(self.completionGroup); 117 | } 118 | 119 | dispatch_async(http_request_operation_processing_queue(), ^{ 120 | if (self.error) { 121 | if (failure) { 122 | dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{ 123 | failure(self, self.error); 124 | }); 125 | } 126 | } else { 127 | id responseObject = self.responseObject; 128 | if (self.error) { 129 | if (failure) { 130 | dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{ 131 | failure(self, self.error); 132 | }); 133 | } 134 | } else { 135 | if (success) { 136 | dispatch_group_async(self.completionGroup ?: http_request_operation_completion_group(), self.completionQueue ?: dispatch_get_main_queue(), ^{ 137 | success(self, responseObject); 138 | }); 139 | } 140 | } 141 | } 142 | 143 | if (self.completionGroup) { 144 | dispatch_group_leave(self.completionGroup); 145 | } 146 | }); 147 | }; 148 | #pragma clang diagnostic pop 149 | } 150 | 151 | #pragma mark - AFURLRequestOperation 152 | 153 | - (void)pause { 154 | [super pause]; 155 | 156 | u_int64_t offset = 0; 157 | if ([self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey]) { 158 | offset = [(NSNumber *)[self.outputStream propertyForKey:NSStreamFileCurrentOffsetKey] unsignedLongLongValue]; 159 | } else { 160 | offset = [(NSData *)[self.outputStream propertyForKey:NSStreamDataWrittenToMemoryStreamKey] length]; 161 | } 162 | 163 | NSMutableURLRequest *mutableURLRequest = [self.request mutableCopy]; 164 | if ([self.response respondsToSelector:@selector(allHeaderFields)] && [[self.response allHeaderFields] valueForKey:@"ETag"]) { 165 | [mutableURLRequest setValue:[[self.response allHeaderFields] valueForKey:@"ETag"] forHTTPHeaderField:@"If-Range"]; 166 | } 167 | [mutableURLRequest setValue:[NSString stringWithFormat:@"bytes=%llu-", offset] forHTTPHeaderField:@"Range"]; 168 | self.request = mutableURLRequest; 169 | } 170 | 171 | #pragma mark - NSSecureCoding 172 | 173 | + (BOOL)supportsSecureCoding { 174 | return YES; 175 | } 176 | 177 | - (id)initWithCoder:(NSCoder *)decoder { 178 | self = [super initWithCoder:decoder]; 179 | if (!self) { 180 | return nil; 181 | } 182 | 183 | self.responseSerializer = [decoder decodeObjectOfClass:[AFHTTPResponseSerializer class] forKey:NSStringFromSelector(@selector(responseSerializer))]; 184 | 185 | return self; 186 | } 187 | 188 | - (void)encodeWithCoder:(NSCoder *)coder { 189 | [super encodeWithCoder:coder]; 190 | 191 | [coder encodeObject:self.responseSerializer forKey:NSStringFromSelector(@selector(responseSerializer))]; 192 | } 193 | 194 | #pragma mark - NSCopying 195 | 196 | - (id)copyWithZone:(NSZone *)zone { 197 | AFHTTPRequestOperation *operation = [super copyWithZone:zone]; 198 | 199 | operation.responseSerializer = [self.responseSerializer copyWithZone:zone]; 200 | operation.completionQueue = self.completionQueue; 201 | operation.completionGroup = self.completionGroup; 202 | 203 | return operation; 204 | } 205 | 206 | @end 207 | -------------------------------------------------------------------------------- /QiniuSDK/AFNetworking/AFHTTPRequestOperationManager.m: -------------------------------------------------------------------------------- 1 | // AFHTTPRequestOperationManager.m 2 | // 3 | // Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) 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 24 | 25 | #import "AFHTTPRequestOperationManager.h" 26 | #import "AFHTTPRequestOperation.h" 27 | 28 | #import 29 | #import 30 | 31 | #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) 32 | #import 33 | #endif 34 | 35 | @interface AFHTTPRequestOperationManager () 36 | @property (readwrite, nonatomic, strong) NSURL *baseURL; 37 | @end 38 | 39 | @implementation AFHTTPRequestOperationManager 40 | 41 | + (instancetype)manager { 42 | return [[self alloc] initWithBaseURL:nil]; 43 | } 44 | 45 | - (instancetype)init { 46 | return [self initWithBaseURL:nil]; 47 | } 48 | 49 | - (instancetype)initWithBaseURL:(NSURL *)url { 50 | self = [super init]; 51 | if (!self) { 52 | return nil; 53 | } 54 | 55 | // Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected 56 | if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) { 57 | url = [url URLByAppendingPathComponent:@""]; 58 | } 59 | 60 | self.baseURL = url; 61 | 62 | self.requestSerializer = [AFHTTPRequestSerializer serializer]; 63 | self.responseSerializer = [AFJSONResponseSerializer serializer]; 64 | 65 | self.securityPolicy = [AFSecurityPolicy defaultPolicy]; 66 | 67 | self.reachabilityManager = [AFNetworkReachabilityManager sharedManager]; 68 | 69 | self.operationQueue = [[NSOperationQueue alloc] init]; 70 | 71 | self.shouldUseCredentialStorage = YES; 72 | 73 | return self; 74 | } 75 | 76 | #pragma mark - 77 | 78 | #ifdef _SYSTEMCONFIGURATION_H 79 | #endif 80 | 81 | - (void)setRequestSerializer:(AFHTTPRequestSerializer *)requestSerializer { 82 | NSParameterAssert(requestSerializer); 83 | 84 | _requestSerializer = requestSerializer; 85 | } 86 | 87 | - (void)setResponseSerializer:(AFHTTPResponseSerializer *)responseSerializer { 88 | NSParameterAssert(responseSerializer); 89 | 90 | _responseSerializer = responseSerializer; 91 | } 92 | 93 | #pragma mark - 94 | 95 | - (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)request 96 | success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success 97 | failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure 98 | { 99 | AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc] initWithRequest:request]; 100 | operation.responseSerializer = self.responseSerializer; 101 | operation.shouldUseCredentialStorage = self.shouldUseCredentialStorage; 102 | operation.credential = self.credential; 103 | operation.securityPolicy = self.securityPolicy; 104 | 105 | [operation setCompletionBlockWithSuccess:success failure:failure]; 106 | operation.completionQueue = self.completionQueue; 107 | operation.completionGroup = self.completionGroup; 108 | 109 | return operation; 110 | } 111 | 112 | #pragma mark - 113 | 114 | - (AFHTTPRequestOperation *)GET:(NSString *)URLString 115 | parameters:(id)parameters 116 | success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success 117 | failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure 118 | { 119 | NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"GET" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; 120 | AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; 121 | 122 | [self.operationQueue addOperation:operation]; 123 | 124 | return operation; 125 | } 126 | 127 | - (AFHTTPRequestOperation *)HEAD:(NSString *)URLString 128 | parameters:(id)parameters 129 | success:(void (^)(AFHTTPRequestOperation *operation))success 130 | failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure 131 | { 132 | NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"HEAD" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; 133 | AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:^(AFHTTPRequestOperation *requestOperation, __unused id responseObject) { 134 | if (success) { 135 | success(requestOperation); 136 | } 137 | } failure:failure]; 138 | 139 | [self.operationQueue addOperation:operation]; 140 | 141 | return operation; 142 | } 143 | 144 | - (AFHTTPRequestOperation *)POST:(NSString *)URLString 145 | parameters:(id)parameters 146 | success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success 147 | failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure 148 | { 149 | NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; 150 | AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; 151 | 152 | [self.operationQueue addOperation:operation]; 153 | 154 | return operation; 155 | } 156 | 157 | - (AFHTTPRequestOperation *)POST:(NSString *)URLString 158 | parameters:(id)parameters 159 | constructingBodyWithBlock:(void (^)(id formData))block 160 | success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success 161 | failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure 162 | { 163 | NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:nil]; 164 | AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; 165 | 166 | [self.operationQueue addOperation:operation]; 167 | 168 | return operation; 169 | } 170 | 171 | - (AFHTTPRequestOperation *)PUT:(NSString *)URLString 172 | parameters:(id)parameters 173 | success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success 174 | failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure 175 | { 176 | NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"PUT" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; 177 | AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; 178 | 179 | [self.operationQueue addOperation:operation]; 180 | 181 | return operation; 182 | } 183 | 184 | - (AFHTTPRequestOperation *)PATCH:(NSString *)URLString 185 | parameters:(id)parameters 186 | success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success 187 | failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure 188 | { 189 | NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"PATCH" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; 190 | AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; 191 | 192 | [self.operationQueue addOperation:operation]; 193 | 194 | return operation; 195 | } 196 | 197 | - (AFHTTPRequestOperation *)DELETE:(NSString *)URLString 198 | parameters:(id)parameters 199 | success:(void (^)(AFHTTPRequestOperation *operation, id responseObject))success 200 | failure:(void (^)(AFHTTPRequestOperation *operation, NSError *error))failure 201 | { 202 | NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:@"DELETE" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:nil]; 203 | AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request success:success failure:failure]; 204 | 205 | [self.operationQueue addOperation:operation]; 206 | 207 | return operation; 208 | } 209 | 210 | #pragma mark - NSObject 211 | 212 | - (NSString *)description { 213 | return [NSString stringWithFormat:@"<%@: %p, baseURL: %@, operationQueue: %@>", NSStringFromClass([self class]), self, [self.baseURL absoluteString], self.operationQueue]; 214 | } 215 | 216 | #pragma mark - NSSecureCoding 217 | 218 | + (BOOL)supportsSecureCoding { 219 | return YES; 220 | } 221 | 222 | - (id)initWithCoder:(NSCoder *)decoder { 223 | NSURL *baseURL = [decoder decodeObjectForKey:NSStringFromSelector(@selector(baseURL))]; 224 | 225 | self = [self initWithBaseURL:baseURL]; 226 | if (!self) { 227 | return nil; 228 | } 229 | 230 | self.requestSerializer = [decoder decodeObjectOfClass:[AFHTTPRequestSerializer class] forKey:NSStringFromSelector(@selector(requestSerializer))]; 231 | self.responseSerializer = [decoder decodeObjectOfClass:[AFHTTPResponseSerializer class] forKey:NSStringFromSelector(@selector(responseSerializer))]; 232 | 233 | return self; 234 | } 235 | 236 | - (void)encodeWithCoder:(NSCoder *)coder { 237 | [coder encodeObject:self.baseURL forKey:NSStringFromSelector(@selector(baseURL))]; 238 | [coder encodeObject:self.requestSerializer forKey:NSStringFromSelector(@selector(requestSerializer))]; 239 | [coder encodeObject:self.responseSerializer forKey:NSStringFromSelector(@selector(responseSerializer))]; 240 | } 241 | 242 | #pragma mark - NSCopying 243 | 244 | - (id)copyWithZone:(NSZone *)zone { 245 | AFHTTPRequestOperationManager *HTTPClient = [[[self class] allocWithZone:zone] initWithBaseURL:self.baseURL]; 246 | 247 | HTTPClient.requestSerializer = [self.requestSerializer copyWithZone:zone]; 248 | HTTPClient.responseSerializer = [self.responseSerializer copyWithZone:zone]; 249 | 250 | return HTTPClient; 251 | } 252 | 253 | @end 254 | -------------------------------------------------------------------------------- /QiniuSDK/AFNetworking/AFHTTPSessionManager.h: -------------------------------------------------------------------------------- 1 | // AFHTTPSessionManager.h 2 | // 3 | // Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) 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 24 | #import 25 | #import 26 | 27 | #if __IPHONE_OS_VERSION_MIN_REQUIRED 28 | #import 29 | #else 30 | #import 31 | #endif 32 | 33 | #import "AFURLSessionManager.h" 34 | 35 | /** 36 | `AFHTTPSessionManager` is a subclass of `AFURLSessionManager` with convenience methods for making HTTP requests. When a `baseURL` is provided, requests made with the `GET` / `POST` / et al. convenience methods can be made with relative paths. 37 | 38 | ## Subclassing Notes 39 | 40 | Developers targeting iOS 7 or Mac OS X 10.9 or later that deal extensively with a web service are encouraged to subclass `AFHTTPSessionManager`, providing a class method that returns a shared singleton object on which authentication and other configuration can be shared across the application. 41 | 42 | For developers targeting iOS 6 or Mac OS X 10.8 or earlier, `AFHTTPRequestOperationManager` may be used to similar effect. 43 | 44 | ## Methods to Override 45 | 46 | To change the behavior of all data task operation construction, which is also used in the `GET` / `POST` / et al. convenience methods, override `dataTaskWithRequest:completionHandler:`. 47 | 48 | ## Serialization 49 | 50 | Requests created by an HTTP client will contain default headers and encode parameters according to the `requestSerializer` property, which is an object conforming to ``. 51 | 52 | Responses received from the server are automatically validated and serialized by the `responseSerializers` property, which is an object conforming to `` 53 | 54 | ## URL Construction Using Relative Paths 55 | 56 | For HTTP convenience methods, the request serializer constructs URLs from the path relative to the `-baseURL`, using `NSURL +URLWithString:relativeToURL:`, when provided. If `baseURL` is `nil`, `path` needs to resolve to a valid `NSURL` object using `NSURL +URLWithString:`. 57 | 58 | Below are a few examples of how `baseURL` and relative paths interact: 59 | 60 | NSURL *baseURL = [NSURL URLWithString:@"http://example.com/v1/"]; 61 | [NSURL URLWithString:@"foo" relativeToURL:baseURL]; // http://example.com/v1/foo 62 | [NSURL URLWithString:@"foo?bar=baz" relativeToURL:baseURL]; // http://example.com/v1/foo?bar=baz 63 | [NSURL URLWithString:@"/foo" relativeToURL:baseURL]; // http://example.com/foo 64 | [NSURL URLWithString:@"foo/" relativeToURL:baseURL]; // http://example.com/v1/foo 65 | [NSURL URLWithString:@"/foo/" relativeToURL:baseURL]; // http://example.com/foo/ 66 | [NSURL URLWithString:@"http://example2.com/" relativeToURL:baseURL]; // http://example2.com/ 67 | 68 | Also important to note is that a trailing slash will be added to any `baseURL` without one. This would otherwise cause unexpected behavior when constructing URLs using paths without a leading slash. 69 | */ 70 | 71 | #if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090) 72 | 73 | @interface AFHTTPSessionManager : AFURLSessionManager 74 | 75 | /** 76 | The URL used to monitor reachability, and construct requests from relative paths in methods like `requestWithMethod:URLString:parameters:`, and the `GET` / `POST` / et al. convenience methods. 77 | */ 78 | @property (readonly, nonatomic, strong) NSURL *baseURL; 79 | 80 | /** 81 | Requests created with `requestWithMethod:URLString:parameters:` & `multipartFormRequestWithMethod:URLString:parameters:constructingBodyWithBlock:` are constructed with a set of default headers using a parameter serialization specified by this property. By default, this is set to an instance of `AFHTTPRequestSerializer`, which serializes query string parameters for `GET`, `HEAD`, and `DELETE` requests, or otherwise URL-form-encodes HTTP message bodies. 82 | 83 | @warning `requestSerializer` must not be `nil`. 84 | */ 85 | @property (nonatomic, strong) AFHTTPRequestSerializer * requestSerializer; 86 | 87 | /** 88 | Responses sent from the server in data tasks created with `dataTaskWithRequest:success:failure:` and run using the `GET` / `POST` / et al. convenience methods are automatically validated and serialized by the response serializer. By default, this property is set to an instance of `AFJSONResponseSerializer`. 89 | 90 | @warning `responseSerializer` must not be `nil`. 91 | */ 92 | @property (nonatomic, strong) AFHTTPResponseSerializer * responseSerializer; 93 | 94 | ///--------------------- 95 | /// @name Initialization 96 | ///--------------------- 97 | 98 | /** 99 | Creates and returns an `AFHTTPSessionManager` object. 100 | */ 101 | + (instancetype)manager; 102 | 103 | /** 104 | Initializes an `AFHTTPSessionManager` object with the specified base URL. 105 | 106 | @param url The base URL for the HTTP client. 107 | 108 | @return The newly-initialized HTTP client 109 | */ 110 | - (instancetype)initWithBaseURL:(NSURL *)url; 111 | 112 | /** 113 | Initializes an `AFHTTPSessionManager` object with the specified base URL. 114 | 115 | This is the designated initializer. 116 | 117 | @param url The base URL for the HTTP client. 118 | @param configuration The configuration used to create the managed session. 119 | 120 | @return The newly-initialized HTTP client 121 | */ 122 | - (instancetype)initWithBaseURL:(NSURL *)url 123 | sessionConfiguration:(NSURLSessionConfiguration *)configuration; 124 | 125 | ///--------------------------- 126 | /// @name Making HTTP Requests 127 | ///--------------------------- 128 | 129 | /** 130 | Creates and runs an `NSURLSessionDataTask` with a `GET` request. 131 | 132 | @param URLString The URL string used to create the request URL. 133 | @param parameters The parameters to be encoded according to the client request serializer. 134 | @param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer. 135 | @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred. 136 | 137 | @see -dataTaskWithRequest:completionHandler: 138 | */ 139 | - (NSURLSessionDataTask *)GET:(NSString *)URLString 140 | parameters:(id)parameters 141 | success:(void (^)(NSURLSessionDataTask *task, id responseObject))success 142 | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure; 143 | 144 | /** 145 | Creates and runs an `NSURLSessionDataTask` with a `HEAD` request. 146 | 147 | @param URLString The URL string used to create the request URL. 148 | @param parameters The parameters to be encoded according to the client request serializer. 149 | @param success A block object to be executed when the task finishes successfully. This block has no return value and takes a single arguments: the data task. 150 | @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred. 151 | 152 | @see -dataTaskWithRequest:completionHandler: 153 | */ 154 | - (NSURLSessionDataTask *)HEAD:(NSString *)URLString 155 | parameters:(id)parameters 156 | success:(void (^)(NSURLSessionDataTask *task))success 157 | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure; 158 | 159 | /** 160 | Creates and runs an `NSURLSessionDataTask` with a `POST` request. 161 | 162 | @param URLString The URL string used to create the request URL. 163 | @param parameters The parameters to be encoded according to the client request serializer. 164 | @param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer. 165 | @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred. 166 | 167 | @see -dataTaskWithRequest:completionHandler: 168 | */ 169 | - (NSURLSessionDataTask *)POST:(NSString *)URLString 170 | parameters:(id)parameters 171 | success:(void (^)(NSURLSessionDataTask *task, id responseObject))success 172 | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure; 173 | 174 | /** 175 | Creates and runs an `NSURLSessionDataTask` with a multipart `POST` request. 176 | 177 | @param URLString The URL string used to create the request URL. 178 | @param parameters The parameters to be encoded according to the client request serializer. 179 | @param block A block that takes a single argument and appends data to the HTTP body. The block argument is an object adopting the `AFMultipartFormData` protocol. 180 | @param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer. 181 | @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred. 182 | 183 | @see -dataTaskWithRequest:completionHandler: 184 | */ 185 | - (NSURLSessionDataTask *)POST:(NSString *)URLString 186 | parameters:(id)parameters 187 | constructingBodyWithBlock:(void (^)(id formData))block 188 | success:(void (^)(NSURLSessionDataTask *task, id responseObject))success 189 | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure; 190 | 191 | /** 192 | Creates and runs an `NSURLSessionDataTask` with a `PUT` request. 193 | 194 | @param URLString The URL string used to create the request URL. 195 | @param parameters The parameters to be encoded according to the client request serializer. 196 | @param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer. 197 | @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred. 198 | 199 | @see -dataTaskWithRequest:completionHandler: 200 | */ 201 | - (NSURLSessionDataTask *)PUT:(NSString *)URLString 202 | parameters:(id)parameters 203 | success:(void (^)(NSURLSessionDataTask *task, id responseObject))success 204 | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure; 205 | 206 | /** 207 | Creates and runs an `NSURLSessionDataTask` with a `PATCH` request. 208 | 209 | @param URLString The URL string used to create the request URL. 210 | @param parameters The parameters to be encoded according to the client request serializer. 211 | @param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer. 212 | @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred. 213 | 214 | @see -dataTaskWithRequest:completionHandler: 215 | */ 216 | - (NSURLSessionDataTask *)PATCH:(NSString *)URLString 217 | parameters:(id)parameters 218 | success:(void (^)(NSURLSessionDataTask *task, id responseObject))success 219 | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure; 220 | 221 | /** 222 | Creates and runs an `NSURLSessionDataTask` with a `DELETE` request. 223 | 224 | @param URLString The URL string used to create the request URL. 225 | @param parameters The parameters to be encoded according to the client request serializer. 226 | @param success A block object to be executed when the task finishes successfully. This block has no return value and takes two arguments: the data task, and the response object created by the client response serializer. 227 | @param failure A block object to be executed when the task finishes unsuccessfully, or that finishes successfully, but encountered an error while parsing the response data. This block has no return value and takes a two arguments: the data task and the error describing the network or parsing error that occurred. 228 | 229 | @see -dataTaskWithRequest:completionHandler: 230 | */ 231 | - (NSURLSessionDataTask *)DELETE:(NSString *)URLString 232 | parameters:(id)parameters 233 | success:(void (^)(NSURLSessionDataTask *task, id responseObject))success 234 | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure; 235 | 236 | @end 237 | 238 | #endif 239 | -------------------------------------------------------------------------------- /QiniuSDK/AFNetworking/AFHTTPSessionManager.m: -------------------------------------------------------------------------------- 1 | // AFHTTPSessionManager.m 2 | // 3 | // Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) 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 "AFHTTPSessionManager.h" 24 | 25 | #if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090) 26 | 27 | #import "AFURLRequestSerialization.h" 28 | #import "AFURLResponseSerialization.h" 29 | 30 | #import 31 | #import 32 | 33 | #ifdef _SYSTEMCONFIGURATION_H 34 | #import 35 | #import 36 | #import 37 | #import 38 | #import 39 | #endif 40 | 41 | #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) 42 | #import 43 | #endif 44 | 45 | @interface AFHTTPSessionManager () 46 | @property (readwrite, nonatomic, strong) NSURL *baseURL; 47 | @end 48 | 49 | @implementation AFHTTPSessionManager 50 | 51 | + (instancetype)manager { 52 | return [[[self class] alloc] initWithBaseURL:nil]; 53 | } 54 | 55 | - (instancetype)init { 56 | return [self initWithBaseURL:nil]; 57 | } 58 | 59 | - (instancetype)initWithBaseURL:(NSURL *)url { 60 | return [self initWithBaseURL:url sessionConfiguration:nil]; 61 | } 62 | 63 | - (instancetype)initWithSessionConfiguration:(NSURLSessionConfiguration *)configuration { 64 | return [self initWithBaseURL:nil sessionConfiguration:configuration]; 65 | } 66 | 67 | - (instancetype)initWithBaseURL:(NSURL *)url 68 | sessionConfiguration:(NSURLSessionConfiguration *)configuration 69 | { 70 | self = [super initWithSessionConfiguration:configuration]; 71 | if (!self) { 72 | return nil; 73 | } 74 | 75 | // Ensure terminal slash for baseURL path, so that NSURL +URLWithString:relativeToURL: works as expected 76 | if ([[url path] length] > 0 && ![[url absoluteString] hasSuffix:@"/"]) { 77 | url = [url URLByAppendingPathComponent:@""]; 78 | } 79 | 80 | self.baseURL = url; 81 | 82 | self.requestSerializer = [AFHTTPRequestSerializer serializer]; 83 | self.responseSerializer = [AFJSONResponseSerializer serializer]; 84 | 85 | return self; 86 | } 87 | 88 | #pragma mark - 89 | 90 | #ifdef _SYSTEMCONFIGURATION_H 91 | #endif 92 | 93 | - (void)setRequestSerializer:(AFHTTPRequestSerializer *)requestSerializer { 94 | NSParameterAssert(requestSerializer); 95 | 96 | _requestSerializer = requestSerializer; 97 | } 98 | 99 | - (void)setResponseSerializer:(AFHTTPResponseSerializer *)responseSerializer { 100 | NSParameterAssert(responseSerializer); 101 | 102 | [super setResponseSerializer:responseSerializer]; 103 | } 104 | 105 | #pragma mark - 106 | 107 | - (NSURLSessionDataTask *)GET:(NSString *)URLString 108 | parameters:(id)parameters 109 | success:(void (^)(NSURLSessionDataTask *task, id responseObject))success 110 | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure 111 | { 112 | NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET" URLString:URLString parameters:parameters success:success failure:failure]; 113 | 114 | [dataTask resume]; 115 | 116 | return dataTask; 117 | } 118 | 119 | - (NSURLSessionDataTask *)HEAD:(NSString *)URLString 120 | parameters:(id)parameters 121 | success:(void (^)(NSURLSessionDataTask *task))success 122 | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure 123 | { 124 | NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"HEAD" URLString:URLString parameters:parameters success:^(NSURLSessionDataTask *task, __unused id responseObject) { 125 | if (success) { 126 | success(task); 127 | } 128 | } failure:failure]; 129 | 130 | [dataTask resume]; 131 | 132 | return dataTask; 133 | } 134 | 135 | - (NSURLSessionDataTask *)POST:(NSString *)URLString 136 | parameters:(id)parameters 137 | success:(void (^)(NSURLSessionDataTask *task, id responseObject))success 138 | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure 139 | { 140 | NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"POST" URLString:URLString parameters:parameters success:success failure:failure]; 141 | 142 | [dataTask resume]; 143 | 144 | return dataTask; 145 | } 146 | 147 | - (NSURLSessionDataTask *)POST:(NSString *)URLString 148 | parameters:(id)parameters 149 | constructingBodyWithBlock:(void (^)(id formData))block 150 | success:(void (^)(NSURLSessionDataTask *task, id responseObject))success 151 | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure 152 | { 153 | NSError *serializationError = nil; 154 | NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:&serializationError]; 155 | if (serializationError) { 156 | if (failure) { 157 | #pragma clang diagnostic push 158 | #pragma clang diagnostic ignored "-Wgnu" 159 | dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{ 160 | failure(nil, serializationError); 161 | }); 162 | #pragma clang diagnostic pop 163 | } 164 | 165 | return nil; 166 | } 167 | 168 | __block NSURLSessionDataTask *task = [self uploadTaskWithStreamedRequest:request progress:nil completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) { 169 | if (error) { 170 | if (failure) { 171 | failure(task, error); 172 | } 173 | } else { 174 | if (success) { 175 | success(task, responseObject); 176 | } 177 | } 178 | }]; 179 | 180 | [task resume]; 181 | 182 | return task; 183 | } 184 | 185 | - (NSURLSessionDataTask *)PUT:(NSString *)URLString 186 | parameters:(id)parameters 187 | success:(void (^)(NSURLSessionDataTask *task, id responseObject))success 188 | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure 189 | { 190 | NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"PUT" URLString:URLString parameters:parameters success:success failure:failure]; 191 | 192 | [dataTask resume]; 193 | 194 | return dataTask; 195 | } 196 | 197 | - (NSURLSessionDataTask *)PATCH:(NSString *)URLString 198 | parameters:(id)parameters 199 | success:(void (^)(NSURLSessionDataTask *task, id responseObject))success 200 | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure 201 | { 202 | NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"PATCH" URLString:URLString parameters:parameters success:success failure:failure]; 203 | 204 | [dataTask resume]; 205 | 206 | return dataTask; 207 | } 208 | 209 | - (NSURLSessionDataTask *)DELETE:(NSString *)URLString 210 | parameters:(id)parameters 211 | success:(void (^)(NSURLSessionDataTask *task, id responseObject))success 212 | failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure 213 | { 214 | NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"DELETE" URLString:URLString parameters:parameters success:success failure:failure]; 215 | 216 | [dataTask resume]; 217 | 218 | return dataTask; 219 | } 220 | 221 | - (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method 222 | URLString:(NSString *)URLString 223 | parameters:(id)parameters 224 | success:(void (^)(NSURLSessionDataTask *, id))success 225 | failure:(void (^)(NSURLSessionDataTask *, NSError *))failure 226 | { 227 | NSError *serializationError = nil; 228 | NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError]; 229 | if (serializationError) { 230 | if (failure) { 231 | #pragma clang diagnostic push 232 | #pragma clang diagnostic ignored "-Wgnu" 233 | dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{ 234 | failure(nil, serializationError); 235 | }); 236 | #pragma clang diagnostic pop 237 | } 238 | 239 | return nil; 240 | } 241 | 242 | __block NSURLSessionDataTask *dataTask = nil; 243 | dataTask = [self dataTaskWithRequest:request completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) { 244 | if (error) { 245 | if (failure) { 246 | failure(dataTask, error); 247 | } 248 | } else { 249 | if (success) { 250 | success(dataTask, responseObject); 251 | } 252 | } 253 | }]; 254 | 255 | return dataTask; 256 | } 257 | 258 | #pragma mark - NSObject 259 | 260 | - (NSString *)description { 261 | return [NSString stringWithFormat:@"<%@: %p, baseURL: %@, session: %@, operationQueue: %@>", NSStringFromClass([self class]), self, [self.baseURL absoluteString], self.session, self.operationQueue]; 262 | } 263 | 264 | #pragma mark - NSSecureCoding 265 | 266 | + (BOOL)supportsSecureCoding { 267 | return YES; 268 | } 269 | 270 | - (id)initWithCoder:(NSCoder *)decoder { 271 | NSURL *baseURL = [decoder decodeObjectOfClass:[NSURL class] forKey:NSStringFromSelector(@selector(baseURL))]; 272 | NSURLSessionConfiguration *configuration = [decoder decodeObjectOfClass:[NSURLSessionConfiguration class] forKey:@"sessionConfiguration"]; 273 | if (!configuration) { 274 | NSString *configurationIdentifier = [decoder decodeObjectOfClass:[NSString class] forKey:@"identifier"]; 275 | if (configurationIdentifier) { 276 | #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) 277 | configuration = [NSURLSessionConfiguration backgroundSessionConfigurationWithIdentifier:configurationIdentifier]; 278 | #else 279 | configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:configurationIdentifier]; 280 | #endif 281 | } 282 | } 283 | 284 | self = [self initWithBaseURL:baseURL sessionConfiguration:configuration]; 285 | if (!self) { 286 | return nil; 287 | } 288 | 289 | self.requestSerializer = [decoder decodeObjectOfClass:[AFHTTPRequestSerializer class] forKey:NSStringFromSelector(@selector(requestSerializer))]; 290 | self.responseSerializer = [decoder decodeObjectOfClass:[AFHTTPResponseSerializer class] forKey:NSStringFromSelector(@selector(responseSerializer))]; 291 | 292 | return self; 293 | } 294 | 295 | - (void)encodeWithCoder:(NSCoder *)coder { 296 | [super encodeWithCoder:coder]; 297 | 298 | [coder encodeObject:self.baseURL forKey:NSStringFromSelector(@selector(baseURL))]; 299 | if ([self.session.configuration conformsToProtocol:@protocol(NSCoding)]) { 300 | [coder encodeObject:self.session.configuration forKey:@"sessionConfiguration"]; 301 | } else { 302 | [coder encodeObject:self.session.configuration.identifier forKey:@"identifier"]; 303 | } 304 | [coder encodeObject:self.requestSerializer forKey:NSStringFromSelector(@selector(requestSerializer))]; 305 | [coder encodeObject:self.responseSerializer forKey:NSStringFromSelector(@selector(responseSerializer))]; 306 | } 307 | 308 | #pragma mark - NSCopying 309 | 310 | - (id)copyWithZone:(NSZone *)zone { 311 | AFHTTPSessionManager *HTTPClient = [[[self class] allocWithZone:zone] initWithBaseURL:self.baseURL sessionConfiguration:self.session.configuration]; 312 | 313 | HTTPClient.requestSerializer = [self.requestSerializer copyWithZone:zone]; 314 | HTTPClient.responseSerializer = [self.responseSerializer copyWithZone:zone]; 315 | 316 | return HTTPClient; 317 | } 318 | 319 | @end 320 | 321 | #endif 322 | -------------------------------------------------------------------------------- /QiniuSDK/AFNetworking/AFNetworkReachabilityManager.h: -------------------------------------------------------------------------------- 1 | // AFNetworkReachabilityManager.h 2 | // 3 | // Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) 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 24 | #import 25 | 26 | typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) { 27 | AFNetworkReachabilityStatusUnknown = -1, 28 | AFNetworkReachabilityStatusNotReachable = 0, 29 | AFNetworkReachabilityStatusReachableViaWWAN = 1, 30 | AFNetworkReachabilityStatusReachableViaWiFi = 2, 31 | }; 32 | 33 | /** 34 | `AFNetworkReachabilityManager` monitors the reachability of domains, and addresses for both WWAN and WiFi network interfaces. 35 | 36 | Reachability can be used to determine background information about why a network operation failed, or to trigger a network operation retrying when a connection is established. It should not be used to prevent a user from initiating a network request, as it's possible that an initial request may be required to establish reachability. 37 | 38 | See Apple's Reachability Sample Code (https://developer.apple.com/library/ios/samplecode/reachability/) 39 | 40 | @warning Instances of `AFNetworkReachabilityManager` must be started with `-startMonitoring` before reachability status can be determined. 41 | */ 42 | @interface AFNetworkReachabilityManager : NSObject 43 | 44 | /** 45 | The current network reachability status. 46 | */ 47 | @property (readonly, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus; 48 | 49 | /** 50 | Whether or not the network is currently reachable. 51 | */ 52 | @property (readonly, nonatomic, assign, getter = isReachable) BOOL reachable; 53 | 54 | /** 55 | Whether or not the network is currently reachable via WWAN. 56 | */ 57 | @property (readonly, nonatomic, assign, getter = isReachableViaWWAN) BOOL reachableViaWWAN; 58 | 59 | /** 60 | Whether or not the network is currently reachable via WiFi. 61 | */ 62 | @property (readonly, nonatomic, assign, getter = isReachableViaWiFi) BOOL reachableViaWiFi; 63 | 64 | ///--------------------- 65 | /// @name Initialization 66 | ///--------------------- 67 | 68 | /** 69 | Returns the shared network reachability manager. 70 | */ 71 | + (instancetype)sharedManager; 72 | 73 | /** 74 | Creates and returns a network reachability manager for the specified domain. 75 | 76 | @param domain The domain used to evaluate network reachability. 77 | 78 | @return An initialized network reachability manager, actively monitoring the specified domain. 79 | */ 80 | + (instancetype)managerForDomain:(NSString *)domain; 81 | 82 | /** 83 | Creates and returns a network reachability manager for the socket address. 84 | 85 | @param address The socket address (`sockaddr_in`) used to evaluate network reachability. 86 | 87 | @return An initialized network reachability manager, actively monitoring the specified socket address. 88 | */ 89 | + (instancetype)managerForAddress:(const void *)address; 90 | 91 | /** 92 | Initializes an instance of a network reachability manager from the specified reachability object. 93 | 94 | @param reachability The reachability object to monitor. 95 | 96 | @return An initialized network reachability manager, actively monitoring the specified reachability. 97 | */ 98 | - (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability; 99 | 100 | ///-------------------------------------------------- 101 | /// @name Starting & Stopping Reachability Monitoring 102 | ///-------------------------------------------------- 103 | 104 | /** 105 | Starts monitoring for changes in network reachability status. 106 | */ 107 | - (void)startMonitoring; 108 | 109 | /** 110 | Stops monitoring for changes in network reachability status. 111 | */ 112 | - (void)stopMonitoring; 113 | 114 | ///------------------------------------------------- 115 | /// @name Getting Localized Reachability Description 116 | ///------------------------------------------------- 117 | 118 | /** 119 | Returns a localized string representation of the current network reachability status. 120 | */ 121 | - (NSString *)localizedNetworkReachabilityStatusString; 122 | 123 | ///--------------------------------------------------- 124 | /// @name Setting Network Reachability Change Callback 125 | ///--------------------------------------------------- 126 | 127 | /** 128 | Sets a callback to be executed when the network availability of the `baseURL` host changes. 129 | 130 | @param block A block object to be executed when the network availability of the `baseURL` host changes.. This block has no return value and takes a single argument which represents the various reachability states from the device to the `baseURL`. 131 | */ 132 | - (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block; 133 | 134 | @end 135 | 136 | ///---------------- 137 | /// @name Constants 138 | ///---------------- 139 | 140 | /** 141 | ## Network Reachability 142 | 143 | The following constants are provided by `AFNetworkReachabilityManager` as possible network reachability statuses. 144 | 145 | enum { 146 | AFNetworkReachabilityStatusUnknown, 147 | AFNetworkReachabilityStatusNotReachable, 148 | AFNetworkReachabilityStatusReachableViaWWAN, 149 | AFNetworkReachabilityStatusReachableViaWiFi, 150 | } 151 | 152 | `AFNetworkReachabilityStatusUnknown` 153 | The `baseURL` host reachability is not known. 154 | 155 | `AFNetworkReachabilityStatusNotReachable` 156 | The `baseURL` host cannot be reached. 157 | 158 | `AFNetworkReachabilityStatusReachableViaWWAN` 159 | The `baseURL` host can be reached via a cellular connection, such as EDGE or GPRS. 160 | 161 | `AFNetworkReachabilityStatusReachableViaWiFi` 162 | The `baseURL` host can be reached via a Wi-Fi connection. 163 | 164 | ### Keys for Notification UserInfo Dictionary 165 | 166 | Strings that are used as keys in a `userInfo` dictionary in a network reachability status change notification. 167 | 168 | `AFNetworkingReachabilityNotificationStatusItem` 169 | A key in the userInfo dictionary in a `AFNetworkingReachabilityDidChangeNotification` notification. 170 | The corresponding value is an `NSNumber` object representing the `AFNetworkReachabilityStatus` value for the current reachability status. 171 | */ 172 | 173 | ///-------------------- 174 | /// @name Notifications 175 | ///-------------------- 176 | 177 | /** 178 | Posted when network reachability changes. 179 | This notification assigns no notification object. The `userInfo` dictionary contains an `NSNumber` object under the `AFNetworkingReachabilityNotificationStatusItem` key, representing the `AFNetworkReachabilityStatus` value for the current network reachability. 180 | 181 | @warning In order for network reachability to be monitored, include the `SystemConfiguration` framework in the active target's "Link Binary With Library" build phase, and add `#import ` to the header prefix of the project (`Prefix.pch`). 182 | */ 183 | extern NSString * const AFNetworkingReachabilityDidChangeNotification; 184 | extern NSString * const AFNetworkingReachabilityNotificationStatusItem; 185 | 186 | ///-------------------- 187 | /// @name Functions 188 | ///-------------------- 189 | 190 | /** 191 | Returns a localized string representation of an `AFNetworkReachabilityStatus` value. 192 | */ 193 | extern NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status); 194 | -------------------------------------------------------------------------------- /QiniuSDK/AFNetworking/AFNetworkReachabilityManager.m: -------------------------------------------------------------------------------- 1 | // AFNetworkReachabilityManager.m 2 | // 3 | // Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) 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 "AFNetworkReachabilityManager.h" 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 | 36 | typedef NS_ENUM(NSUInteger, AFNetworkReachabilityAssociation) { 37 | AFNetworkReachabilityForAddress = 1, 38 | AFNetworkReachabilityForAddressPair = 2, 39 | AFNetworkReachabilityForName = 3, 40 | }; 41 | 42 | NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status) { 43 | switch (status) { 44 | case AFNetworkReachabilityStatusNotReachable: 45 | return NSLocalizedStringFromTable(@"Not Reachable", @"AFNetworking", nil); 46 | case AFNetworkReachabilityStatusReachableViaWWAN: 47 | return NSLocalizedStringFromTable(@"Reachable via WWAN", @"AFNetworking", nil); 48 | case AFNetworkReachabilityStatusReachableViaWiFi: 49 | return NSLocalizedStringFromTable(@"Reachable via WiFi", @"AFNetworking", nil); 50 | case AFNetworkReachabilityStatusUnknown: 51 | default: 52 | return NSLocalizedStringFromTable(@"Unknown", @"AFNetworking", nil); 53 | } 54 | } 55 | 56 | static AFNetworkReachabilityStatus AFNetworkReachabilityStatusForFlags(SCNetworkReachabilityFlags flags) { 57 | BOOL isReachable = ((flags & kSCNetworkReachabilityFlagsReachable) != 0); 58 | BOOL needsConnection = ((flags & kSCNetworkReachabilityFlagsConnectionRequired) != 0); 59 | BOOL canConnectionAutomatically = (((flags & kSCNetworkReachabilityFlagsConnectionOnDemand ) != 0) || ((flags & kSCNetworkReachabilityFlagsConnectionOnTraffic) != 0)); 60 | BOOL canConnectWithoutUserInteraction = (canConnectionAutomatically && (flags & kSCNetworkReachabilityFlagsInterventionRequired) == 0); 61 | BOOL isNetworkReachable = (isReachable && (!needsConnection || canConnectWithoutUserInteraction)); 62 | 63 | AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusUnknown; 64 | if (isNetworkReachable == NO) { 65 | status = AFNetworkReachabilityStatusNotReachable; 66 | } 67 | #if TARGET_OS_IPHONE 68 | else if ((flags & kSCNetworkReachabilityFlagsIsWWAN) != 0) { 69 | status = AFNetworkReachabilityStatusReachableViaWWAN; 70 | } 71 | #endif 72 | else { 73 | status = AFNetworkReachabilityStatusReachableViaWiFi; 74 | } 75 | 76 | return status; 77 | } 78 | 79 | static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) { 80 | AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags); 81 | AFNetworkReachabilityStatusBlock block = (__bridge AFNetworkReachabilityStatusBlock)info; 82 | if (block) { 83 | block(status); 84 | } 85 | 86 | 87 | dispatch_async(dispatch_get_main_queue(), ^{ 88 | NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 89 | [notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:@{ AFNetworkingReachabilityNotificationStatusItem: @(status) }]; 90 | }); 91 | 92 | } 93 | 94 | static const void * AFNetworkReachabilityRetainCallback(const void *info) { 95 | return Block_copy(info); 96 | } 97 | 98 | static void AFNetworkReachabilityReleaseCallback(const void *info) { 99 | if (info) { 100 | Block_release(info); 101 | } 102 | } 103 | 104 | @interface AFNetworkReachabilityManager () 105 | @property (readwrite, nonatomic, assign) SCNetworkReachabilityRef networkReachability; 106 | @property (readwrite, nonatomic, assign) AFNetworkReachabilityAssociation networkReachabilityAssociation; 107 | @property (readwrite, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus; 108 | @property (readwrite, nonatomic, copy) AFNetworkReachabilityStatusBlock networkReachabilityStatusBlock; 109 | @end 110 | 111 | @implementation AFNetworkReachabilityManager 112 | 113 | + (instancetype)sharedManager { 114 | static AFNetworkReachabilityManager *_sharedManager = nil; 115 | static dispatch_once_t onceToken; 116 | dispatch_once(&onceToken, ^{ 117 | struct sockaddr_in address; 118 | bzero(&address, sizeof(address)); 119 | address.sin_len = sizeof(address); 120 | address.sin_family = AF_INET; 121 | 122 | _sharedManager = [self managerForAddress:&address]; 123 | }); 124 | 125 | return _sharedManager; 126 | } 127 | 128 | + (instancetype)managerForDomain:(NSString *)domain { 129 | SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]); 130 | 131 | AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability]; 132 | manager.networkReachabilityAssociation = AFNetworkReachabilityForName; 133 | 134 | return manager; 135 | } 136 | 137 | + (instancetype)managerForAddress:(const void *)address { 138 | SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address); 139 | 140 | AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability]; 141 | manager.networkReachabilityAssociation = AFNetworkReachabilityForAddress; 142 | 143 | return manager; 144 | } 145 | 146 | - (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability { 147 | self = [super init]; 148 | if (!self) { 149 | return nil; 150 | } 151 | 152 | self.networkReachability = reachability; 153 | self.networkReachabilityStatus = AFNetworkReachabilityStatusUnknown; 154 | 155 | return self; 156 | } 157 | 158 | - (void)dealloc { 159 | [self stopMonitoring]; 160 | 161 | if (_networkReachability) { 162 | CFRelease(_networkReachability); 163 | _networkReachability = NULL; 164 | } 165 | } 166 | 167 | #pragma mark - 168 | 169 | - (BOOL)isReachable { 170 | return [self isReachableViaWWAN] || [self isReachableViaWiFi]; 171 | } 172 | 173 | - (BOOL)isReachableViaWWAN { 174 | return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWWAN; 175 | } 176 | 177 | - (BOOL)isReachableViaWiFi { 178 | return self.networkReachabilityStatus == AFNetworkReachabilityStatusReachableViaWiFi; 179 | } 180 | 181 | #pragma mark - 182 | 183 | - (void)startMonitoring { 184 | [self stopMonitoring]; 185 | 186 | if (!self.networkReachability) { 187 | return; 188 | } 189 | 190 | __weak __typeof(self)weakSelf = self; 191 | AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) { 192 | __strong __typeof(weakSelf)strongSelf = weakSelf; 193 | 194 | strongSelf.networkReachabilityStatus = status; 195 | if (strongSelf.networkReachabilityStatusBlock) { 196 | strongSelf.networkReachabilityStatusBlock(status); 197 | } 198 | 199 | }; 200 | 201 | SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL}; 202 | SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context); 203 | SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); 204 | 205 | switch (self.networkReachabilityAssociation) { 206 | case AFNetworkReachabilityForName: 207 | break; 208 | case AFNetworkReachabilityForAddress: 209 | case AFNetworkReachabilityForAddressPair: 210 | default: { 211 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{ 212 | SCNetworkReachabilityFlags flags; 213 | SCNetworkReachabilityGetFlags(self.networkReachability, &flags); 214 | AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags); 215 | dispatch_async(dispatch_get_main_queue(), ^{ 216 | callback(status); 217 | 218 | NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter]; 219 | [notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:@{ AFNetworkingReachabilityNotificationStatusItem: @(status) }]; 220 | 221 | 222 | }); 223 | }); 224 | } 225 | break; 226 | } 227 | } 228 | 229 | - (void)stopMonitoring { 230 | if (!self.networkReachability) { 231 | return; 232 | } 233 | 234 | SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes); 235 | } 236 | 237 | #pragma mark - 238 | 239 | - (NSString *)localizedNetworkReachabilityStatusString { 240 | return AFStringFromNetworkReachabilityStatus(self.networkReachabilityStatus); 241 | } 242 | 243 | #pragma mark - 244 | 245 | - (void)setReachabilityStatusChangeBlock:(void (^)(AFNetworkReachabilityStatus status))block { 246 | self.networkReachabilityStatusBlock = block; 247 | } 248 | 249 | #pragma mark - NSKeyValueObserving 250 | 251 | + (NSSet *)keyPathsForValuesAffectingValueForKey:(NSString *)key { 252 | if ([key isEqualToString:@"reachable"] || [key isEqualToString:@"reachableViaWWAN"] || [key isEqualToString:@"reachableViaWiFi"]) { 253 | return [NSSet setWithObject:@"networkReachabilityStatus"]; 254 | } 255 | 256 | return [super keyPathsForValuesAffectingValueForKey:key]; 257 | } 258 | 259 | @end 260 | -------------------------------------------------------------------------------- /QiniuSDK/AFNetworking/AFNetworking.h: -------------------------------------------------------------------------------- 1 | // AFNetworking.h 2 | // 3 | // Copyright (c) 2013 AFNetworking (http://afnetworking.com/) 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 24 | #import 25 | 26 | #ifndef _AFNETWORKING_ 27 | #define _AFNETWORKING_ 28 | 29 | #import "AFURLRequestSerialization.h" 30 | #import "AFURLResponseSerialization.h" 31 | #import "AFSecurityPolicy.h" 32 | #import "AFNetworkReachabilityManager.h" 33 | 34 | #import "AFURLConnectionOperation.h" 35 | #import "AFHTTPRequestOperation.h" 36 | #import "AFHTTPRequestOperationManager.h" 37 | 38 | #if ( ( defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090) || \ 39 | ( defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 ) ) 40 | #import "AFURLSessionManager.h" 41 | #import "AFHTTPSessionManager.h" 42 | #endif 43 | 44 | #endif /* _AFNETWORKING_ */ 45 | -------------------------------------------------------------------------------- /QiniuSDK/AFNetworking/AFSecurityPolicy.h: -------------------------------------------------------------------------------- 1 | // AFSecurity.h 2 | // 3 | // Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) 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 24 | #import 25 | 26 | typedef NS_ENUM(NSUInteger, AFSSLPinningMode) { 27 | AFSSLPinningModeNone, 28 | AFSSLPinningModePublicKey, 29 | AFSSLPinningModeCertificate, 30 | }; 31 | 32 | /** 33 | `AFSecurityPolicy` evaluates server trust against pinned X.509 certificates and public keys over secure connections. 34 | 35 | Adding pinned SSL certificates to your app helps prevent man-in-the-middle attacks and other vulnerabilities. Applications dealing with sensitive customer data or financial information are strongly encouraged to route all communication over an HTTPS connection with SSL pinning configured and enabled. 36 | */ 37 | @interface AFSecurityPolicy : NSObject 38 | 39 | /** 40 | The criteria by which server trust should be evaluated against the pinned SSL certificates. Defaults to `AFSSLPinningModeNone`. 41 | */ 42 | @property (nonatomic, assign) AFSSLPinningMode SSLPinningMode; 43 | 44 | /** 45 | Whether to evaluate an entire SSL certificate chain, or just the leaf certificate. Defaults to `YES`. 46 | */ 47 | @property (nonatomic, assign) BOOL validatesCertificateChain; 48 | 49 | /** 50 | The certificates used to evaluate server trust according to the SSL pinning mode. By default, this property is set to any (`.cer`) certificates included in the app bundle. 51 | */ 52 | @property (nonatomic, strong) NSArray *pinnedCertificates; 53 | 54 | /** 55 | Whether or not to trust servers with an invalid or expired SSL certificates. Defaults to `NO`. 56 | */ 57 | @property (nonatomic, assign) BOOL allowInvalidCertificates; 58 | 59 | /** 60 | Whether or not to validate the domain name in the certificates CN field. Defaults to `YES` for `AFSSLPinningModePublicKey` or `AFSSLPinningModeCertificate`, otherwise `NO`. 61 | */ 62 | @property (nonatomic, assign) BOOL validatesDomainName; 63 | 64 | ///----------------------------------------- 65 | /// @name Getting Specific Security Policies 66 | ///----------------------------------------- 67 | 68 | /** 69 | Returns the shared default security policy, which does not accept invalid certificates, and does not validate against pinned certificates or public keys. 70 | 71 | @return The default security policy. 72 | */ 73 | + (instancetype)defaultPolicy; 74 | 75 | ///--------------------- 76 | /// @name Initialization 77 | ///--------------------- 78 | 79 | /** 80 | Creates and returns a security policy with the specified pinning mode. 81 | 82 | @param pinningMode The SSL pinning mode. 83 | 84 | @return A new security policy. 85 | */ 86 | + (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode; 87 | 88 | ///------------------------------ 89 | /// @name Evaluating Server Trust 90 | ///------------------------------ 91 | 92 | /** 93 | Whether or not the specified server trust should be accepted, based on the security policy. 94 | 95 | This method should be used when responding to an authentication challenge from a server. 96 | 97 | @param serverTrust The X.509 certificate trust of the server. 98 | 99 | @return Whether or not to trust the server. 100 | 101 | @warning This method has been deprecated in favor of `-evaluateServerTrust:forDomain:`. 102 | */ 103 | - (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust DEPRECATED_ATTRIBUTE; 104 | 105 | /** 106 | Whether or not the specified server trust should be accepted, based on the security policy. 107 | 108 | This method should be used when responding to an authentication challenge from a server. 109 | 110 | @param serverTrust The X.509 certificate trust of the server. 111 | @param domain The domain of serverTrust. If `nil`, the domain will not be validated. 112 | 113 | @return Whether or not to trust the server. 114 | */ 115 | - (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust 116 | forDomain:(NSString *)domain; 117 | 118 | @end 119 | 120 | ///---------------- 121 | /// @name Constants 122 | ///---------------- 123 | 124 | /** 125 | ## SSL Pinning Modes 126 | 127 | The following constants are provided by `AFSSLPinningMode` as possible SSL pinning modes. 128 | 129 | enum { 130 | AFSSLPinningModeNone, 131 | AFSSLPinningModePublicKey, 132 | AFSSLPinningModeCertificate, 133 | } 134 | 135 | `AFSSLPinningModeNone` 136 | Do not used pinned certificates to validate servers. 137 | 138 | `AFSSLPinningModePublicKey` 139 | Validate host certificates against public keys of pinned certificates. 140 | 141 | `AFSSLPinningModeCertificate` 142 | Validate host certificates against pinned certificates. 143 | */ 144 | -------------------------------------------------------------------------------- /QiniuSDK/AFNetworking/AFSecurityPolicy.m: -------------------------------------------------------------------------------- 1 | // AFSecurity.m 2 | // 3 | // Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) 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 "AFSecurityPolicy.h" 24 | 25 | // Equivalent of macro in , without causing compiler warning: 26 | // "'DebugAssert' is deprecated: first deprecated in OS X 10.8" 27 | #ifndef AF_Require 28 | #define AF_Require(assertion, exceptionLabel) \ 29 | do { \ 30 | if (__builtin_expect(!(assertion), 0)) { \ 31 | goto exceptionLabel; \ 32 | } \ 33 | } while (0) 34 | #endif 35 | 36 | #ifndef AF_Require_noErr 37 | #define AF_Require_noErr(errorCode, exceptionLabel) \ 38 | do { \ 39 | if (__builtin_expect(0 != (errorCode), 0)) { \ 40 | goto exceptionLabel; \ 41 | } \ 42 | } while (0) 43 | #endif 44 | 45 | #if !defined(__IPHONE_OS_VERSION_MIN_REQUIRED) 46 | static NSData * AFSecKeyGetData(SecKeyRef key) { 47 | CFDataRef data = NULL; 48 | 49 | AF_Require_noErr(SecItemExport(key, kSecFormatUnknown, kSecItemPemArmour, NULL, &data), _out); 50 | 51 | return (__bridge_transfer NSData *)data; 52 | 53 | _out: 54 | if (data) { 55 | CFRelease(data); 56 | } 57 | 58 | return nil; 59 | } 60 | #endif 61 | 62 | static BOOL AFSecKeyIsEqualToKey(SecKeyRef key1, SecKeyRef key2) { 63 | #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) 64 | return [(__bridge id)key1 isEqual:(__bridge id)key2]; 65 | #else 66 | return [AFSecKeyGetData(key1) isEqual:AFSecKeyGetData(key2)]; 67 | #endif 68 | } 69 | 70 | static id AFPublicKeyForCertificate(NSData *certificate) { 71 | id allowedPublicKey = nil; 72 | SecCertificateRef allowedCertificate; 73 | SecCertificateRef allowedCertificates[1]; 74 | CFArrayRef tempCertificates = nil; 75 | SecPolicyRef policy = nil; 76 | SecTrustRef allowedTrust = nil; 77 | SecTrustResultType result; 78 | 79 | allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificate); 80 | AF_Require(allowedCertificate != NULL, _out); 81 | 82 | allowedCertificates[0] = allowedCertificate; 83 | tempCertificates = CFArrayCreate(NULL, (const void **)allowedCertificates, 1, NULL); 84 | 85 | policy = SecPolicyCreateBasicX509(); 86 | AF_Require_noErr(SecTrustCreateWithCertificates(tempCertificates, policy, &allowedTrust), _out); 87 | AF_Require_noErr(SecTrustEvaluate(allowedTrust, &result), _out); 88 | 89 | allowedPublicKey = (__bridge_transfer id)SecTrustCopyPublicKey(allowedTrust); 90 | 91 | _out: 92 | if (allowedTrust) { 93 | CFRelease(allowedTrust); 94 | } 95 | 96 | if (policy) { 97 | CFRelease(policy); 98 | } 99 | 100 | if (tempCertificates) { 101 | CFRelease(tempCertificates); 102 | } 103 | 104 | if (allowedCertificate) { 105 | CFRelease(allowedCertificate); 106 | } 107 | 108 | return allowedPublicKey; 109 | } 110 | 111 | static BOOL AFServerTrustIsValid(SecTrustRef serverTrust) { 112 | BOOL isValid = NO; 113 | SecTrustResultType result; 114 | AF_Require_noErr(SecTrustEvaluate(serverTrust, &result), _out); 115 | 116 | isValid = (result == kSecTrustResultUnspecified || result == kSecTrustResultProceed); 117 | 118 | _out: 119 | return isValid; 120 | } 121 | 122 | static NSArray * AFCertificateTrustChainForServerTrust(SecTrustRef serverTrust) { 123 | CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust); 124 | NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount]; 125 | 126 | for (CFIndex i = 0; i < certificateCount; i++) { 127 | SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i); 128 | [trustChain addObject:(__bridge_transfer NSData *)SecCertificateCopyData(certificate)]; 129 | } 130 | 131 | return [NSArray arrayWithArray:trustChain]; 132 | } 133 | 134 | static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) { 135 | SecPolicyRef policy = SecPolicyCreateBasicX509(); 136 | CFIndex certificateCount = SecTrustGetCertificateCount(serverTrust); 137 | NSMutableArray *trustChain = [NSMutableArray arrayWithCapacity:(NSUInteger)certificateCount]; 138 | for (CFIndex i = 0; i < certificateCount; i++) { 139 | SecCertificateRef certificate = SecTrustGetCertificateAtIndex(serverTrust, i); 140 | 141 | SecCertificateRef someCertificates[] = {certificate}; 142 | CFArrayRef certificates = CFArrayCreate(NULL, (const void **)someCertificates, 1, NULL); 143 | 144 | SecTrustRef trust; 145 | AF_Require_noErr(SecTrustCreateWithCertificates(certificates, policy, &trust), _out); 146 | 147 | SecTrustResultType result; 148 | AF_Require_noErr(SecTrustEvaluate(trust, &result), _out); 149 | 150 | [trustChain addObject:(__bridge_transfer id)SecTrustCopyPublicKey(trust)]; 151 | 152 | _out: 153 | if (trust) { 154 | CFRelease(trust); 155 | } 156 | 157 | if (certificates) { 158 | CFRelease(certificates); 159 | } 160 | 161 | continue; 162 | } 163 | CFRelease(policy); 164 | 165 | return [NSArray arrayWithArray:trustChain]; 166 | } 167 | 168 | #pragma mark - 169 | 170 | @interface AFSecurityPolicy() 171 | @property (readwrite, nonatomic, strong) NSArray *pinnedPublicKeys; 172 | @end 173 | 174 | @implementation AFSecurityPolicy 175 | 176 | + (NSArray *)defaultPinnedCertificates { 177 | static NSArray *_defaultPinnedCertificates = nil; 178 | static dispatch_once_t onceToken; 179 | dispatch_once(&onceToken, ^{ 180 | NSBundle *bundle = [NSBundle bundleForClass:[self class]]; 181 | NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"."]; 182 | 183 | NSMutableArray *certificates = [NSMutableArray arrayWithCapacity:[paths count]]; 184 | for (NSString *path in paths) { 185 | NSData *certificateData = [NSData dataWithContentsOfFile:path]; 186 | [certificates addObject:certificateData]; 187 | } 188 | 189 | _defaultPinnedCertificates = [[NSArray alloc] initWithArray:certificates]; 190 | }); 191 | 192 | return _defaultPinnedCertificates; 193 | } 194 | 195 | + (instancetype)defaultPolicy { 196 | AFSecurityPolicy *securityPolicy = [[self alloc] init]; 197 | securityPolicy.SSLPinningMode = AFSSLPinningModeNone; 198 | 199 | return securityPolicy; 200 | } 201 | 202 | + (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode { 203 | AFSecurityPolicy *securityPolicy = [[self alloc] init]; 204 | securityPolicy.SSLPinningMode = pinningMode; 205 | securityPolicy.validatesDomainName = YES; 206 | [securityPolicy setPinnedCertificates:[self defaultPinnedCertificates]]; 207 | 208 | return securityPolicy; 209 | } 210 | 211 | - (id)init { 212 | self = [super init]; 213 | if (!self) { 214 | return nil; 215 | } 216 | 217 | self.validatesCertificateChain = YES; 218 | 219 | return self; 220 | } 221 | 222 | #pragma mark - 223 | 224 | - (void)setPinnedCertificates:(NSArray *)pinnedCertificates { 225 | _pinnedCertificates = pinnedCertificates; 226 | 227 | if (self.pinnedCertificates) { 228 | NSMutableArray *mutablePinnedPublicKeys = [NSMutableArray arrayWithCapacity:[self.pinnedCertificates count]]; 229 | for (NSData *certificate in self.pinnedCertificates) { 230 | id publicKey = AFPublicKeyForCertificate(certificate); 231 | if (!publicKey) { 232 | continue; 233 | } 234 | [mutablePinnedPublicKeys addObject:publicKey]; 235 | } 236 | self.pinnedPublicKeys = [NSArray arrayWithArray:mutablePinnedPublicKeys]; 237 | } else { 238 | self.pinnedPublicKeys = nil; 239 | } 240 | } 241 | 242 | #pragma mark - 243 | 244 | - (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust { 245 | return [self evaluateServerTrust:serverTrust forDomain:nil]; 246 | } 247 | 248 | - (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust 249 | forDomain:(NSString *)domain 250 | { 251 | NSMutableArray *policies = [NSMutableArray array]; 252 | if (self.validatesDomainName) { 253 | [policies addObject:(__bridge_transfer id)SecPolicyCreateSSL(true, (__bridge CFStringRef)domain)]; 254 | } else { 255 | [policies addObject:(__bridge_transfer id)SecPolicyCreateBasicX509()]; 256 | } 257 | 258 | SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies); 259 | 260 | if (!AFServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates) { 261 | return NO; 262 | } 263 | 264 | NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust); 265 | switch (self.SSLPinningMode) { 266 | case AFSSLPinningModeNone: 267 | return YES; 268 | case AFSSLPinningModeCertificate: { 269 | NSMutableArray *pinnedCertificates = [NSMutableArray array]; 270 | for (NSData *certificateData in self.pinnedCertificates) { 271 | [pinnedCertificates addObject:(__bridge_transfer id)SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificateData)]; 272 | } 273 | SecTrustSetAnchorCertificates(serverTrust, (__bridge CFArrayRef)pinnedCertificates); 274 | 275 | if (!AFServerTrustIsValid(serverTrust)) { 276 | return NO; 277 | } 278 | 279 | if (!self.validatesCertificateChain) { 280 | return YES; 281 | } 282 | 283 | NSUInteger trustedCertificateCount = 0; 284 | for (NSData *trustChainCertificate in serverCertificates) { 285 | if ([self.pinnedCertificates containsObject:trustChainCertificate]) { 286 | trustedCertificateCount++; 287 | } 288 | } 289 | 290 | return trustedCertificateCount == [serverCertificates count]; 291 | } 292 | case AFSSLPinningModePublicKey: { 293 | NSUInteger trustedPublicKeyCount = 0; 294 | NSArray *publicKeys = AFPublicKeyTrustChainForServerTrust(serverTrust); 295 | if (!self.validatesCertificateChain && [publicKeys count] > 0) { 296 | publicKeys = @[[publicKeys firstObject]]; 297 | } 298 | 299 | for (id trustChainPublicKey in publicKeys) { 300 | for (id pinnedPublicKey in self.pinnedPublicKeys) { 301 | if (AFSecKeyIsEqualToKey((__bridge SecKeyRef)trustChainPublicKey, (__bridge SecKeyRef)pinnedPublicKey)) { 302 | trustedPublicKeyCount += 1; 303 | } 304 | } 305 | } 306 | 307 | return trustedPublicKeyCount > 0 && ((self.validatesCertificateChain && trustedPublicKeyCount == [serverCertificates count]) || (!self.validatesCertificateChain && trustedPublicKeyCount >= 1)); 308 | } 309 | } 310 | 311 | return NO; 312 | } 313 | 314 | #pragma mark - NSKeyValueObserving 315 | 316 | + (NSSet *)keyPathsForValuesAffectingPinnedPublicKeys { 317 | return [NSSet setWithObject:@"pinnedCertificates"]; 318 | } 319 | 320 | @end 321 | -------------------------------------------------------------------------------- /QiniuSDK/AFNetworking/AFURLConnectionOperation.h: -------------------------------------------------------------------------------- 1 | // AFURLConnectionOperation.h 2 | // 3 | // Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) 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 24 | 25 | #import 26 | #import "AFURLRequestSerialization.h" 27 | #import "AFURLResponseSerialization.h" 28 | #import "AFSecurityPolicy.h" 29 | 30 | /** 31 | `AFURLConnectionOperation` is a subclass of `NSOperation` that implements `NSURLConnection` delegate methods. 32 | 33 | ## Subclassing Notes 34 | 35 | This is the base class of all network request operations. You may wish to create your own subclass in order to implement additional `NSURLConnection` delegate methods (see "`NSURLConnection` Delegate Methods" below), or to provide additional properties and/or class constructors. 36 | 37 | If you are creating a subclass that communicates over the HTTP or HTTPS protocols, you may want to consider subclassing `AFHTTPRequestOperation` instead, as it supports specifying acceptable content types or status codes. 38 | 39 | ## NSURLConnection Delegate Methods 40 | 41 | `AFURLConnectionOperation` implements the following `NSURLConnection` delegate methods: 42 | 43 | - `connection:didReceiveResponse:` 44 | - `connection:didReceiveData:` 45 | - `connectionDidFinishLoading:` 46 | - `connection:didFailWithError:` 47 | - `connection:didSendBodyData:totalBytesWritten:totalBytesExpectedToWrite:` 48 | - `connection:willCacheResponse:` 49 | - `connectionShouldUseCredentialStorage:` 50 | - `connection:needNewBodyStream:` 51 | - `connection:willSendRequestForAuthenticationChallenge:` 52 | 53 | If any of these methods are overridden in a subclass, they _must_ call the `super` implementation first. 54 | 55 | ## Callbacks and Completion Blocks 56 | 57 | The built-in `completionBlock` provided by `NSOperation` allows for custom behavior to be executed after the request finishes. It is a common pattern for class constructors in subclasses to take callback block parameters, and execute them conditionally in the body of its `completionBlock`. Make sure to handle cancelled operations appropriately when setting a `completionBlock` (i.e. returning early before parsing response data). See the implementation of any of the `AFHTTPRequestOperation` subclasses for an example of this. 58 | 59 | Subclasses are strongly discouraged from overriding `setCompletionBlock:`, as `AFURLConnectionOperation`'s implementation includes a workaround to mitigate retain cycles, and what Apple rather ominously refers to as ["The Deallocation Problem"](http://developer.apple.com/library/ios/#technotes/tn2109/). 60 | 61 | ## SSL Pinning 62 | 63 | Relying on the CA trust model to validate SSL certificates exposes your app to security vulnerabilities, such as man-in-the-middle attacks. For applications that connect to known servers, SSL certificate pinning provides an increased level of security, by checking server certificate validity against those specified in the app bundle. 64 | 65 | SSL with certificate pinning is strongly recommended for any application that transmits sensitive information to an external webservice. 66 | 67 | Connections will be validated on all matching certificates with a `.cer` extension in the bundle root. 68 | 69 | ## App Extensions 70 | 71 | When using AFNetworking in an App Extension, `#define AF_APP_EXTENSIONS` to avoid using unavailable APIs. 72 | 73 | ## NSCoding & NSCopying Conformance 74 | 75 | `AFURLConnectionOperation` conforms to the `NSCoding` and `NSCopying` protocols, allowing operations to be archived to disk, and copied in memory, respectively. However, because of the intrinsic limitations of capturing the exact state of an operation at a particular moment, there are some important caveats to keep in mind: 76 | 77 | ### NSCoding Caveats 78 | 79 | - Encoded operations do not include any block or stream properties. Be sure to set `completionBlock`, `outputStream`, and any callback blocks as necessary when using `-initWithCoder:` or `NSKeyedUnarchiver`. 80 | - Operations are paused on `encodeWithCoder:`. If the operation was encoded while paused or still executing, its archived state will return `YES` for `isReady`. Otherwise, the state of an operation when encoding will remain unchanged. 81 | 82 | ### NSCopying Caveats 83 | 84 | - `-copy` and `-copyWithZone:` return a new operation with the `NSURLRequest` of the original. So rather than an exact copy of the operation at that particular instant, the copying mechanism returns a completely new instance, which can be useful for retrying operations. 85 | - A copy of an operation will not include the `outputStream` of the original. 86 | - Operation copies do not include `completionBlock`, as it often strongly captures a reference to `self`, which would otherwise have the unintuitive side-effect of pointing to the _original_ operation when copied. 87 | */ 88 | 89 | @interface AFURLConnectionOperation : NSOperation 90 | 91 | ///------------------------------- 92 | /// @name Accessing Run Loop Modes 93 | ///------------------------------- 94 | 95 | /** 96 | The run loop modes in which the operation will run on the network thread. By default, this is a single-member set containing `NSRunLoopCommonModes`. 97 | */ 98 | @property (nonatomic, strong) NSSet *runLoopModes; 99 | 100 | ///----------------------------------------- 101 | /// @name Getting URL Connection Information 102 | ///----------------------------------------- 103 | 104 | /** 105 | The request used by the operation's connection. 106 | */ 107 | @property (readonly, nonatomic, strong) NSURLRequest *request; 108 | 109 | /** 110 | The last response received by the operation's connection. 111 | */ 112 | @property (readonly, nonatomic, strong) NSURLResponse *response; 113 | 114 | /** 115 | The error, if any, that occurred in the lifecycle of the request. 116 | */ 117 | @property (readonly, nonatomic, strong) NSError *error; 118 | 119 | ///---------------------------- 120 | /// @name Getting Response Data 121 | ///---------------------------- 122 | 123 | /** 124 | The data received during the request. 125 | */ 126 | @property (readonly, nonatomic, strong) NSData *responseData; 127 | 128 | /** 129 | The string representation of the response data. 130 | */ 131 | @property (readonly, nonatomic, copy) NSString *responseString; 132 | 133 | /** 134 | The string encoding of the response. 135 | 136 | If the response does not specify a valid string encoding, `responseStringEncoding` will return `NSUTF8StringEncoding`. 137 | */ 138 | @property (readonly, nonatomic, assign) NSStringEncoding responseStringEncoding; 139 | 140 | ///------------------------------- 141 | /// @name Managing URL Credentials 142 | ///------------------------------- 143 | 144 | /** 145 | Whether the URL connection should consult the credential storage for authenticating the connection. `YES` by default. 146 | 147 | This is the value that is returned in the `NSURLConnectionDelegate` method `-connectionShouldUseCredentialStorage:`. 148 | */ 149 | @property (nonatomic, assign) BOOL shouldUseCredentialStorage; 150 | 151 | /** 152 | The credential used for authentication challenges in `-connection:didReceiveAuthenticationChallenge:`. 153 | 154 | This will be overridden by any shared credentials that exist for the username or password of the request URL, if present. 155 | */ 156 | @property (nonatomic, strong) NSURLCredential *credential; 157 | 158 | ///------------------------------- 159 | /// @name Managing Security Policy 160 | ///------------------------------- 161 | 162 | /** 163 | The security policy used to evaluate server trust for secure connections. 164 | */ 165 | @property (nonatomic, strong) AFSecurityPolicy *securityPolicy; 166 | 167 | ///------------------------ 168 | /// @name Accessing Streams 169 | ///------------------------ 170 | 171 | /** 172 | The input stream used to read data to be sent during the request. 173 | 174 | This property acts as a proxy to the `HTTPBodyStream` property of `request`. 175 | */ 176 | @property (nonatomic, strong) NSInputStream *inputStream; 177 | 178 | /** 179 | The output stream that is used to write data received until the request is finished. 180 | 181 | By default, data is accumulated into a buffer that is stored into `responseData` upon completion of the request, with the intermediary `outputStream` property set to `nil`. When `outputStream` is set, the data will not be accumulated into an internal buffer, and as a result, the `responseData` property of the completed request will be `nil`. The output stream will be scheduled in the network thread runloop upon being set. 182 | */ 183 | @property (nonatomic, strong) NSOutputStream *outputStream; 184 | 185 | ///--------------------------------- 186 | /// @name Managing Callback Queues 187 | ///--------------------------------- 188 | 189 | /** 190 | The dispatch queue for `completionBlock`. If `NULL` (default), the main queue is used. 191 | */ 192 | @property (nonatomic, strong) dispatch_queue_t completionQueue; 193 | 194 | /** 195 | The dispatch group for `completionBlock`. If `NULL` (default), a private dispatch group is used. 196 | */ 197 | @property (nonatomic, strong) dispatch_group_t completionGroup; 198 | 199 | ///--------------------------------------------- 200 | /// @name Managing Request Operation Information 201 | ///--------------------------------------------- 202 | 203 | /** 204 | The user info dictionary for the receiver. 205 | */ 206 | @property (nonatomic, strong) NSDictionary *userInfo; 207 | 208 | ///------------------------------------------------------ 209 | /// @name Initializing an AFURLConnectionOperation Object 210 | ///------------------------------------------------------ 211 | 212 | /** 213 | Initializes and returns a newly allocated operation object with a url connection configured with the specified url request. 214 | 215 | This is the designated initializer. 216 | 217 | @param urlRequest The request object to be used by the operation connection. 218 | */ 219 | - (instancetype)initWithRequest:(NSURLRequest *)urlRequest; 220 | 221 | ///---------------------------------- 222 | /// @name Pausing / Resuming Requests 223 | ///---------------------------------- 224 | 225 | /** 226 | Pauses the execution of the request operation. 227 | 228 | A paused operation returns `NO` for `-isReady`, `-isExecuting`, and `-isFinished`. As such, it will remain in an `NSOperationQueue` until it is either cancelled or resumed. Pausing a finished, cancelled, or paused operation has no effect. 229 | */ 230 | - (void)pause; 231 | 232 | /** 233 | Whether the request operation is currently paused. 234 | 235 | @return `YES` if the operation is currently paused, otherwise `NO`. 236 | */ 237 | - (BOOL)isPaused; 238 | 239 | /** 240 | Resumes the execution of the paused request operation. 241 | 242 | Pause/Resume behavior varies depending on the underlying implementation for the operation class. In its base implementation, resuming a paused requests restarts the original request. However, since HTTP defines a specification for how to request a specific content range, `AFHTTPRequestOperation` will resume downloading the request from where it left off, instead of restarting the original request. 243 | */ 244 | - (void)resume; 245 | 246 | ///---------------------------------------------- 247 | /// @name Configuring Backgrounding Task Behavior 248 | ///---------------------------------------------- 249 | 250 | /** 251 | Specifies that the operation should continue execution after the app has entered the background, and the expiration handler for that background task. 252 | 253 | @param handler A handler to be called shortly before the application’s remaining background time reaches 0. The handler is wrapped in a block that cancels the operation, and cleans up and marks the end of execution, unlike the `handler` parameter in `UIApplication -beginBackgroundTaskWithExpirationHandler:`, which expects this to be done in the handler itself. The handler is called synchronously on the main thread, thus blocking the application’s suspension momentarily while the application is notified. 254 | */ 255 | #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && !defined(AF_APP_EXTENSIONS) 256 | - (void)setShouldExecuteAsBackgroundTaskWithExpirationHandler:(void (^)(void))handler; 257 | #endif 258 | 259 | ///--------------------------------- 260 | /// @name Setting Progress Callbacks 261 | ///--------------------------------- 262 | 263 | /** 264 | Sets a callback to be called when an undetermined number of bytes have been uploaded to the server. 265 | 266 | @param block A block object to be called when an undetermined number of bytes have been uploaded to the server. This block has no return value and takes three arguments: the number of bytes written since the last time the upload progress block was called, the total bytes written, and the total bytes expected to be written during the request, as initially determined by the length of the HTTP body. This block may be called multiple times, and will execute on the main thread. 267 | */ 268 | - (void)setUploadProgressBlock:(void (^)(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite))block; 269 | 270 | /** 271 | Sets a callback to be called when an undetermined number of bytes have been downloaded from the server. 272 | 273 | @param block A block object to be called when an undetermined number of bytes have been downloaded from the server. This block has no return value and takes three arguments: the number of bytes read since the last time the download progress block was called, the total bytes read, and the total bytes expected to be read during the request, as initially determined by the expected content size of the `NSHTTPURLResponse` object. This block may be called multiple times, and will execute on the main thread. 274 | */ 275 | - (void)setDownloadProgressBlock:(void (^)(NSUInteger bytesRead, long long totalBytesRead, long long totalBytesExpectedToRead))block; 276 | 277 | ///------------------------------------------------- 278 | /// @name Setting NSURLConnection Delegate Callbacks 279 | ///------------------------------------------------- 280 | 281 | /** 282 | Sets a block to be executed when the connection will authenticate a challenge in order to download its request, as handled by the `NSURLConnectionDelegate` method `connection:willSendRequestForAuthenticationChallenge:`. 283 | 284 | @param block A block object to be executed when the connection will authenticate a challenge in order to download its request. The block has no return type and takes two arguments: the URL connection object, and the challenge that must be authenticated. This block must invoke one of the challenge-responder methods (NSURLAuthenticationChallengeSender protocol). 285 | 286 | If `allowsInvalidSSLCertificate` is set to YES, `connection:willSendRequestForAuthenticationChallenge:` will attempt to have the challenge sender use credentials with invalid SSL certificates. 287 | */ 288 | - (void)setWillSendRequestForAuthenticationChallengeBlock:(void (^)(NSURLConnection *connection, NSURLAuthenticationChallenge *challenge))block; 289 | 290 | /** 291 | Sets a block to be executed when the server redirects the request from one URL to another URL, or when the request URL changed by the `NSURLProtocol` subclass handling the request in order to standardize its format, as handled by the `NSURLConnectionDataDelegate` method `connection:willSendRequest:redirectResponse:`. 292 | 293 | @param block A block object to be executed when the request URL was changed. The block returns an `NSURLRequest` object, the URL request to redirect, and takes three arguments: the URL connection object, the the proposed redirected request, and the URL response that caused the redirect. 294 | */ 295 | - (void)setRedirectResponseBlock:(NSURLRequest * (^)(NSURLConnection *connection, NSURLRequest *request, NSURLResponse *redirectResponse))block; 296 | 297 | 298 | /** 299 | Sets a block to be executed to modify the response a connection will cache, if any, as handled by the `NSURLConnectionDelegate` method `connection:willCacheResponse:`. 300 | 301 | @param block A block object to be executed to determine what response a connection will cache, if any. The block returns an `NSCachedURLResponse` object, the cached response to store in memory or `nil` to prevent the response from being cached, and takes two arguments: the URL connection object, and the cached response provided for the request. 302 | */ 303 | - (void)setCacheResponseBlock:(NSCachedURLResponse * (^)(NSURLConnection *connection, NSCachedURLResponse *cachedResponse))block; 304 | 305 | /// 306 | 307 | /** 308 | 309 | */ 310 | + (NSArray *)batchOfRequestOperations:(NSArray *)operations 311 | progressBlock:(void (^)(NSUInteger numberOfFinishedOperations, NSUInteger totalNumberOfOperations))progressBlock 312 | completionBlock:(void (^)(NSArray *operations))completionBlock; 313 | 314 | @end 315 | 316 | ///-------------------- 317 | /// @name Notifications 318 | ///-------------------- 319 | 320 | /** 321 | Posted when an operation begins executing. 322 | */ 323 | extern NSString * const AFNetworkingOperationDidStartNotification; 324 | 325 | /** 326 | Posted when an operation finishes. 327 | */ 328 | extern NSString * const AFNetworkingOperationDidFinishNotification; 329 | -------------------------------------------------------------------------------- /QiniuSDK/AFNetworking/AFURLResponseSerialization.h: -------------------------------------------------------------------------------- 1 | // AFSerialization.h 2 | // 3 | // Copyright (c) 2013-2014 AFNetworking (http://afnetworking.com) 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 24 | #import 25 | 26 | /** 27 | The `AFURLResponseSerialization` protocol is adopted by an object that decodes data into a more useful object representation, according to details in the server response. Response serializers may additionally perform validation on the incoming response and data. 28 | 29 | For example, a JSON response serializer may check for an acceptable status code (`2XX` range) and content type (`application/json`), decoding a valid JSON response into an object. 30 | */ 31 | @protocol AFURLResponseSerialization 32 | 33 | /** 34 | The response object decoded from the data associated with a specified response. 35 | 36 | @param response The response to be processed. 37 | @param data The response data to be decoded. 38 | @param error The error that occurred while attempting to decode the response data. 39 | 40 | @return The object decoded from the specified response data. 41 | */ 42 | - (id)responseObjectForResponse:(NSURLResponse *)response 43 | data:(NSData *)data 44 | error:(NSError *__autoreleasing *)error; 45 | 46 | @end 47 | 48 | #pragma mark - 49 | 50 | /** 51 | `AFHTTPResponseSerializer` conforms to the `AFURLRequestSerialization` & `AFURLResponseSerialization` protocols, offering a concrete base implementation of query string / URL form-encoded parameter serialization and default request headers, as well as response status code and content type validation. 52 | 53 | Any request or response serializer dealing with HTTP is encouraged to subclass `AFHTTPResponseSerializer` in order to ensure consistent default behavior. 54 | */ 55 | @interface AFHTTPResponseSerializer : NSObject 56 | 57 | /** 58 | The string encoding used to serialize parameters. 59 | */ 60 | @property (nonatomic, assign) NSStringEncoding stringEncoding; 61 | 62 | /** 63 | Creates and returns a serializer with default configuration. 64 | */ 65 | + (instancetype)serializer; 66 | 67 | ///----------------------------------------- 68 | /// @name Configuring Response Serialization 69 | ///----------------------------------------- 70 | 71 | /** 72 | The acceptable HTTP status codes for responses. When non-`nil`, responses with status codes not contained by the set will result in an error during validation. 73 | 74 | See http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html 75 | */ 76 | @property (nonatomic, copy) NSIndexSet *acceptableStatusCodes; 77 | 78 | /** 79 | The acceptable MIME types for responses. When non-`nil`, responses with a `Content-Type` with MIME types that do not intersect with the set will result in an error during validation. 80 | */ 81 | @property (nonatomic, copy) NSSet *acceptableContentTypes; 82 | 83 | /** 84 | Validates the specified response and data. 85 | 86 | In its base implementation, this method checks for an acceptable status code and content type. Subclasses may wish to add other domain-specific checks. 87 | 88 | @param response The response to be validated. 89 | @param data The data associated with the response. 90 | @param error The error that occurred while attempting to validate the response. 91 | 92 | @return `YES` if the response is valid, otherwise `NO`. 93 | */ 94 | - (BOOL)validateResponse:(NSHTTPURLResponse *)response 95 | data:(NSData *)data 96 | error:(NSError *__autoreleasing *)error; 97 | 98 | @end 99 | 100 | #pragma mark - 101 | 102 | 103 | /** 104 | `AFJSONResponseSerializer` is a subclass of `AFHTTPResponseSerializer` that validates and decodes JSON responses. 105 | 106 | By default, `AFJSONResponseSerializer` accepts the following MIME types, which includes the official standard, `application/json`, as well as other commonly-used types: 107 | 108 | - `application/json` 109 | - `text/json` 110 | - `text/javascript` 111 | */ 112 | @interface AFJSONResponseSerializer : AFHTTPResponseSerializer 113 | 114 | /** 115 | Options for reading the response JSON data and creating the Foundation objects. For possible values, see the `NSJSONSerialization` documentation section "NSJSONReadingOptions". `0` by default. 116 | */ 117 | @property (nonatomic, assign) NSJSONReadingOptions readingOptions; 118 | 119 | /** 120 | Whether to remove keys with `NSNull` values from response JSON. Defaults to `NO`. 121 | */ 122 | @property (nonatomic, assign) BOOL removesKeysWithNullValues; 123 | 124 | /** 125 | Creates and returns a JSON serializer with specified reading and writing options. 126 | 127 | @param readingOptions The specified JSON reading options. 128 | */ 129 | + (instancetype)serializerWithReadingOptions:(NSJSONReadingOptions)readingOptions; 130 | 131 | @end 132 | 133 | #pragma mark - 134 | 135 | /** 136 | `AFXMLParserSerializer` is a subclass of `AFHTTPResponseSerializer` that validates and decodes XML responses as an `NSXMLParser` objects. 137 | 138 | By default, `AFXMLParserSerializer` accepts the following MIME types, which includes the official standard, `application/xml`, as well as other commonly-used types: 139 | 140 | - `application/xml` 141 | - `text/xml` 142 | */ 143 | @interface AFXMLParserResponseSerializer : AFHTTPResponseSerializer 144 | 145 | @end 146 | 147 | #pragma mark - 148 | 149 | #ifdef __MAC_OS_X_VERSION_MIN_REQUIRED 150 | 151 | /** 152 | `AFXMLDocumentSerializer` is a subclass of `AFHTTPResponseSerializer` that validates and decodes XML responses as an `NSXMLDocument` objects. 153 | 154 | By default, `AFXMLDocumentSerializer` accepts the following MIME types, which includes the official standard, `application/xml`, as well as other commonly-used types: 155 | 156 | - `application/xml` 157 | - `text/xml` 158 | */ 159 | @interface AFXMLDocumentResponseSerializer : AFHTTPResponseSerializer 160 | 161 | /** 162 | Input and output options specifically intended for `NSXMLDocument` objects. For possible values, see the `NSJSONSerialization` documentation section "NSJSONReadingOptions". `0` by default. 163 | */ 164 | @property (nonatomic, assign) NSUInteger options; 165 | 166 | /** 167 | Creates and returns an XML document serializer with the specified options. 168 | 169 | @param mask The XML document options. 170 | */ 171 | + (instancetype)serializerWithXMLDocumentOptions:(NSUInteger)mask; 172 | 173 | @end 174 | 175 | #endif 176 | 177 | #pragma mark - 178 | 179 | /** 180 | `AFPropertyListSerializer` is a subclass of `AFHTTPResponseSerializer` that validates and decodes XML responses as an `NSXMLDocument` objects. 181 | 182 | By default, `AFPropertyListSerializer` accepts the following MIME types: 183 | 184 | - `application/x-plist` 185 | */ 186 | @interface AFPropertyListResponseSerializer : AFHTTPResponseSerializer 187 | 188 | /** 189 | The property list format. Possible values are described in "NSPropertyListFormat". 190 | */ 191 | @property (nonatomic, assign) NSPropertyListFormat format; 192 | 193 | /** 194 | The property list reading options. Possible values are described in "NSPropertyListMutabilityOptions." 195 | */ 196 | @property (nonatomic, assign) NSPropertyListReadOptions readOptions; 197 | 198 | /** 199 | Creates and returns a property list serializer with a specified format, read options, and write options. 200 | 201 | @param format The property list format. 202 | @param readOptions The property list reading options. 203 | */ 204 | + (instancetype)serializerWithFormat:(NSPropertyListFormat)format 205 | readOptions:(NSPropertyListReadOptions)readOptions; 206 | 207 | @end 208 | 209 | #pragma mark - 210 | 211 | /** 212 | `AFImageSerializer` is a subclass of `AFHTTPResponseSerializer` that validates and decodes image responses. 213 | 214 | By default, `AFImageSerializer` accepts the following MIME types, which correspond to the image formats supported by UIImage or NSImage: 215 | 216 | - `image/tiff` 217 | - `image/jpeg` 218 | - `image/gif` 219 | - `image/png` 220 | - `image/ico` 221 | - `image/x-icon` 222 | - `image/bmp` 223 | - `image/x-bmp` 224 | - `image/x-xbitmap` 225 | - `image/x-win-bitmap` 226 | */ 227 | @interface AFImageResponseSerializer : AFHTTPResponseSerializer 228 | 229 | #if defined(__IPHONE_OS_VERSION_MIN_REQUIRED) 230 | /** 231 | The scale factor used when interpreting the image data to construct `responseImage`. Specifying a scale factor of 1.0 results in an image whose size matches the pixel-based dimensions of the image. Applying a different scale factor changes the size of the image as reported by the size property. This is set to the value of scale of the main screen by default, which automatically scales images for retina displays, for instance. 232 | */ 233 | @property (nonatomic, assign) CGFloat imageScale; 234 | 235 | /** 236 | Whether to automatically inflate response image data for compressed formats (such as PNG or JPEG). Enabling this can significantly improve drawing performance on iOS when used with `setCompletionBlockWithSuccess:failure:`, as it allows a bitmap representation to be constructed in the background rather than on the main thread. `YES` by default. 237 | */ 238 | @property (nonatomic, assign) BOOL automaticallyInflatesResponseImage; 239 | #endif 240 | 241 | @end 242 | 243 | #pragma mark - 244 | 245 | /** 246 | `AFCompoundSerializer` is a subclass of `AFHTTPResponseSerializer` that delegates the response serialization to the first `AFHTTPResponseSerializer` object that returns an object for `responseObjectForResponse:data:error:`, falling back on the default behavior of `AFHTTPResponseSerializer`. This is useful for supporting multiple potential types and structures of server responses with a single serializer. 247 | */ 248 | @interface AFCompoundResponseSerializer : AFHTTPResponseSerializer 249 | 250 | /** 251 | The component response serializers. 252 | */ 253 | @property (readonly, nonatomic, copy) NSArray *responseSerializers; 254 | 255 | /** 256 | Creates and returns a compound serializer comprised of the specified response serializers. 257 | 258 | @warning Each response serializer specified must be a subclass of `AFHTTPResponseSerializer`, and response to `-validateResponse:data:error:`. 259 | */ 260 | + (instancetype)compoundSerializerWithResponseSerializers:(NSArray *)responseSerializers; 261 | 262 | @end 263 | 264 | ///---------------- 265 | /// @name Constants 266 | ///---------------- 267 | 268 | /** 269 | ## Error Domains 270 | 271 | The following error domain is predefined. 272 | 273 | - `NSString * const AFURLResponseSerializationErrorDomain` 274 | 275 | ### Constants 276 | 277 | `AFURLResponseSerializationErrorDomain` 278 | AFURLResponseSerializer errors. Error codes for `AFURLResponseSerializationErrorDomain` correspond to codes in `NSURLErrorDomain`. 279 | */ 280 | extern NSString * const AFURLResponseSerializationErrorDomain; 281 | 282 | /** 283 | ## User info dictionary keys 284 | 285 | These keys may exist in the user info dictionary, in addition to those defined for NSError. 286 | 287 | - `NSString * const AFNetworkingOperationFailingURLResponseErrorKey` 288 | - `NSString * const AFNetworkingOperationFailingURLResponseDataErrorKey` 289 | 290 | ### Constants 291 | 292 | `AFNetworkingOperationFailingURLResponseErrorKey` 293 | The corresponding value is an `NSURLResponse` containing the response of the operation associated with an error. This key is only present in the `AFURLResponseSerializationErrorDomain`. 294 | 295 | `AFNetworkingOperationFailingURLResponseDataErrorKey` 296 | The corresponding value is an `NSData` containing the original data of the operation associated with an error. This key is only present in the `AFURLResponseSerializationErrorDomain`. 297 | */ 298 | extern NSString * const AFNetworkingOperationFailingURLResponseErrorKey; 299 | 300 | extern NSString * const AFNetworkingOperationFailingURLResponseDataErrorKey; 301 | 302 | 303 | -------------------------------------------------------------------------------- /QiniuSDK/QiniuBlkputRet.h: -------------------------------------------------------------------------------- 1 | // 2 | // QiniuBlkputRet.h 3 | // QiniuSDK 4 | // 5 | // Created by ltz on 14-2-27. 6 | // Copyright (c) 2014年 Qiniu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface QiniuBlkputRet : NSObject 12 | 13 | - (QiniuBlkputRet *)initWithDictionary:(NSDictionary *)dictionary; 14 | 15 | @property (copy, nonatomic) NSString *ctx; 16 | @property (copy, nonatomic) NSString *checksum; 17 | @property (copy, nonatomic) NSString *host; 18 | 19 | @property int crc32; 20 | @property int offset; 21 | 22 | @end 23 | -------------------------------------------------------------------------------- /QiniuSDK/QiniuBlkputRet.m: -------------------------------------------------------------------------------- 1 | // 2 | // QiniuBlkputRet.m 3 | // QiniuSDK 4 | // 5 | // Created by ltz on 14-2-27. 6 | // Copyright (c) 2014年 Qiniu. All rights reserved. 7 | // 8 | 9 | #import "QiniuBlkputRet.h" 10 | 11 | @implementation QiniuBlkputRet 12 | 13 | - (QiniuBlkputRet *)initWithDictionary:(NSDictionary *)dictionary 14 | { 15 | self = [super init]; 16 | 17 | self.ctx = [dictionary valueForKey:@"ctx"]; 18 | self.crc32 = [[dictionary valueForKey:@"crc32"] intValue]; 19 | self.offset = [[dictionary valueForKey:@"offset"] intValue]; 20 | self.host = [dictionary valueForKey:@"host"]; 21 | 22 | return self; 23 | } 24 | 25 | - (void) encodeWithCoder:(NSCoder *)aCoder { 26 | [aCoder encodeObject:self.host forKey:@"host"]; 27 | [aCoder encodeObject:self.ctx forKey:@"ctx"]; 28 | [aCoder encodeInt:self.offset forKey:@"offset"]; 29 | } 30 | 31 | - (id) initWithCoder:(NSCoder *)aDecoder { 32 | if (self = [super init]) { 33 | self.host = [aDecoder decodeObjectForKey:@"host"]; 34 | self.ctx = [aDecoder decodeObjectForKey:@"ctx"]; 35 | self.offset = [aDecoder decodeIntForKey:@"offset"]; 36 | } 37 | return self; 38 | } 39 | 40 | 41 | @end -------------------------------------------------------------------------------- /QiniuSDK/QiniuConfig.h: -------------------------------------------------------------------------------- 1 | // 2 | // QiniuConfig.h 3 | // QiniuSDK 4 | // 5 | // Created by Qiniu Developers 2013 6 | // 7 | 8 | #import 9 | 10 | #define kQiniuUndefinedKey @"?" 11 | 12 | #define kQiniuVersion @"6.3.3" 13 | 14 | #define kQiniuUpHostsLast 1 15 | NSString *kQiniuUpHosts[kQiniuUpHostsLast+1]; 16 | -------------------------------------------------------------------------------- /QiniuSDK/QiniuConfig.m: -------------------------------------------------------------------------------- 1 | // 2 | // QiniuConfig.h 3 | // QiniuSDK 4 | // 5 | // Created by Qiniu Developers 2013 6 | // 7 | 8 | #import "QiniuConfig.h" 9 | 10 | 11 | NSString *kQiniuUpHosts[] = {@"http://upload.qiniu.com", @"http://up.qiniu.com"}; -------------------------------------------------------------------------------- /QiniuSDK/QiniuHttpClient.h: -------------------------------------------------------------------------------- 1 | // 2 | // QiniuClient.h 3 | // QiniuSDK 4 | // 5 | // Created by 张光宇 on 2/9/14. 6 | // Copyright (c) 2014 Shanghai Qiniu Information Technologies Co., Ltd. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AFNetworking/AFNetworking.h" 11 | typedef void (^QNBooleanResultBlock)(BOOL succeeded, NSError *error); 12 | typedef void (^QNArrayResultBlock)(NSArray *result, NSError *error); 13 | typedef void (^QNObjectResultBlock)(id object, NSError *error); 14 | @class QiniuPutExtra; 15 | 16 | 17 | #define QiniuClient [QiniuHttpClient manager] 18 | 19 | @interface QiniuHttpClient : AFHTTPRequestOperationManager 20 | - (AFHTTPRequestOperation *)uploadFile:(NSString *)filePath 21 | key:(NSString *)key 22 | token:(NSString *)token 23 | extra:(QiniuPutExtra *)extra 24 | uphost:(NSString *)uphost 25 | progress:(void (^)(float percent))progressBlock 26 | complete:(QNObjectResultBlock)complete; 27 | 28 | - (AFHTTPRequestOperation *)uploadFileData:(NSData *)data 29 | key:(NSString *)key 30 | token:(NSString *)token 31 | extra:(QiniuPutExtra *)extra 32 | uphost:(NSString *)uphost 33 | progress:(void (^)(float percent))progressBlock 34 | complete:(QNObjectResultBlock)complete; 35 | @end 36 | 37 | 38 | 39 | 40 | 41 | @interface QiniuPutExtra : NSObject 42 | 43 | // user comtom params, refer to http://docs.qiniu.com/api/put.html#xVariables 44 | @property (retain, nonatomic) NSDictionary *params; 45 | 46 | // specify file's mimeType, or server side automatically determine the mimeType. 47 | @property (copy, nonatomic) NSString *mimeType; 48 | 49 | // specify file's crc32 value. 50 | // server side can check it for integrity accodring to the value of checkCrc. 51 | @property UInt32 crc32; 52 | 53 | // if checkCrc is 0, server side will not check crc32. 54 | // if checkCrc is 1, server side will check crc32 using the value of crc32. 55 | @property UInt32 checkCrc; 56 | 57 | - (NSDictionary *)convertToPostParams; 58 | 59 | @end 60 | -------------------------------------------------------------------------------- /QiniuSDK/QiniuHttpClient.m: -------------------------------------------------------------------------------- 1 | 2 | // 3 | // QiniuClient.m 4 | // QiniuSDK 5 | // 6 | // Created by 张光宇 on 2/9/14. 7 | // Copyright (c) 2014 Shanghai Qiniu Information Technologies Co., Ltd. All rights reserved. 8 | // 9 | 10 | #import "QiniuHttpClient.h" 11 | #import "QiniuConfig.h" 12 | #import "QiniuUtils.h" 13 | 14 | @implementation QiniuHttpClient 15 | 16 | + (instancetype)sharedInstance{ 17 | static QiniuHttpClient *_sharedInstance = nil; 18 | static dispatch_once_t onceToken; 19 | dispatch_once(&onceToken, ^{ 20 | _sharedInstance = [[self alloc] init]; 21 | // assert(_DefaultSpaceName); 22 | // _sharedInstance.spaceName = _DefaultSpaceName; 23 | }); 24 | return _sharedInstance; 25 | } 26 | 27 | - (AFHTTPRequestOperation *)uploadFile:(NSString *)filePath 28 | key:(NSString *)key 29 | token:(NSString *)token 30 | extra:(QiniuPutExtra *)extra 31 | uphost:(NSString *)uphost 32 | progress:(void (^)(float percent))progressBlock 33 | complete:(QNObjectResultBlock)complete{ 34 | 35 | NSParameterAssert(filePath); 36 | NSParameterAssert(token); 37 | NSError *error = nil; 38 | [[[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:&error] fileSize]; 39 | 40 | if (error) { 41 | complete(nil,error); 42 | return nil; 43 | } 44 | 45 | NSData *data = [NSData dataWithContentsOfFile:filePath]; 46 | return [self uploadFileData:data 47 | key:key 48 | token:token 49 | extra:extra 50 | uphost:uphost 51 | progress:progressBlock 52 | complete:complete]; 53 | } 54 | 55 | - (AFHTTPRequestOperation *)uploadFileData:(NSData *)data 56 | key:(NSString *)key 57 | token:(NSString *)token 58 | extra:(QiniuPutExtra *)extra 59 | uphost:(NSString *)uphost 60 | progress:(void (^)(float percent))progressBlock 61 | complete:(QNObjectResultBlock)complete{ 62 | 63 | NSParameterAssert(data); 64 | NSParameterAssert(token); 65 | 66 | NSMutableDictionary *parameters = [NSMutableDictionary dictionary]; 67 | 68 | if (key && ![key isEqualToString:kQiniuUndefinedKey]) { 69 | parameters[@"key"] = key; 70 | } 71 | if (!key) { 72 | key = kQiniuUndefinedKey; 73 | } 74 | 75 | parameters[@"token"] = token; 76 | 77 | if (extra) { 78 | [parameters addEntriesFromDictionary:extra.convertToPostParams]; 79 | } 80 | 81 | NSString *mimeType = extra.mimeType; 82 | if (!mimeType) { 83 | mimeType = @"application/octet-stream"; 84 | } 85 | 86 | NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" 87 | URLString:uphost 88 | parameters:parameters 89 | constructingBodyWithBlock:^(id formData) { 90 | 91 | [formData appendPartWithFileData:data 92 | name:@"file" 93 | fileName:key 94 | mimeType:mimeType]; 95 | } error:nil]; 96 | 97 | 98 | AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request 99 | success:^(AFHTTPRequestOperation *operation, id responseObject) { 100 | complete(operation,nil); 101 | } failure:^(AFHTTPRequestOperation *operation, NSError *error) { 102 | complete(operation,error); 103 | }]; 104 | 105 | [operation setUploadProgressBlock:^(NSUInteger bytesWritten, long long totalBytesWritten, long long totalBytesExpectedToWrite) { 106 | progressBlock((float)totalBytesWritten / (float)totalBytesExpectedToWrite); 107 | }]; 108 | [self.operationQueue addOperation:operation]; 109 | return operation; 110 | } 111 | 112 | 113 | - (AFHTTPRequestOperation *)HTTPRequestOperationWithRequest:(NSURLRequest *)theRequest 114 | success:(void (^)(AFHTTPRequestOperation *, id))success 115 | failure:(void (^)(AFHTTPRequestOperation *, NSError *))failure{ 116 | 117 | NSMutableURLRequest *request = (NSMutableURLRequest *)theRequest; 118 | [request addValue:qiniuUserAgent() forHTTPHeaderField:@"User-Agent"]; 119 | AFHTTPRequestOperation *operation = [super HTTPRequestOperationWithRequest:request success:success failure:failure]; 120 | 121 | return operation; 122 | } 123 | 124 | @end 125 | 126 | 127 | @implementation QiniuPutExtra 128 | 129 | - (NSDictionary *)convertToPostParams{ 130 | NSMutableDictionary *params = [NSMutableDictionary dictionaryWithDictionary:self.params]; 131 | if (self.checkCrc == 1) { 132 | params[@"crc32"] = [NSString stringWithFormat:@"%u", (unsigned int)self.crc32]; 133 | } 134 | return params; 135 | } 136 | 137 | @end 138 | -------------------------------------------------------------------------------- /QiniuSDK/QiniuResumableClient.h: -------------------------------------------------------------------------------- 1 | // 2 | // QiniuResumableClient.h 3 | // QiniuSDK 4 | // 5 | // Created by ltz on 14-2-24. 6 | // Copyright (c) 2014年 Qiniu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AFNetworking/AFNetworking.h" 11 | #import "QiniuBlkputRet.h" 12 | 13 | typedef void (^QNProgressBlock)(float); 14 | typedef void (^QNCompleteBlock)(id object, NSError *error); 15 | 16 | #define QiniuBlockBits 22 17 | #define QiniuBlockMask ((1 << QiniuBlockBits) - 1) 18 | #define QiniuDefaultChunkSize (256 * 1024) 19 | #define QiniuDefaultMaxWorkers 3 20 | #define QiniuDefaultTryTimes 3 21 | 22 | @class QiniuRioPutExtra; 23 | 24 | @interface QiniuResumableClient : AFHTTPRequestOperationManager 25 | 26 | - (void)mkblock:(NSData *)mappedData 27 | offsetBase:(UInt32)offsetBase 28 | blockSize:(UInt32)blockSize 29 | bodyLength:(UInt32)bodyLength 30 | uphost:(NSString *)uphost 31 | progress:(QNProgressBlock)progressBlock 32 | complete:(QNCompleteBlock)complete; 33 | 34 | - (void)chunkPut:(NSData *)mappedData 35 | blockPutRet:(QiniuBlkputRet *)blockPutRet 36 | offsetBase:(UInt32)offsetBase 37 | bodyLength:(UInt32)bodyLength 38 | progress:(QNProgressBlock)progressBlock 39 | complete:(QNCompleteBlock)complete; 40 | 41 | - (void)blockPut:(NSData *)mappedData 42 | blockIndex:(UInt32)blockIndex 43 | blockSize:(UInt32)blockSize 44 | extra:(QiniuRioPutExtra *)extra 45 | uphost:(NSString *)uphost 46 | progress:(QNProgressBlock)progressBlock 47 | complete:(QNCompleteBlock)complete; 48 | 49 | - (void)mkfile:(NSString *)key 50 | fileSize:(UInt32)fileSize 51 | extra:(QiniuRioPutExtra *)extra 52 | uphost:(NSString *)uphost 53 | progress:(QNProgressBlock)progressBlock 54 | complete:(QNCompleteBlock)complete; 55 | 56 | - (QiniuResumableClient *)initWithToken:(NSString *)token 57 | withMaxWorkers:(UInt32)maxWorkers 58 | withChunkSize:(UInt32)chunkSize 59 | withTryTime:(UInt32)tryTime; 60 | 61 | - (void)setHeaders:(NSMutableURLRequest *)request; 62 | 63 | @property BOOL canceled; 64 | - (void)cancelTasks; 65 | 66 | @property UInt32 retryTime; 67 | @property UInt32 chunkSize; 68 | @property (copy, nonatomic) NSString *token; 69 | 70 | @end 71 | 72 | typedef void (^QiniuRioNotify)(int blockIndex, int blockSize, QiniuBlkputRet* ret); 73 | typedef void (^QiniuRioNotifyErr)(int blockIndex, int blockSize, NSError* error); 74 | 75 | 76 | 77 | @interface QiniuRioPutExtra : NSObject 78 | 79 | + (QiniuRioPutExtra *)extraWithParams:(NSDictionary *)params; 80 | - (QiniuRioPutExtra *)init; 81 | - (QiniuRioPutExtra *)initWithBlockCount:(UInt32)blockCount; 82 | 83 | @property (retain, nonatomic)QiniuResumableClient *client; 84 | - (void)cancelTasks; 85 | 86 | @property (copy, nonatomic) NSDictionary* params; 87 | @property (copy, nonatomic) NSString* mimeType; 88 | @property UInt32 chunkSize; 89 | @property UInt32 tryTimes; 90 | @property UInt32 concurrentNum; 91 | @property (retain, nonatomic) NSMutableArray* progresses; 92 | @property (copy) QiniuRioNotify notify; 93 | @property (copy) QiniuRioNotifyErr notifyErr; 94 | 95 | @property UInt32 uploadedBlockNumber; 96 | @property UInt32 blockCount; 97 | - (BOOL)blockUploadedAndCheck; 98 | 99 | @property UInt32 uploadedChunkNumber; 100 | @property UInt32 chunkCount; 101 | - (float)chunkUploadedAndPercent; 102 | 103 | @end -------------------------------------------------------------------------------- /QiniuSDK/QiniuResumableClient.m: -------------------------------------------------------------------------------- 1 | // 2 | // QiniuResumableClient.m 3 | // QiniuSDK 4 | // 5 | // Created by ltz on 14-2-24. 6 | // Copyright (c) 2014年 Qiniu. All rights reserved. 7 | // 8 | 9 | #import "QiniuResumableClient.h" 10 | #import "QiniuConfig.h" 11 | #import "QiniuUtils.h" 12 | 13 | @implementation QiniuResumableClient 14 | 15 | - (QiniuResumableClient *)initWithToken:(NSString *)token 16 | withMaxWorkers:(UInt32)maxWorkers 17 | withChunkSize:(UInt32)chunkSize 18 | withTryTime:(UInt32)tryTime 19 | { 20 | self = [super init]; 21 | self.token = [[NSString alloc] initWithFormat:@"UpToken %@", token]; 22 | self.retryTime = tryTime; 23 | self.chunkSize = chunkSize; // 256k 24 | 25 | self.responseSerializer = [AFJSONResponseSerializer serializer]; 26 | self.operationQueue = [[NSOperationQueue alloc] init]; 27 | [self.operationQueue setMaxConcurrentOperationCount:maxWorkers]; 28 | 29 | return self; 30 | } 31 | 32 | - (void)cancelTasks 33 | { 34 | self.canceled = YES; 35 | } 36 | 37 | - (void)mkblock:(NSData *)mappedData 38 | offsetBase:(UInt32)offset 39 | blockSize:(UInt32)blockSize 40 | bodyLength:(UInt32)bodyLength 41 | uphost:(NSString *)uphost 42 | progress:(QNProgressBlock)progressBlock 43 | complete:(QNCompleteBlock)complete 44 | { 45 | if (self.canceled) { 46 | return; 47 | } 48 | NSString *callUrl = [[NSString alloc] initWithFormat:@"%@/mkblk/%d", uphost, (unsigned int)blockSize]; 49 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:callUrl]]; 50 | 51 | [self setHeaders:request]; 52 | 53 | NSData *postData = [mappedData subdataWithRange:NSMakeRange(offset, bodyLength)]; 54 | [request setHTTPBody:postData]; 55 | 56 | QNCompleteBlock success = ^(AFHTTPRequestOperation *operation, id responseObject) 57 | { 58 | // TODO: check crc32 59 | complete(operation, nil); 60 | }; 61 | QNCompleteBlock failure = ^(AFHTTPRequestOperation *operation, NSError *error) 62 | { 63 | complete(operation, error); 64 | }; 65 | 66 | AFHTTPRequestOperation *operation = [super HTTPRequestOperationWithRequest:request 67 | success:success 68 | failure:failure]; 69 | [self.operationQueue addOperation:operation]; 70 | } 71 | 72 | - (void)chunkPut:(NSData *)mappedData 73 | blockPutRet:(QiniuBlkputRet *)blockPutRet 74 | offsetBase:(UInt32)offsetBase 75 | bodyLength:(UInt32)bodyLength 76 | progress:(QNProgressBlock)progressBlock 77 | complete:(QNCompleteBlock)complete 78 | { 79 | if (self.canceled) { 80 | return; 81 | } 82 | NSString *callUrl = [[NSString alloc] initWithFormat:@"%@/bput/%@/%d", blockPutRet.host, blockPutRet.ctx, (unsigned int)blockPutRet.offset]; 83 | NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:callUrl]]; 84 | 85 | [self setHeaders:request]; 86 | 87 | NSData *postData = [mappedData subdataWithRange:NSMakeRange(offsetBase + blockPutRet.offset, bodyLength)]; 88 | [request setHTTPBody:postData]; 89 | 90 | QNCompleteBlock success = ^(AFHTTPRequestOperation *operation, id responseObject) 91 | { 92 | // TODO: check crc32 93 | complete(operation, nil); 94 | }; 95 | QNCompleteBlock failure = ^(AFHTTPRequestOperation *operation, NSError *error) 96 | { 97 | complete(operation, error); 98 | }; 99 | 100 | AFHTTPRequestOperation *operation = [super HTTPRequestOperationWithRequest:request 101 | success:success 102 | failure:failure]; 103 | [self.operationQueue addOperation:operation]; 104 | } 105 | 106 | - (void)blockPut:(NSData *)mappedData 107 | blockIndex:(UInt32)blockIndex 108 | blockSize:(UInt32)blockSize 109 | extra:(QiniuRioPutExtra *)extra 110 | uphost:(NSString *)uphost 111 | progress:(QNProgressBlock)progressBlock 112 | complete:(QNCompleteBlock)complete 113 | { 114 | // @autoreleasepool { 115 | 116 | 117 | UInt32 offsetBase = blockIndex << QiniuBlockBits; 118 | 119 | __block UInt32 bodyLength = self.chunkSize < blockSize ? self.chunkSize : blockSize; 120 | __block QiniuBlkputRet *blockPutRet; 121 | __block UInt32 retryTime = self.retryTime; 122 | __block BOOL isMkblock = YES; 123 | 124 | QNCompleteBlock __block __weak weakChunkComplete; 125 | QNCompleteBlock chunkComplete; 126 | weakChunkComplete = chunkComplete = ^(AFHTTPRequestOperation *operation, NSError *error) 127 | { 128 | if (error != nil) { 129 | 130 | if (retryTime == 0 || isMkblock || [operation.response statusCode] == 701) { 131 | complete(operation, error); 132 | return; 133 | } else { 134 | retryTime --; 135 | } 136 | } else { 137 | if (progressBlock != nil) { 138 | progressBlock([extra chunkUploadedAndPercent]); 139 | } 140 | retryTime = self.retryTime; 141 | isMkblock = NO; 142 | blockPutRet = [[QiniuBlkputRet alloc] initWithDictionary:operation.responseObject]; 143 | 144 | UInt32 remainLength = blockSize - blockPutRet.offset; 145 | bodyLength = self.chunkSize < remainLength ? self.chunkSize : remainLength; 146 | } 147 | 148 | if (blockPutRet.offset == blockSize) { 149 | complete(operation, nil); 150 | return; 151 | } 152 | 153 | [self chunkPut:mappedData 154 | blockPutRet:blockPutRet 155 | offsetBase:offsetBase 156 | bodyLength:bodyLength 157 | progress:progressBlock 158 | complete:weakChunkComplete]; 159 | }; 160 | 161 | [self mkblock:mappedData 162 | offsetBase:offsetBase 163 | blockSize:blockSize 164 | bodyLength:bodyLength 165 | uphost:uphost 166 | progress:progressBlock 167 | complete:chunkComplete]; 168 | // } 169 | } 170 | 171 | + (NSString *)encode:(NSString *)str 172 | { 173 | return urlSafeBase64String(str); 174 | } 175 | 176 | - (void)mkfile:(NSString *)key 177 | fileSize:(UInt32)fileSize 178 | extra:(QiniuRioPutExtra *)extra 179 | uphost:(NSString *)uphost 180 | progress:(QNProgressBlock)progressBlock 181 | complete:(QNCompleteBlock)complete 182 | { 183 | 184 | NSString *mimeStr = extra.mimeType == nil ? @"" : [[NSString alloc] initWithFormat:@"/mimetype/%@", [QiniuResumableClient encode:extra.mimeType]]; 185 | 186 | NSString *callUrl = [[NSString alloc] initWithFormat:@"%@/mkfile/%u%@", uphost, (unsigned int)fileSize, mimeStr]; 187 | 188 | if (key != nil) { 189 | NSString *keyStr = [[NSString alloc] initWithFormat:@"/key/%@", [QiniuResumableClient encode:key]]; 190 | callUrl = [NSString stringWithFormat:@"%@%@", callUrl, keyStr]; 191 | } 192 | 193 | if (extra.params != nil) { 194 | NSEnumerator *e = [extra.params keyEnumerator]; 195 | for (id key = [e nextObject]; key != nil; key = [e nextObject]) { 196 | callUrl = [NSString stringWithFormat:@"%@/%@/%@", callUrl, key, [QiniuResumableClient encode:[extra.params objectForKey:key]]]; 197 | } 198 | } 199 | 200 | NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:[[NSURL alloc] initWithString:callUrl]]; 201 | [self setHeaders:request]; 202 | 203 | NSMutableData *postData = [NSMutableData data]; 204 | NSString *bodyStr = [extra.progresses componentsJoinedByString:@","]; 205 | [postData appendData:[bodyStr dataUsingEncoding:NSUTF8StringEncoding]]; 206 | [request setHTTPBody:postData]; 207 | 208 | QNCompleteBlock success = ^(AFHTTPRequestOperation *operation, id responseObject) 209 | { 210 | if (progressBlock != nil) { 211 | progressBlock(1); 212 | } 213 | complete(operation, nil); 214 | }; 215 | QNCompleteBlock failure = ^(AFHTTPRequestOperation *operation, NSError *error) 216 | { 217 | complete(operation, error); 218 | }; 219 | 220 | AFHTTPRequestOperation *operation = [self HTTPRequestOperationWithRequest:request 221 | success:success 222 | failure:failure]; 223 | [self.operationQueue addOperation:operation]; 224 | } 225 | 226 | - (void)setHeaders:(NSMutableURLRequest *)request 227 | { 228 | [request setValue:self.token forHTTPHeaderField:@"Authorization"]; 229 | [request setValue:@"application/octet-stream" forHTTPHeaderField:@"Content-Type"]; 230 | [request addValue:qiniuUserAgent() forHTTPHeaderField:@"User-Agent"]; 231 | [request setHTTPMethod:@"POST"]; 232 | } 233 | 234 | @end 235 | 236 | @implementation QiniuRioPutExtra 237 | 238 | + (QiniuRioPutExtra *)extraWithParams:(NSDictionary *)params 239 | { 240 | QiniuRioPutExtra *extra = [[QiniuRioPutExtra alloc] init]; 241 | extra.params = params; 242 | return extra; 243 | } 244 | 245 | - (QiniuRioPutExtra *)init 246 | { 247 | self = [super init]; 248 | return self; 249 | } 250 | 251 | - (void)cancelTasks 252 | { 253 | [self.client cancelTasks]; 254 | } 255 | 256 | - (QiniuRioPutExtra *)initWithBlockCount:(UInt32)count 257 | { 258 | self = [super init]; 259 | self.blockCount = count; 260 | return self; 261 | } 262 | 263 | - (BOOL) blockUploadedAndCheck 264 | { 265 | static NSLock *blockNumlock; 266 | if (blockNumlock == nil) { 267 | blockNumlock = [[NSLock alloc] init]; 268 | } 269 | 270 | BOOL allBlockOk; 271 | 272 | [blockNumlock lock]; 273 | self.uploadedBlockNumber ++; 274 | allBlockOk = self.uploadedBlockNumber == self.blockCount; 275 | [blockNumlock unlock]; 276 | 277 | return allBlockOk; 278 | } 279 | 280 | - (float) chunkUploadedAndPercent 281 | { 282 | static NSLock *chunkNumlock; 283 | if (chunkNumlock == nil) { 284 | chunkNumlock = [[NSLock alloc] init]; 285 | } 286 | 287 | float percent; 288 | [chunkNumlock lock]; 289 | self.uploadedChunkNumber ++; 290 | percent = (float)self.uploadedChunkNumber / self.chunkCount; 291 | [chunkNumlock unlock]; 292 | 293 | if (percent > 0.95) { 294 | percent = 0.95; 295 | } 296 | 297 | return percent; 298 | } 299 | 300 | - (void) encodeWithCoder:(NSCoder *)aCoder { 301 | [aCoder encodeObject:self.params forKey:@"params"]; 302 | [aCoder encodeObject:self.mimeType forKey:@"mimeType"]; 303 | [aCoder encodeInt32:self.chunkSize forKey:@"chunkSize"]; 304 | [aCoder encodeInt32:self.tryTimes forKey:@"tryTimes"]; 305 | [aCoder encodeInt32:self.concurrentNum forKey:@"concurrentNum"]; 306 | [aCoder encodeObject:self.progresses forKey:@"progresses"]; 307 | [aCoder encodeInt32:self.blockCount forKey:@"blockCount"]; 308 | [aCoder encodeInt32:self.chunkCount forKey:@"chunkCount"]; 309 | } 310 | 311 | - (id) initWithCoder:(NSCoder *)aDecoder { 312 | if (self = [super init]) { 313 | self.params = [aDecoder decodeObjectForKey:@"params"]; 314 | self.mimeType = [aDecoder decodeObjectForKey:@"mimeType"]; 315 | self.chunkSize = [aDecoder decodeInt32ForKey:@"chunkSize"]; 316 | self.tryTimes = [aDecoder decodeInt32ForKey:@"tryTimes"]; 317 | self.concurrentNum = [aDecoder decodeInt32ForKey:@"concurrentNum"]; 318 | self.progresses = [aDecoder decodeObjectForKey:@"progresses"]; 319 | self.blockCount = [aDecoder decodeInt32ForKey:@"blockCount"]; 320 | self.chunkCount = [aDecoder decodeInt32ForKey:@"chunkCount"]; 321 | } 322 | return self; 323 | } 324 | 325 | @end 326 | -------------------------------------------------------------------------------- /QiniuSDK/QiniuResumableUploader.h: -------------------------------------------------------------------------------- 1 | // 2 | // QiniuResumableUploader.h 3 | // QiniuSDK 4 | // 5 | // Created by ltz on 14-2-23. 6 | // Copyright (c) 2014年 Qiniu. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AFNetworking/AFNetworking.h" 11 | #import "QiniuResumableClient.h" 12 | #import "QiniuUploadDelegate.h" 13 | 14 | @interface QiniuResumableUploader : NSObject 15 | 16 | @property (assign, nonatomic) id delegate; 17 | @property (copy, nonatomic)NSString *token; 18 | 19 | 20 | - (QiniuResumableUploader *)initWithToken:(NSString *)token; 21 | 22 | - (void) uploadFile:(NSString *)filePath 23 | key:(NSString *)key 24 | extra:(QiniuRioPutExtra *)extra; 25 | 26 | @property (retain, nonatomic)QiniuResumableClient *client; 27 | 28 | @end 29 | 30 | -------------------------------------------------------------------------------- /QiniuSDK/QiniuResumableUploader.m: -------------------------------------------------------------------------------- 1 | // 2 | // QiniuResumableUploader.m 3 | // QiniuSDK 4 | // 5 | // Created by ltz on 14-2-23. 6 | // Copyright (c) 2014年 Qiniu. All rights reserved. 7 | // 8 | 9 | #import "QiniuResumableUploader.h" 10 | #import "QiniuResumableClient.h" 11 | #import "QiniuUtils.h" 12 | #import "QiniuConfig.h" 13 | 14 | @implementation QiniuResumableUploader 15 | 16 | - (QiniuResumableUploader *) initWithToken:(NSString *)token 17 | { 18 | if (self = [super init]) { 19 | self.token = token; 20 | } 21 | return self; 22 | } 23 | 24 | - (void) uploadFile:(NSString *)filePath 25 | key:(NSString *)key 26 | extra:(QiniuRioPutExtra *)extra 27 | { 28 | @autoreleasepool { 29 | NSError *error = nil; 30 | NSDictionary *fileAttr = [[NSFileManager defaultManager] attributesOfItemAtPath:filePath error:&error]; 31 | if (error != nil) { 32 | [self.delegate uploadFailed:filePath error:error]; 33 | return; 34 | } 35 | 36 | NSNumber *fileSizeNumber = [fileAttr objectForKey:NSFileSize]; 37 | UInt32 fileSize = [fileSizeNumber intValue]; 38 | UInt32 blockCount = [QiniuResumableUploader blockCount:fileSize]; 39 | 40 | 41 | if (extra == nil) { 42 | extra = [[QiniuRioPutExtra alloc] initWithBlockCount:blockCount]; 43 | } 44 | if (extra.concurrentNum == 0) { 45 | extra.concurrentNum = QiniuDefaultMaxWorkers; 46 | } 47 | if (extra.chunkSize == 0) { 48 | extra.chunkSize = QiniuDefaultChunkSize; 49 | } 50 | if (extra.tryTimes == 0) { 51 | extra.tryTimes = QiniuDefaultTryTimes; 52 | } 53 | 54 | 55 | UInt32 blockSize = 1 << QiniuBlockBits; 56 | 57 | if (extra.client == nil) { 58 | extra.client = [[QiniuResumableClient alloc] initWithToken:self.token 59 | withMaxWorkers:extra.concurrentNum 60 | withChunkSize:extra.chunkSize 61 | withTryTime:extra.tryTimes]; 62 | } 63 | extra.client.canceled = NO; 64 | extra.uploadedBlockNumber = 0; 65 | extra.uploadedChunkNumber = 0; 66 | 67 | 68 | if (extra.progresses == nil) { 69 | // it's a new extra 70 | extra.chunkCount = (fileSize / extra.chunkSize) + (fileSize % extra.chunkSize?1:0); 71 | 72 | extra.blockCount = blockCount; 73 | extra.progresses = [[NSMutableArray alloc] initWithCapacity:blockCount]; 74 | for (int i=0; i 0) { 125 | retryTime --; 126 | 127 | [extra.client blockPut:mappedData 128 | blockIndex:blockIndex 129 | blockSize:blockSize1 130 | extra:extra 131 | uphost:kQiniuUpHosts[blockRetryIndex] 132 | progress:weakProgressBlock 133 | complete:weakBlockComplete]; 134 | } else { 135 | if (blockRetryIndex < kQiniuUpHostsLast && isRetryHost(operation)) { 136 | blockRetryIndex ++; 137 | retryTime = extra.client.retryTime; 138 | 139 | [extra.client blockPut:mappedData 140 | blockIndex:blockIndex 141 | blockSize:blockSize1 142 | extra:extra 143 | uphost:kQiniuUpHosts[blockRetryIndex] 144 | progress:weakProgressBlock 145 | complete:weakBlockComplete]; 146 | 147 | return; 148 | 149 | } 150 | if (extra.notifyErr != nil) { 151 | error = qiniuErrorWithOperation(operation, error); 152 | extra.notifyErr(blockIndex, blockSize1, error); 153 | } 154 | } 155 | return; 156 | } 157 | 158 | 159 | // operation == nil: block already in progresses 160 | if (operation != nil) { 161 | NSString *ctx = [operation.responseObject valueForKey:@"ctx"]; 162 | [extra.progresses replaceObjectAtIndex:blockIndex withObject:ctx]; 163 | 164 | QiniuBlkputRet *ret = [[QiniuBlkputRet alloc] initWithDictionary:operation.responseObject]; 165 | if (extra.notify != nil) { 166 | extra.notify(blockIndex, blockSize1, ret); 167 | } 168 | } 169 | 170 | BOOL blockUploadedOK = [extra blockUploadedAndCheck]; 171 | if (blockUploadedOK) { 172 | 173 | QNCompleteBlock __block completeBlock; 174 | QNCompleteBlock __block __weak weakCompleteBlock = completeBlock = ^(AFHTTPRequestOperation *operation, NSError *error) { 175 | if (error) { 176 | if (mkfileRetryIndex < kQiniuUpHostsLast && isRetryHost(operation)) { 177 | 178 | mkfileRetryIndex ++; 179 | [extra.client mkfile:key 180 | fileSize:fileSize 181 | extra:extra 182 | uphost:kQiniuUpHosts[mkfileRetryIndex] 183 | progress:weakProgressBlock 184 | complete:weakCompleteBlock]; 185 | 186 | return; 187 | } 188 | error = qiniuErrorWithOperation(operation, error); 189 | [self.delegate uploadFailed:filePath error:error]; 190 | }else{ 191 | NSDictionary *resp = operation.responseObject; 192 | [self.delegate uploadSucceeded:filePath ret:resp]; 193 | } 194 | }; 195 | 196 | [extra.client mkfile:key 197 | fileSize:fileSize 198 | extra:extra 199 | uphost:kQiniuUpHosts[0] 200 | progress:weakProgressBlock 201 | complete:weakCompleteBlock]; 202 | return; 203 | } 204 | }; 205 | 206 | 207 | if (extra.progresses[blockIndex] != [NSNull null]) { 208 | // block already uploaded 209 | int count = blockSize1 / extra.chunkSize + ((blockSize1%extra.chunkSize!=0)?1:0); 210 | NSLog(@"count: %d", count); 211 | extra.uploadedChunkNumber += count; 212 | 213 | weakBlockComplete(nil, nil); 214 | continue; 215 | } 216 | 217 | 218 | [extra.client blockPut:mappedData 219 | blockIndex:blockIndex 220 | blockSize:blockSize1 221 | extra:extra 222 | uphost:kQiniuUpHosts[0] 223 | progress:weakProgressBlock 224 | complete:weakBlockComplete]; 225 | } 226 | } 227 | } 228 | 229 | + (UInt32) blockCount:(unsigned long long)fileSize 230 | { 231 | return (UInt32)((fileSize + QiniuBlockMask) >> QiniuBlockBits); 232 | } 233 | 234 | @end 235 | -------------------------------------------------------------------------------- /QiniuSDK/QiniuSDK-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #ifdef __OBJC__ 8 | #import 9 | #endif 10 | -------------------------------------------------------------------------------- /QiniuSDK/QiniuSimpleUploader.h: -------------------------------------------------------------------------------- 1 | // 2 | // QiniuSimpleUploader.h 3 | // QiniuSimpleUploader 4 | // 5 | // Created by Qiniu Developers 2013 6 | // 7 | 8 | #import 9 | #import "QiniuHttpClient.h" 10 | #import "QiniuUploadDelegate.h" 11 | 12 | @class QiniuPutExtra; 13 | 14 | // Upload local file to Qiniu Cloud Service with one single request. 15 | @interface QiniuSimpleUploader : NSObject 16 | 17 | // Delegates to receive events for upload progress info. 18 | @property (assign, nonatomic) id delegate; 19 | 20 | // Token contains expiration field. 21 | // It is possible that after a period you'll receive a 401 error with this token. 22 | // If that happens you'll need to retrieve a new token from server and set here. 23 | @property (copy, nonatomic) NSString *token; 24 | 25 | // Returns a QiniuSimpleUploader instance. 26 | + (id) uploaderWithToken:(NSString *)token; 27 | 28 | - (id)initWithToken:(NSString *)token; 29 | 30 | // Upload local file to qiniu cloud storage, the extra is optional. 31 | - (void) uploadFile:(NSString *)filePath 32 | key:(NSString *)key 33 | extra:(QiniuPutExtra *)extra; 34 | 35 | - (void) uploadFileData:(NSData *)fileData 36 | key:(NSString *)key 37 | extra:(QiniuPutExtra *)extra; 38 | 39 | @end 40 | 41 | -------------------------------------------------------------------------------- /QiniuSDK/QiniuSimpleUploader.m: -------------------------------------------------------------------------------- 1 | // 2 | // QiniuSimpleUploader.m 3 | // QiniuSimpleUploader 4 | // 5 | // Created by Qiniu Developers 2013 6 | // 7 | 8 | #import "QiniuConfig.h" 9 | #import "QiniuSimpleUploader.h" 10 | #import "QiniuUtils.h" 11 | #import "QiniuHttpClient.h" 12 | 13 | @interface QiniuSimpleUploader () 14 | //@property(nonatomic,copy)NSString *filePath; 15 | //@property(nonatomic,assign)uint64_t *fileSize; 16 | //@property(nonatomic,assign)uint64_t *sentBytes; 17 | @end 18 | 19 | // ------------------------------------------------------------------------------------------ 20 | 21 | @implementation QiniuSimpleUploader 22 | 23 | + (id) uploaderWithToken:(NSString *)token { 24 | return [[self alloc] initWithToken:token]; 25 | } 26 | 27 | // Must always override super's designated initializer. 28 | - (id)init { 29 | return [self initWithToken:nil]; 30 | } 31 | 32 | - (id)initWithToken:(NSString *)token { 33 | if (self = [super init]) { 34 | self.token = token; 35 | } 36 | return self; 37 | } 38 | 39 | - (void) uploadFileData:(NSData *)fileData 40 | key:(NSString *)key 41 | extra:(QiniuPutExtra *)extra 42 | { 43 | int __block retryIndex = 0; 44 | QNProgress __block progressBlock; 45 | QNProgress __block __weak weakProgressBlock = progressBlock = ^(float percent) { 46 | if ([self.delegate respondsToSelector:@selector(uploadProgressUpdated:percent:)]) { 47 | [self.delegate uploadProgressUpdated:key percent:percent]; 48 | } 49 | }; 50 | 51 | QNComplete __block completeBlock; 52 | QNComplete __block __weak weakCompleteBlock = completeBlock = ^(AFHTTPRequestOperation *operation, NSError *error) { 53 | if (error) { 54 | if (retryIndex < kQiniuUpHostsLast && isRetryHost(operation)) { 55 | retryIndex ++; 56 | [QiniuClient uploadFileData:fileData 57 | key:key 58 | token:self.token 59 | extra:extra 60 | uphost:kQiniuUpHosts[retryIndex] 61 | progress:weakProgressBlock 62 | complete:weakCompleteBlock]; 63 | return; 64 | } 65 | error = qiniuErrorWithOperation(operation, error); 66 | [self.delegate uploadFailed:key error:error]; 67 | }else{ 68 | NSDictionary *resp = operation.responseObject; 69 | [self.delegate uploadSucceeded:key ret:resp]; 70 | } 71 | }; 72 | 73 | [QiniuClient uploadFileData:fileData 74 | key:key 75 | token:self.token 76 | extra:extra 77 | uphost:kQiniuUpHosts[0] 78 | progress:weakProgressBlock 79 | complete:weakCompleteBlock]; 80 | 81 | } 82 | 83 | - (void) uploadFile:(NSString *)filePath 84 | key:(NSString *)key 85 | extra:(QiniuPutExtra *)extra 86 | { 87 | int __block retryIndex = 0; 88 | QNProgress __block progressBlock; 89 | QNProgress __block __weak weakProgressBlock = progressBlock = ^(float percent) { 90 | if ([self.delegate respondsToSelector:@selector(uploadProgressUpdated:percent:)]) { 91 | [self.delegate uploadProgressUpdated:filePath percent:percent]; 92 | } 93 | }; 94 | 95 | QNComplete __block completeBlock; 96 | QNComplete __block __weak weakCompleteBlock = completeBlock = ^(AFHTTPRequestOperation *operation, NSError *error) { 97 | if (error) { 98 | if (retryIndex < kQiniuUpHostsLast && isRetryHost(operation)) { 99 | retryIndex ++; 100 | [QiniuClient uploadFile:filePath 101 | key:key 102 | token:self.token 103 | extra:extra 104 | uphost:kQiniuUpHosts[retryIndex] 105 | progress:weakProgressBlock 106 | complete:weakCompleteBlock]; 107 | return; 108 | } 109 | error = qiniuErrorWithOperation(operation, error); 110 | [self.delegate uploadFailed:filePath error:error]; 111 | }else{ 112 | NSDictionary *resp = operation.responseObject; 113 | [self.delegate uploadSucceeded:filePath ret:resp]; 114 | } 115 | }; 116 | 117 | [QiniuClient uploadFile:filePath 118 | key:key 119 | token:self.token 120 | extra:extra 121 | uphost:kQiniuUpHosts[0] 122 | progress:weakProgressBlock 123 | complete:weakCompleteBlock]; 124 | 125 | } 126 | 127 | @end 128 | 129 | -------------------------------------------------------------------------------- /QiniuSDK/QiniuUploadDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // QiniuUploadDelegate.h 3 | // QiniuSDK 4 | // 5 | // Created by ltz on 14-2-26. 6 | // Copyright (c) 2014年 Qiniu. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | // Upload delegates. Should be implemented by callers to receive callback info. 12 | 13 | @protocol QiniuUploadDelegate 14 | 15 | @optional 16 | 17 | // Progress updated. 1.0 indicates 100%. 18 | - (void)uploadProgressUpdated:(NSString *)filePath percent:(float)percent; 19 | 20 | // Following two methods are required, because without them caller won't know when the 21 | // procedure is completed. 22 | 23 | @required 24 | // Upload completed successfully. 25 | - (void)uploadSucceeded:(NSString *)filePath ret:(NSDictionary *)ret; 26 | 27 | // Upload failed. 28 | - (void)uploadFailed:(NSString *)filePath error:(NSError *)error; 29 | 30 | @end 31 | -------------------------------------------------------------------------------- /QiniuSDK/QiniuUtils.h: -------------------------------------------------------------------------------- 1 | // 2 | // QiniuUtils.h 3 | // QiniuSDK 4 | // 5 | // Created by Qiniu Developers 2013 6 | // 7 | 8 | #import 9 | #import "AFHTTPRequestOperation.h" 10 | 11 | typedef void (^QNProgress)(float percent); 12 | typedef void (^QNComplete)(AFHTTPRequestOperation *operation, NSError *error); 13 | 14 | NSString *urlSafeBase64String(NSString *sourceString); 15 | 16 | NSError *qiniuError(int errorCode, NSString *errorDescription); 17 | 18 | NSError *qiniuErrorWithOperation(AFHTTPRequestOperation *operation, NSError *error); 19 | 20 | NSString *qiniuUserAgent(); 21 | 22 | BOOL isRetryHost(AFHTTPRequestOperation *operation); 23 | -------------------------------------------------------------------------------- /QiniuSDK/QiniuUtils.m: -------------------------------------------------------------------------------- 1 | // 2 | // QiniuUtils.m 3 | // QiniuSDK 4 | // 5 | // Created by Qiniu Developers 2013 6 | // 7 | 8 | #import 9 | 10 | #import "QiniuConfig.h" 11 | #import "QiniuUtils.h" 12 | 13 | #define kQiniuErrorKey @"error" 14 | #define kQiniuErrorDomain @"QiniuErrorDomain" 15 | 16 | NSString *urlSafeBase64String(NSString *sourceString) { 17 | NSData *data = [NSData dataWithBytes:[sourceString UTF8String] length:[sourceString lengthOfBytesUsingEncoding:NSUTF8StringEncoding]]; 18 | NSUInteger length = [data length]; 19 | NSMutableData *mutableData = [NSMutableData dataWithLength:((length + 2) / 3) * 4]; 20 | 21 | uint8_t *input = (uint8_t *)[data bytes]; 22 | uint8_t *output = (uint8_t *)[mutableData mutableBytes]; 23 | 24 | for (NSUInteger i = 0; i < length; i += 3) { 25 | NSUInteger value = 0; 26 | for (NSUInteger j = i; j < (i + 3); j++) { 27 | value <<= 8; 28 | if (j < length) { 29 | value |= (0xFF & input[j]); 30 | } 31 | } 32 | 33 | static uint8_t const kAFBase64EncodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; 34 | 35 | NSUInteger idx = (i / 3) * 4; 36 | output[idx + 0] = kAFBase64EncodingTable[(value >> 18) & 0x3F]; 37 | output[idx + 1] = kAFBase64EncodingTable[(value >> 12) & 0x3F]; 38 | output[idx + 2] = (i + 1) < length ? kAFBase64EncodingTable[(value >> 6) & 0x3F] : '='; 39 | output[idx + 3] = (i + 2) < length ? kAFBase64EncodingTable[(value >> 0) & 0x3F] : '='; 40 | } 41 | 42 | return [[NSString alloc] initWithData:mutableData encoding:NSASCIIStringEncoding]; 43 | } 44 | 45 | NSError *qiniuError(int errorCode, NSString *errorDescription) { 46 | return [NSError errorWithDomain:kQiniuErrorDomain code:errorCode userInfo:[NSDictionary dictionaryWithObject:errorDescription forKey:kQiniuErrorKey]]; 47 | } 48 | 49 | NSError *qiniuErrorWithOperation(AFHTTPRequestOperation *operation, NSError *error) { 50 | 51 | if (operation == nil || operation.responseObject == nil) { 52 | return error; 53 | } 54 | 55 | NSMutableDictionary *userInfo = nil; 56 | NSInteger errorCode = -1; 57 | 58 | if ([operation.responseObject isKindOfClass:NSDictionary.class]) { 59 | userInfo = [NSMutableDictionary dictionaryWithDictionary:operation.responseObject]; 60 | } 61 | errorCode = [operation.response statusCode]; 62 | 63 | if (!userInfo) { 64 | userInfo = [NSMutableDictionary init]; 65 | } 66 | 67 | NSString *reqid = [[operation.response allHeaderFields] objectForKey:@"X-Reqid"]; 68 | [userInfo setObject:reqid forKey:@"reqid"]; 69 | 70 | return [NSError errorWithDomain:kQiniuErrorDomain code:errorCode userInfo:userInfo]; 71 | } 72 | 73 | static NSString* clientId(){ 74 | long long now_timestamp = [[NSDate date] timeIntervalSince1970]*1000; 75 | int r = arc4random()%1000; 76 | return [NSString stringWithFormat:@"%lld%u", now_timestamp, r]; 77 | } 78 | 79 | static NSString* _clientId = nil; 80 | 81 | NSString *qiniuUserAgent() { 82 | if (_clientId == nil){ 83 | _clientId = clientId(); 84 | } 85 | return [NSString stringWithFormat:@"Qiniu-iOS/%@ (%@; iOS %@; %@)", kQiniuVersion, [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], _clientId]; 86 | } 87 | 88 | BOOL isRetryHost(AFHTTPRequestOperation *operation) { 89 | 90 | NSInteger errorCode = [operation.response statusCode]; 91 | 92 | if (errorCode / 100 == 4 || errorCode / 100 == 6 || errorCode / 100 == 7) { 93 | return false; 94 | } 95 | if (errorCode == 579 || errorCode == 599) { 96 | return false; 97 | } 98 | return true; 99 | } 100 | -------------------------------------------------------------------------------- /QiniuSDKTests/QiniuSDKTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | Qiniu.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /QiniuSDKTests/QiniuSDKTests.h: -------------------------------------------------------------------------------- 1 | // 2 | // QiniuSDKTests.h 3 | // QiniuSDKTests 4 | // 5 | // Created by Qiniu Developers 2013 6 | // 7 | 8 | #import 9 | #import "QiniuSimpleUploader.h" 10 | #import "QiniuResumableUploader.h" 11 | 12 | @interface QiniuSDKTests : XCTestCase 13 | { 14 | BOOL _succeed; 15 | BOOL _done; 16 | BOOL _progressReceived; 17 | NSError *_error; 18 | NSDictionary *_retDictionary; 19 | 20 | NSString *_filePath; 21 | NSString *_fileMedium; 22 | NSString *_fileLarge; 23 | NSString *_token; 24 | } 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /QiniuSDKTests/QiniuSDKTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // QiniuSDKTests.m 3 | // QiniuSDKTests 4 | // 5 | // Created by Qiniu Developers 2013 6 | // 7 | 8 | #import "QiniuSDKTests.h" 9 | #import "QiniuConfig.h" 10 | #import 11 | 12 | #define kWaitTime 400 // seconds 13 | 14 | @implementation QiniuSDKTests 15 | 16 | - (void)setUp 17 | { 18 | [super setUp]; 19 | 20 | _filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"test1.png"]; 21 | _fileMedium = [NSTemporaryDirectory() stringByAppendingPathComponent:@"medium.mp4"]; 22 | _fileLarge = [NSTemporaryDirectory() stringByAppendingPathComponent:@"large.mp4"]; 23 | NSLog(@"Test file: %@", _filePath); 24 | 25 | // Download a file and save to local path. 26 | NSFileManager *fileManager = [NSFileManager defaultManager]; 27 | if (![fileManager fileExistsAtPath:_filePath]) 28 | { 29 | NSURL *url = [NSURL URLWithString:@"http://qiniuphotos.qiniudn.com/gogopher.jpg"]; 30 | NSData *data = [NSData dataWithContentsOfURL:url]; 31 | [data writeToFile:_filePath atomically:TRUE]; 32 | } 33 | 34 | if (![fileManager fileExistsAtPath:_fileMedium]) 35 | { 36 | NSURL *url = [NSURL URLWithString:@"http://shars.qiniudn.com/outcrf.mp4"]; 37 | NSData *data = [NSData dataWithContentsOfURL:url]; 38 | [data writeToFile:_fileMedium atomically:TRUE]; 39 | } 40 | 41 | // Prepare the uptoken 42 | // token with a year, 14.2.23 43 | _token = @"6UOyH0xzsnOF-uKmsHgpi7AhGWdfvI8glyYV3uPg:m-8jeXMWC-4kstLEHEMCfZAZnWc=:eyJkZWFkbGluZSI6MTQyNDY4ODYxOCwic2NvcGUiOiJ0ZXN0MzY5In0="; 44 | 45 | _done = false; 46 | _progressReceived = false; 47 | } 48 | 49 | - (void)tearDown 50 | { 51 | // NSFileManager *fileManager = [NSFileManager defaultManager]; 52 | // [fileManager removeItemAtPath:_filePath error:Nil]; 53 | 54 | // Tear-down code here. 55 | [super tearDown]; 56 | } 57 | 58 | 59 | // Upload progress 60 | - (void)uploadProgressUpdated:(NSString *)theFilePath percent:(float)percent 61 | { 62 | _progressReceived = YES; 63 | NSLog(@"Progress Updated: %@ - %f", theFilePath, percent); 64 | } 65 | // */ 66 | 67 | // Upload completed successfully 68 | - (void)uploadSucceeded:(NSString *)theFilePath ret:(NSDictionary *)ret 69 | { 70 | _done = YES; 71 | _succeed = YES; 72 | _retDictionary = ret; 73 | NSLog(@"Upload Succeeded: %@ - Ret: %@", theFilePath, ret); 74 | } 75 | 76 | // Upload failed 77 | - (void)uploadFailed:(NSString *)theFilePath error:(NSError *)error 78 | { 79 | _done = YES; 80 | _error = error; 81 | NSLog(@"Upload Failed: %@ - Reason: %@", theFilePath, error); 82 | NSString *reqid = [error.userInfo valueForKey:@"reqid"]; 83 | XCTAssertFalse(reqid == nil, @"no reqid"); 84 | } 85 | 86 | - (NSString *) timeString { 87 | NSDateFormatter *formatter = [[NSDateFormatter alloc] init]; 88 | [formatter setDateFormat: @"yyyy-MM-dd-HH-mm-ss-zzz"]; 89 | return [formatter stringFromDate:[NSDate date]]; 90 | } 91 | 92 | - (void) waitFinish { 93 | int waitLoop = kWaitTime; 94 | while (!_done && waitLoop > 0) // Wait for 10 seconds. 95 | { 96 | // NSLog(@"Waiting for the result..."); 97 | [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]; 98 | waitLoop--; 99 | } 100 | if (waitLoop <= 0) { 101 | XCTFail(@"Failed to receive expected delegate messages."); 102 | } 103 | } 104 | 105 | - (void) testUploadData 106 | { 107 | QiniuSimpleUploader *uploader = [QiniuSimpleUploader uploaderWithToken:_token]; 108 | uploader.delegate = self; 109 | NSData *data = [NSData dataWithContentsOfFile:_filePath]; 110 | [uploader uploadFileData:data key:[NSString stringWithFormat:@"test-%@.png", [self timeString]] extra:nil]; 111 | [self waitFinish]; 112 | XCTAssertEqual(_succeed, YES, "UploadData failed, error: %@", _error); 113 | } 114 | 115 | - (void) testUploadDataWithoutKey 116 | { 117 | QiniuSimpleUploader *uploader = [QiniuSimpleUploader uploaderWithToken:_token]; 118 | uploader.delegate = self; 119 | NSData *data = [NSData dataWithContentsOfFile:_filePath]; 120 | [uploader uploadFileData:data key:nil extra:nil]; 121 | [self waitFinish]; 122 | XCTAssertEqual(_succeed, YES, "UploadData failed, error: %@", _error); 123 | } 124 | 125 | - (void) testSimpleUpload 126 | { 127 | QiniuSimpleUploader *uploader = [QiniuSimpleUploader uploaderWithToken:_token]; 128 | uploader.delegate = self; 129 | [uploader uploadFile:_filePath key:[NSString stringWithFormat:@"test-%@.png", [self timeString]] extra:nil]; 130 | [self waitFinish]; 131 | XCTAssertEqual(_succeed, YES, "SimpleUpload failed, error: %@", _error); 132 | } 133 | 134 | - (void) testSimpleUploadRetry 135 | { 136 | NSString *upTmp = kQiniuUpHosts[0]; 137 | kQiniuUpHosts[0] = @"http://127.0.0.1"; 138 | 139 | QiniuSimpleUploader *uploader = [QiniuSimpleUploader uploaderWithToken:_token]; 140 | uploader.delegate = self; 141 | [uploader uploadFile:_filePath key:[NSString stringWithFormat:@"test-%@.png", [self timeString]] extra:nil]; 142 | [self waitFinish]; 143 | XCTAssertEqual(_succeed, YES, "SimpleUpload failed, error: %@", _error); 144 | 145 | kQiniuUpHosts[0] = upTmp; 146 | } 147 | 148 | 149 | - (void) testSimpleUploadFailed 150 | { 151 | QiniuSimpleUploader *uploader = [QiniuSimpleUploader uploaderWithToken:@""]; 152 | uploader.delegate = self; 153 | [uploader uploadFile:_filePath key:[NSString stringWithFormat:@"test-%@.png", [self timeString]] extra:nil]; 154 | [self waitFinish]; 155 | XCTAssertEqual(NO, NO, "SimpleUpload should failed, error: %@", _error); 156 | } 157 | 158 | 159 | - (void) testSimpleUploadWithUndefinedKey 160 | { 161 | QiniuSimpleUploader *uploader = [QiniuSimpleUploader uploaderWithToken:_token]; 162 | uploader.delegate = self; 163 | [uploader uploadFile:_filePath key:kQiniuUndefinedKey extra:nil]; 164 | [self waitFinish]; 165 | } 166 | 167 | 168 | - (void) testSimpleUploadWithReturnBodyAndUserParams 169 | { 170 | QiniuSimpleUploader *uploader = [QiniuSimpleUploader uploaderWithToken:_token]; 171 | uploader.delegate = self; 172 | 173 | // extra argument 174 | QiniuPutExtra *extra = [[QiniuPutExtra alloc] init]; 175 | extra.params = @{@"x:foo": @"fooName"}; 176 | 177 | // upload 178 | [uploader uploadFile:_filePath key:[NSString stringWithFormat:@"test-%@.png", [self timeString]] extra:extra]; 179 | [self waitFinish]; 180 | } 181 | 182 | - (void) testSimpleUploadWithWrongCrc32 183 | { 184 | QiniuSimpleUploader *uploader = [QiniuSimpleUploader uploaderWithToken:_token]; 185 | uploader.delegate = self; 186 | 187 | // wrong crc32 value 188 | QiniuPutExtra *extra = [[QiniuPutExtra alloc] init] ; 189 | extra.crc32 = 123456; 190 | extra.checkCrc = 1; 191 | 192 | // upload 193 | [uploader uploadFile:_filePath key:[NSString stringWithFormat:@"test-%@.png", [self timeString]] extra:extra]; 194 | [self waitFinish]; 195 | } 196 | 197 | - (void)testResumableUploadSmall 198 | { 199 | QiniuResumableUploader *uploader = [[QiniuResumableUploader alloc] initWithToken:_token]; 200 | uploader.delegate = self; 201 | 202 | NSLog(@"resumable upload"); 203 | [uploader uploadFile:_filePath key:[NSString stringWithFormat:@"test-%@.png", [self timeString]] extra:nil]; 204 | [self waitFinish]; 205 | XCTAssertEqual(_succeed, YES, "ResumableUpload failed, error: %@", _error); 206 | } 207 | 208 | - (void)testResumableUploadSmallRetry 209 | { 210 | NSString *upTmp = kQiniuUpHosts[0]; 211 | kQiniuUpHosts[0] = @"http://127.0.0.1"; 212 | 213 | QiniuResumableUploader *uploader = [[QiniuResumableUploader alloc] initWithToken:_token]; 214 | uploader.delegate = self; 215 | 216 | NSLog(@"resumable upload"); 217 | [uploader uploadFile:_filePath key:[NSString stringWithFormat:@"test-%@.png", [self timeString]] extra:nil]; 218 | [self waitFinish]; 219 | XCTAssertEqual(_succeed, YES, "ResumableUpload failed, error: %@", _error); 220 | 221 | kQiniuUpHosts[0] = upTmp; 222 | 223 | } 224 | 225 | 226 | - (void)testResumableUploadWithoutKey 227 | { 228 | QiniuResumableUploader *uploader = [[QiniuResumableUploader alloc] initWithToken:_token]; 229 | uploader.delegate = self; 230 | 231 | NSLog(@"resumable upload"); 232 | [uploader uploadFile:_filePath key:nil extra:nil]; 233 | [self waitFinish]; 234 | XCTAssertEqual(_succeed, YES, "ResumableUpload failed, error: %@", _error); 235 | } 236 | 237 | 238 | - (void)testResumableUploadWithParam 239 | { 240 | QiniuResumableUploader *uploader = [[QiniuResumableUploader alloc] initWithToken:_token]; 241 | uploader.delegate = self; 242 | 243 | NSDictionary *params = [NSDictionary dictionaryWithObject:@"iamaiosdeveloper" forKey:@"x:cus"]; 244 | QiniuRioPutExtra *extra = [QiniuRioPutExtra extraWithParams:params]; 245 | extra.notify = ^(int blockIndex, int blockSize, QiniuBlkputRet* ret) { 246 | NSLog(@"notify for data persistence, blockIndex:%d, blockSize:%d, offset:%d ctx:%@", 247 | blockIndex, blockSize, (unsigned int)ret.offset, ret.ctx); 248 | }; 249 | extra.notifyErr = ^(int blockIndex, int blockSize, NSError* error) { 250 | NSLog(@"notify for block upload failed, blockIndex:%d, blockSize:%d, error:%@", 251 | blockIndex, blockSize, error); 252 | }; 253 | extra.concurrentNum = 1; 254 | 255 | [uploader uploadFile:_filePath key:[NSString stringWithFormat:@"test-params-%@.png", [self timeString]] extra:extra]; 256 | 257 | [self waitFinish]; 258 | XCTAssertEqual(_succeed, YES, "ResumableUpload failed, error: %@", _error); 259 | XCTAssertEqualObjects(@"iamaiosdeveloper", [_retDictionary objectForKey:@"x:cus"], "x:cus not equal"); 260 | } 261 | 262 | - (void)testResumableUploadMedium 263 | { 264 | QiniuResumableUploader *uploader = [[QiniuResumableUploader alloc] initWithToken:_token]; 265 | uploader.delegate = self; 266 | 267 | [uploader uploadFile:_fileMedium key:[NSString stringWithFormat:@"test-medium-%@.mp4", [self timeString]] extra:nil]; 268 | [self waitFinish]; 269 | XCTAssertEqual(_succeed, YES, "ResumableUpload failed, error: %@", _error); 270 | } 271 | 272 | - (void)testEncodeExtra 273 | { 274 | QiniuResumableUploader *uploader = [[QiniuResumableUploader alloc] initWithToken:_token]; 275 | uploader.delegate = self; 276 | QiniuRioPutExtra *extra = [[QiniuRioPutExtra alloc] init]; 277 | extra.notify = ^(int blockIndex, int blockSize, QiniuBlkputRet* ret) { 278 | NSLog(@"[testEncodeExtra]notify for data persistence, blockIndex:%d, blockSize:%d, offset:%d ctx:%@", 279 | blockIndex, blockSize, (unsigned int)ret.offset, ret.ctx); 280 | }; 281 | 282 | NSString *key = [NSString stringWithFormat:@"test-encode-extra-%@.mp4", [self timeString]]; 283 | [uploader uploadFile:_fileMedium key:key extra:extra]; 284 | 285 | NSData *serialized; 286 | int loop = 40; 287 | while (loop > 0) { 288 | [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:1.0]]; 289 | if (extra.uploadedBlockNumber > 0) { 290 | [extra cancelTasks]; 291 | serialized = [NSKeyedArchiver archivedDataWithRootObject:extra]; 292 | NSLog(@"extra.uploadedBlockNumber: %d", (unsigned int)extra.uploadedBlockNumber); 293 | break; 294 | } 295 | loop--; 296 | } 297 | if (loop == 0) { 298 | XCTFail(@"upload block time out"); 299 | } 300 | 301 | QiniuRioPutExtra *newExtra = [NSKeyedUnarchiver unarchiveObjectWithData:serialized]; 302 | newExtra.notify = ^(int blockIndex, int blockSize, QiniuBlkputRet* ret) { 303 | NSLog(@"[testEncodeExtra,new]notify for data persistence, blockIndex:%d, blockSize:%d, offset:%d ctx:%@", 304 | blockIndex, blockSize, (unsigned int)ret.offset, ret.ctx); 305 | XCTAssertTrue([extra.progresses[blockIndex] isKindOfClass:[NSNull class]], @"index of progresses should be nil, index: %d", blockIndex); 306 | }; 307 | 308 | [uploader uploadFile:_fileMedium key:key extra:newExtra]; 309 | [self waitFinish]; 310 | XCTAssertEqual(_succeed, YES, "ResumableUpload reuse extra failed, error: %@", _error); 311 | } 312 | 313 | //- (void)testResumableUploadLarge 314 | //{ 315 | // @autoreleasepool { 316 | // 317 | // 318 | // QiniuResumableUploader *uploader = [[QiniuResumableUploader alloc] initWithToken:_token]; 319 | // uploader.delegate = self; 320 | // 321 | // [uploader uploadFile:_fileLarge key:[NSString stringWithFormat:@"test-large-%@", [self timeString]] extra:nil]; 322 | // } 323 | // 324 | // [self waitFinish]; 325 | // 326 | // XCTAssertEqual(_succeed, YES, "ResumableUpload failed, error: %@", _error); 327 | //} 328 | 329 | 330 | /* 331 | - (void) testSimpleUploadWithRightCrc32 332 | { 333 | QiniuSimpleUploader *uploader = [QiniuSimpleUploader uploaderWithToken:_token]; 334 | uploader.delegate = self; 335 | 336 | // calc right crc32 value 337 | NSData *buffer = [NSData dataWithContentsOfFile:_filePath]; 338 | uLong crc = crc32(0L, Z_NULL, 0); 339 | crc = crc32(crc, [buffer bytes], [buffer length]); 340 | 341 | // extra argument with right crc32 342 | QiniuPutExtra *extra = [[QiniuPutExtra alloc] init]; 343 | extra.crc32 = crc; 344 | extra.checkCrc = 1; 345 | 346 | // upload 347 | [uploader uploadFile:_filePath key:[NSString stringWithFormat:@"test-%@.png", [self timeString]] extra:extra]; 348 | [self waitFinish]; 349 | } 350 | */ 351 | 352 | @end 353 | -------------------------------------------------------------------------------- /QiniuSDKTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Qiniu Resource Storage SDK for iOS 2 | 3 | [![Build Status](https://api.travis-ci.org/qiniu/ios-sdk.png?branch=master)](https://travis-ci.org/qiniu/ios-sdk) 4 | 5 | [![Qiniu Logo](http://qiniu-brand.qiniudn.com/5/logo-white-195x105.png)](http://www.qiniu.com/) 6 | 7 | ## 新版SDK 8 | 6.X版本基本不再更新, 建议使用新版本SDK,https://github.com/qiniu/objc-sdk 9 | 10 | ## 下载 11 | 12 | ### 从 release 版本下载 13 | 14 | 下载地址:https://github.com/qiniu/ios-sdk/releases 15 | 16 | 这是我们建议的方式,release 版本有版本号,有 [CHANGELOG](https://github.com/qiniu/ios-sdk/blob/develop/CHANGELOG.md),使用规格也会比较稳定。 17 | 18 | ### 从 git 库下载 19 | 20 | 你可以直接用 git clone 下载源代码来使用。但是请注意非 master 分支的代码在规格上可能承受变更,应谨慎使用。 21 | 22 | 23 | ## 使用 24 | 25 | 参考文档:[七牛云存储 iOS SDK 使用指南](http://developer.qiniu.com/docs/v6/sdk/ios-sdk.html) 26 | 27 | 28 | ## 贡献代码 29 | 30 | 1. Fork 31 | 2. 创建您的特性分支 (`git checkout -b my-new-feature`) 32 | 3. 提交您的改动 (`git commit -am 'Added some feature'`) 33 | 4. 将您的修改记录提交到远程 `git` 仓库 (`git push origin my-new-feature`) 34 | 5. 然后到 github 网站的该 `git` 远程仓库的 `my-new-feature` 分支下发起 Pull Request 35 | 36 | 37 | ## 许可证 38 | 39 | Copyright (c) 2012-2014 qiniu.com 40 | 41 | 基于 MIT 协议发布: 42 | 43 | * [www.opensource.org/licenses/MIT](http://www.opensource.org/licenses/MIT) 44 | --------------------------------------------------------------------------------