mirror of
https://github.com/samuelclay/NewsBlur.git
synced 2025-09-18 21:50:56 +00:00
Starting to move from ASI to AFNetworking. This is going to take a while.
This commit is contained in:
parent
6ce80372e9
commit
391140a8be
43 changed files with 1025 additions and 10187 deletions
|
@ -1,35 +0,0 @@
|
|||
//
|
||||
// ASIAuthenticationDialog.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 21/08/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
@class ASIHTTPRequest;
|
||||
|
||||
typedef enum _ASIAuthenticationType {
|
||||
ASIStandardAuthenticationType = 0,
|
||||
ASIProxyAuthenticationType = 1
|
||||
} ASIAuthenticationType;
|
||||
|
||||
@interface ASIAutorotatingViewController : UIViewController
|
||||
@end
|
||||
|
||||
@interface ASIAuthenticationDialog : ASIAutorotatingViewController <UIActionSheetDelegate, UITableViewDelegate, UITableViewDataSource> {
|
||||
ASIHTTPRequest *request;
|
||||
ASIAuthenticationType type;
|
||||
UITableView *tableView;
|
||||
UIViewController *presentingController;
|
||||
BOOL didEnableRotationNotifications;
|
||||
}
|
||||
+ (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)request;
|
||||
+ (void)dismiss;
|
||||
|
||||
@property (atomic, retain) ASIHTTPRequest *request;
|
||||
@property (atomic, assign) ASIAuthenticationType type;
|
||||
@property (atomic, assign) BOOL didEnableRotationNotifications;
|
||||
@property (retain, nonatomic) UIViewController *presentingController;
|
||||
@end
|
|
@ -1,521 +0,0 @@
|
|||
//
|
||||
// ASIAuthenticationDialog.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 21/08/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIAuthenticationDialog.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
#import <QuartzCore/QuartzCore.h>
|
||||
|
||||
static ASIAuthenticationDialog *sharedDialog = nil;
|
||||
BOOL isDismissing = NO;
|
||||
static NSMutableArray *requestsNeedingAuthentication = nil;
|
||||
|
||||
static const NSUInteger kUsernameRow = 0;
|
||||
static const NSUInteger kUsernameSection = 0;
|
||||
static const NSUInteger kPasswordRow = 1;
|
||||
static const NSUInteger kPasswordSection = 0;
|
||||
static const NSUInteger kDomainRow = 0;
|
||||
static const NSUInteger kDomainSection = 1;
|
||||
|
||||
|
||||
@implementation ASIAutorotatingViewController
|
||||
|
||||
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
|
||||
{
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
|
||||
@interface ASIAuthenticationDialog ()
|
||||
- (void)showTitle;
|
||||
- (void)show;
|
||||
- (NSArray *)requestsRequiringTheseCredentials;
|
||||
- (void)presentNextDialog;
|
||||
- (void)keyboardWillShow:(NSNotification *)notification;
|
||||
- (void)orientationChanged:(NSNotification *)notification;
|
||||
- (void)cancelAuthenticationFromDialog:(id)sender;
|
||||
- (void)loginWithCredentialsFromDialog:(id)sender;
|
||||
@property (atomic, retain) UITableView *tableView;
|
||||
@end
|
||||
|
||||
@implementation ASIAuthenticationDialog
|
||||
|
||||
#pragma mark init / dealloc
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self == [ASIAuthenticationDialog class]) {
|
||||
requestsNeedingAuthentication = [[NSMutableArray array] retain];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)presentAuthenticationDialogForRequest:(ASIHTTPRequest *)theRequest
|
||||
{
|
||||
// No need for a lock here, this will always be called on the main thread
|
||||
if (!sharedDialog) {
|
||||
sharedDialog = [[self alloc] init];
|
||||
[sharedDialog setRequest:theRequest];
|
||||
if ([theRequest authenticationNeeded] == ASIProxyAuthenticationNeeded) {
|
||||
[sharedDialog setType:ASIProxyAuthenticationType];
|
||||
} else {
|
||||
[sharedDialog setType:ASIStandardAuthenticationType];
|
||||
}
|
||||
[sharedDialog show];
|
||||
} else {
|
||||
[requestsNeedingAuthentication addObject:theRequest];
|
||||
}
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
if ((self = [self initWithNibName:nil bundle:nil])) {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
|
||||
#endif
|
||||
if (![UIDevice currentDevice].generatesDeviceOrientationNotifications) {
|
||||
[[UIDevice currentDevice] beginGeneratingDeviceOrientationNotifications];
|
||||
[self setDidEnableRotationNotifications:YES];
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(orientationChanged:) name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if ([self didEnableRotationNotifications]) {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIDeviceOrientationDidChangeNotification object:nil];
|
||||
}
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:UIKeyboardWillShowNotification object:nil];
|
||||
|
||||
[request release];
|
||||
[tableView release];
|
||||
[presentingController.view removeFromSuperview];
|
||||
[presentingController release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark keyboard notifications
|
||||
|
||||
- (void)keyboardWillShow:(NSNotification *)notification
|
||||
{
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPhone) {
|
||||
#endif
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_3_2
|
||||
NSValue *keyboardBoundsValue = [[notification userInfo] objectForKey:UIKeyboardFrameEndUserInfoKey];
|
||||
#else
|
||||
NSValue *keyboardBoundsValue = [[notification userInfo] objectForKey:UIKeyboardBoundsUserInfoKey];
|
||||
#endif
|
||||
CGRect keyboardBounds;
|
||||
[keyboardBoundsValue getValue:&keyboardBounds];
|
||||
UIEdgeInsets e = UIEdgeInsetsMake(0, 0, keyboardBounds.size.height, 0);
|
||||
[[self tableView] setScrollIndicatorInsets:e];
|
||||
[[self tableView] setContentInset:e];
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// Manually handles orientation changes on iPhone
|
||||
- (void)orientationChanged:(NSNotification *)notification
|
||||
{
|
||||
[self showTitle];
|
||||
|
||||
UIInterfaceOrientation o = (UIInterfaceOrientation)[[UIApplication sharedApplication] statusBarOrientation];
|
||||
CGFloat angle = 0;
|
||||
switch (o) {
|
||||
case UIDeviceOrientationLandscapeLeft: angle = 90; break;
|
||||
case UIDeviceOrientationLandscapeRight: angle = -90; break;
|
||||
case UIDeviceOrientationPortraitUpsideDown: angle = 180; break;
|
||||
default: break;
|
||||
}
|
||||
|
||||
CGRect f = [[UIScreen mainScreen] bounds];
|
||||
|
||||
// Swap the frame height and width if necessary
|
||||
if (UIInterfaceOrientationIsLandscape(o)) {
|
||||
CGFloat t;
|
||||
t = f.size.width;
|
||||
f.size.width = f.size.height;
|
||||
f.size.height = t;
|
||||
}
|
||||
|
||||
CGAffineTransform previousTransform = self.view.layer.affineTransform;
|
||||
CGAffineTransform newTransform = CGAffineTransformMakeRotation((CGFloat)(angle * M_PI / 180.0));
|
||||
|
||||
// Reset the transform so we can set the size
|
||||
self.view.layer.affineTransform = CGAffineTransformIdentity;
|
||||
self.view.frame = (CGRect){ { 0, 0 }, f.size};
|
||||
|
||||
// Revert to the previous transform for correct animation
|
||||
self.view.layer.affineTransform = previousTransform;
|
||||
|
||||
[UIView beginAnimations:nil context:NULL];
|
||||
[UIView setAnimationDuration:0.3];
|
||||
|
||||
// Set the new transform
|
||||
self.view.layer.affineTransform = newTransform;
|
||||
|
||||
// Fix the view origin
|
||||
self.view.frame = (CGRect){ { f.origin.x, f.origin.y },self.view.frame.size};
|
||||
[UIView commitAnimations];
|
||||
}
|
||||
|
||||
#pragma mark utilities
|
||||
|
||||
- (UIViewController *)presentingController
|
||||
{
|
||||
if (!presentingController) {
|
||||
presentingController = [[ASIAutorotatingViewController alloc] initWithNibName:nil bundle:nil];
|
||||
|
||||
// Attach to the window, but don't interfere.
|
||||
UIWindow *window = [[[UIApplication sharedApplication] windows] objectAtIndex:0];
|
||||
[window addSubview:[presentingController view]];
|
||||
[[presentingController view] setFrame:CGRectZero];
|
||||
[[presentingController view] setUserInteractionEnabled:NO];
|
||||
}
|
||||
|
||||
return presentingController;
|
||||
}
|
||||
|
||||
- (UITextField *)textFieldInRow:(NSUInteger)row section:(NSUInteger)section
|
||||
{
|
||||
return [[[[[self tableView] cellForRowAtIndexPath:
|
||||
[NSIndexPath indexPathForRow:(NSInteger)row inSection:(NSInteger)section]]
|
||||
contentView] subviews] objectAtIndex:0];
|
||||
}
|
||||
|
||||
- (UITextField *)usernameField
|
||||
{
|
||||
return [self textFieldInRow:kUsernameRow section:kUsernameSection];
|
||||
}
|
||||
|
||||
- (UITextField *)passwordField
|
||||
{
|
||||
return [self textFieldInRow:kPasswordRow section:kPasswordSection];
|
||||
}
|
||||
|
||||
- (UITextField *)domainField
|
||||
{
|
||||
return [self textFieldInRow:kDomainRow section:kDomainSection];
|
||||
}
|
||||
|
||||
#pragma mark show / dismiss
|
||||
|
||||
+ (void)dismiss
|
||||
{
|
||||
UIViewController* dismisser = nil;
|
||||
if ([sharedDialog respondsToSelector:@selector(presentingViewController)]){
|
||||
dismisser = [sharedDialog presentingViewController];
|
||||
}else{
|
||||
dismisser = [sharedDialog parentViewController];
|
||||
}
|
||||
if([dismisser respondsToSelector:@selector(dismissViewControllerAnimated:completion:)]){
|
||||
[dismisser dismissViewControllerAnimated:YES completion:nil];
|
||||
}else{
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[dismisser dismissModalViewControllerAnimated:YES];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
}
|
||||
|
||||
- (void)viewDidDisappear:(BOOL)animated
|
||||
{
|
||||
[super viewDidDisappear:animated];
|
||||
[self retain];
|
||||
[sharedDialog release];
|
||||
sharedDialog = nil;
|
||||
[self performSelector:@selector(presentNextDialog) withObject:nil afterDelay:0];
|
||||
[self release];
|
||||
}
|
||||
|
||||
- (void)dismiss
|
||||
{
|
||||
if (self == sharedDialog) {
|
||||
[[self class] dismiss];
|
||||
} else {
|
||||
UIViewController* dismisser = nil;
|
||||
if ([self respondsToSelector:@selector(presentingViewController)]){
|
||||
dismisser = [self presentingViewController];
|
||||
}else{
|
||||
dismisser = [self parentViewController];
|
||||
}
|
||||
if([dismisser respondsToSelector:@selector(dismissViewControllerAnimated:completion:)]){
|
||||
[dismisser dismissViewControllerAnimated:YES completion:nil];
|
||||
}else{
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[dismisser dismissModalViewControllerAnimated:YES];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)showTitle
|
||||
{
|
||||
UINavigationBar *navigationBar = [[[self view] subviews] objectAtIndex:0];
|
||||
UINavigationItem *navItem = [[navigationBar items] objectAtIndex:0];
|
||||
if (UIDeviceOrientationIsPortrait([[UIDevice currentDevice] orientation])) {
|
||||
// Setup the title
|
||||
if ([self type] == ASIProxyAuthenticationType) {
|
||||
[navItem setPrompt:@"Login to this secure proxy server."];
|
||||
} else {
|
||||
[navItem setPrompt:@"Login to this secure server."];
|
||||
}
|
||||
} else {
|
||||
[navItem setPrompt:nil];
|
||||
}
|
||||
[navigationBar sizeToFit];
|
||||
CGRect f = [[self view] bounds];
|
||||
f.origin.y = [navigationBar frame].size.height;
|
||||
f.size.height -= f.origin.y;
|
||||
[[self tableView] setFrame:f];
|
||||
}
|
||||
|
||||
- (void)show
|
||||
{
|
||||
// Remove all subviews
|
||||
UIView *v;
|
||||
while ((v = [[[self view] subviews] lastObject])) {
|
||||
[v removeFromSuperview];
|
||||
}
|
||||
|
||||
// Setup toolbar
|
||||
UINavigationBar *bar = [[[UINavigationBar alloc] init] autorelease];
|
||||
[bar setAutoresizingMask:UIViewAutoresizingFlexibleWidth];
|
||||
|
||||
UINavigationItem *navItem = [[[UINavigationItem alloc] init] autorelease];
|
||||
bar.items = [NSArray arrayWithObject:navItem];
|
||||
|
||||
[[self view] addSubview:bar];
|
||||
|
||||
[self showTitle];
|
||||
|
||||
// Setup toolbar buttons
|
||||
if ([self type] == ASIProxyAuthenticationType) {
|
||||
[navItem setTitle:[[self request] proxyHost]];
|
||||
} else {
|
||||
[navItem setTitle:[[[self request] url] host]];
|
||||
}
|
||||
|
||||
[navItem setLeftBarButtonItem:[[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelAuthenticationFromDialog:)] autorelease]];
|
||||
[navItem setRightBarButtonItem:[[[UIBarButtonItem alloc] initWithTitle:@"Login" style:UIBarButtonItemStyleDone target:self action:@selector(loginWithCredentialsFromDialog:)] autorelease]];
|
||||
|
||||
// We show the login form in a table view, similar to Safari's authentication dialog
|
||||
[bar sizeToFit];
|
||||
CGRect f = [[self view] bounds];
|
||||
f.origin.y = [bar frame].size.height;
|
||||
f.size.height -= f.origin.y;
|
||||
|
||||
[self setTableView:[[[UITableView alloc] initWithFrame:f style:UITableViewStyleGrouped] autorelease]];
|
||||
[[self tableView] setDelegate:self];
|
||||
[[self tableView] setDataSource:self];
|
||||
[[self tableView] setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
|
||||
[[self view] addSubview:[self tableView]];
|
||||
|
||||
// Force reload the table content, and focus the first field to show the keyboard
|
||||
[[self tableView] reloadData];
|
||||
[[[[[self tableView] cellForRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]].contentView subviews] objectAtIndex:0] becomeFirstResponder];
|
||||
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
|
||||
[self setModalPresentationStyle:UIModalPresentationFormSheet];
|
||||
}
|
||||
#endif
|
||||
|
||||
if([[self presentingController] respondsToSelector:@selector(presentViewController:animated:completion:)]){
|
||||
[[self presentingController] presentViewController:self animated:YES completion:nil];
|
||||
}else{
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wdeprecated-declarations"
|
||||
[[self presentingController] presentModalViewController:self animated:YES];
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark button callbacks
|
||||
|
||||
- (void)cancelAuthenticationFromDialog:(id)sender
|
||||
{
|
||||
for (ASIHTTPRequest *theRequest in [self requestsRequiringTheseCredentials]) {
|
||||
[theRequest cancelAuthentication];
|
||||
[requestsNeedingAuthentication removeObject:theRequest];
|
||||
}
|
||||
[self dismiss];
|
||||
}
|
||||
|
||||
- (NSArray *)requestsRequiringTheseCredentials
|
||||
{
|
||||
NSMutableArray *requestsRequiringTheseCredentials = [NSMutableArray array];
|
||||
NSURL *requestURL = [[self request] url];
|
||||
for (ASIHTTPRequest *otherRequest in requestsNeedingAuthentication) {
|
||||
NSURL *theURL = [otherRequest url];
|
||||
if (([otherRequest authenticationNeeded] == [[self request] authenticationNeeded]) && [[theURL host] isEqualToString:[requestURL host]] && ([theURL port] == [requestURL port] || ([requestURL port] && [[theURL port] isEqualToNumber:[requestURL port]])) && [[theURL scheme] isEqualToString:[requestURL scheme]] && ((![otherRequest authenticationRealm] && ![[self request] authenticationRealm]) || ([otherRequest authenticationRealm] && [[self request] authenticationRealm] && [[[self request] authenticationRealm] isEqualToString:[otherRequest authenticationRealm]]))) {
|
||||
[requestsRequiringTheseCredentials addObject:otherRequest];
|
||||
}
|
||||
}
|
||||
[requestsRequiringTheseCredentials addObject:[self request]];
|
||||
return requestsRequiringTheseCredentials;
|
||||
}
|
||||
|
||||
- (void)presentNextDialog
|
||||
{
|
||||
if ([requestsNeedingAuthentication count]) {
|
||||
ASIHTTPRequest *nextRequest = [requestsNeedingAuthentication objectAtIndex:0];
|
||||
[requestsNeedingAuthentication removeObjectAtIndex:0];
|
||||
[[self class] presentAuthenticationDialogForRequest:nextRequest];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (void)loginWithCredentialsFromDialog:(id)sender
|
||||
{
|
||||
for (ASIHTTPRequest *theRequest in [self requestsRequiringTheseCredentials]) {
|
||||
|
||||
NSString *username = [[self usernameField] text];
|
||||
NSString *password = [[self passwordField] text];
|
||||
|
||||
if (username == nil) { username = @""; }
|
||||
if (password == nil) { password = @""; }
|
||||
|
||||
if ([self type] == ASIProxyAuthenticationType) {
|
||||
[theRequest setProxyUsername:username];
|
||||
[theRequest setProxyPassword:password];
|
||||
} else {
|
||||
[theRequest setUsername:username];
|
||||
[theRequest setPassword:password];
|
||||
}
|
||||
|
||||
// Handle NTLM domains
|
||||
NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme];
|
||||
if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) {
|
||||
NSString *domain = [[self domainField] text];
|
||||
if ([self type] == ASIProxyAuthenticationType) {
|
||||
[theRequest setProxyDomain:domain];
|
||||
} else {
|
||||
[theRequest setDomain:domain];
|
||||
}
|
||||
}
|
||||
|
||||
[theRequest retryUsingSuppliedCredentials];
|
||||
[requestsNeedingAuthentication removeObject:theRequest];
|
||||
}
|
||||
[self dismiss];
|
||||
}
|
||||
|
||||
#pragma mark table view data source
|
||||
|
||||
- (NSInteger)numberOfSectionsInTableView:(UITableView *)aTableView
|
||||
{
|
||||
NSString *scheme = ([self type] == ASIStandardAuthenticationType) ? [[self request] authenticationScheme] : [[self request] proxyAuthenticationScheme];
|
||||
if ([scheme isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeNTLM]) {
|
||||
return 2;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)aTableView heightForFooterInSection:(NSInteger)section
|
||||
{
|
||||
if (section == [self numberOfSectionsInTableView:aTableView]-1) {
|
||||
return 30;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (CGFloat)tableView:(UITableView *)aTableView heightForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
if (section == 0) {
|
||||
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_3_2
|
||||
if (UI_USER_INTERFACE_IDIOM() == UIUserInterfaceIdiomPad) {
|
||||
return 54;
|
||||
}
|
||||
#endif
|
||||
return 30;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
- (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section
|
||||
{
|
||||
if (section == 0) {
|
||||
return [[self request] authenticationRealm];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
|
||||
{
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= __IPHONE_3_0
|
||||
UITableViewCell *cell = [[[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil] autorelease];
|
||||
#else
|
||||
UITableViewCell *cell = [[[UITableViewCell alloc] initWithFrame:CGRectMake(0,0,0,0) reuseIdentifier:nil] autorelease];
|
||||
#endif
|
||||
|
||||
[cell setSelectionStyle:UITableViewCellSelectionStyleNone];
|
||||
|
||||
CGRect f = CGRectInset([cell bounds], 10, 10);
|
||||
UITextField *textField = [[[UITextField alloc] initWithFrame:f] autorelease];
|
||||
[textField setAutoresizingMask:UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight];
|
||||
[textField setAutocapitalizationType:UITextAutocapitalizationTypeNone];
|
||||
[textField setAutocorrectionType:UITextAutocorrectionTypeNo];
|
||||
|
||||
NSInteger s = [indexPath section];
|
||||
NSInteger r = [indexPath row];
|
||||
|
||||
if (s == kUsernameSection && r == kUsernameRow) {
|
||||
[textField setPlaceholder:@"User"];
|
||||
} else if (s == kPasswordSection && r == kPasswordRow) {
|
||||
[textField setPlaceholder:@"Password"];
|
||||
[textField setSecureTextEntry:YES];
|
||||
} else if (s == kDomainSection && r == kDomainRow) {
|
||||
[textField setPlaceholder:@"Domain"];
|
||||
}
|
||||
[cell.contentView addSubview:textField];
|
||||
|
||||
return cell;
|
||||
}
|
||||
|
||||
- (NSInteger)tableView:(UITableView *)aTableView numberOfRowsInSection:(NSInteger)section
|
||||
{
|
||||
if (section == 0) {
|
||||
return 2;
|
||||
} else {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
- (NSString *)tableView:(UITableView *)aTableView titleForFooterInSection:(NSInteger)section
|
||||
{
|
||||
if (section == [self numberOfSectionsInTableView:aTableView]-1) {
|
||||
// If we're using Basic authentication and the connection is not using SSL, we'll show the plain text message
|
||||
if ([[[self request] authenticationScheme] isEqualToString:(NSString *)kCFHTTPAuthenticationSchemeBasic] && ![[[[self request] url] scheme] isEqualToString:@"https"]) {
|
||||
return @"Password will be sent in the clear.";
|
||||
// We are using Digest, NTLM, or any scheme over SSL
|
||||
} else {
|
||||
return @"Password will be sent securely.";
|
||||
}
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@synthesize request;
|
||||
@synthesize type;
|
||||
@synthesize tableView;
|
||||
@synthesize didEnableRotationNotifications;
|
||||
@synthesize presentingController;
|
||||
@end
|
|
@ -1,103 +0,0 @@
|
|||
//
|
||||
// ASICacheDelegate.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 01/05/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
@class ASIHTTPRequest;
|
||||
|
||||
// Cache policies control the behaviour of a cache and how requests use the cache
|
||||
// When setting a cache policy, you can use a combination of these values as a bitmask
|
||||
// For example: [request setCachePolicy:ASIAskServerIfModifiedCachePolicy|ASIFallbackToCacheIfLoadFailsCachePolicy|ASIDoNotWriteToCacheCachePolicy];
|
||||
// Note that some of the behaviours below are mutally exclusive - you cannot combine ASIAskServerIfModifiedWhenStaleCachePolicy and ASIAskServerIfModifiedCachePolicy, for example.
|
||||
typedef enum _ASICachePolicy {
|
||||
|
||||
// The default cache policy. When you set a request to use this, it will use the cache's defaultCachePolicy
|
||||
// ASIDownloadCache's default cache policy is 'ASIAskServerIfModifiedWhenStaleCachePolicy'
|
||||
ASIUseDefaultCachePolicy = 0,
|
||||
|
||||
// Tell the request not to read from the cache
|
||||
ASIDoNotReadFromCacheCachePolicy = 1,
|
||||
|
||||
// The the request not to write to the cache
|
||||
ASIDoNotWriteToCacheCachePolicy = 2,
|
||||
|
||||
// Ask the server if there is an updated version of this resource (using a conditional GET) ONLY when the cached data is stale
|
||||
ASIAskServerIfModifiedWhenStaleCachePolicy = 4,
|
||||
|
||||
// Always ask the server if there is an updated version of this resource (using a conditional GET)
|
||||
ASIAskServerIfModifiedCachePolicy = 8,
|
||||
|
||||
// If cached data exists, use it even if it is stale. This means requests will not talk to the server unless the resource they are requesting is not in the cache
|
||||
ASIOnlyLoadIfNotCachedCachePolicy = 16,
|
||||
|
||||
// If cached data exists, use it even if it is stale. If cached data does not exist, stop (will not set an error on the request)
|
||||
ASIDontLoadCachePolicy = 32,
|
||||
|
||||
// Specifies that cached data may be used if the request fails. If cached data is used, the request will succeed without error. Usually used in combination with other options above.
|
||||
ASIFallbackToCacheIfLoadFailsCachePolicy = 64
|
||||
} ASICachePolicy;
|
||||
|
||||
// Cache storage policies control whether cached data persists between application launches (ASICachePermanentlyCacheStoragePolicy) or not (ASICacheForSessionDurationCacheStoragePolicy)
|
||||
// Calling [ASIHTTPRequest clearSession] will remove any data stored using ASICacheForSessionDurationCacheStoragePolicy
|
||||
typedef enum _ASICacheStoragePolicy {
|
||||
ASICacheForSessionDurationCacheStoragePolicy = 0,
|
||||
ASICachePermanentlyCacheStoragePolicy = 1
|
||||
} ASICacheStoragePolicy;
|
||||
|
||||
|
||||
@protocol ASICacheDelegate <NSObject>
|
||||
|
||||
@required
|
||||
|
||||
// Should return the cache policy that will be used when requests have their cache policy set to ASIUseDefaultCachePolicy
|
||||
- (ASICachePolicy)defaultCachePolicy;
|
||||
|
||||
// Returns the date a cached response should expire on. Pass a non-zero max age to specify a custom date.
|
||||
- (NSDate *)expiryDateForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge;
|
||||
|
||||
// Updates cached response headers with a new expiry date. Pass a non-zero max age to specify a custom date.
|
||||
- (void)updateExpiryForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge;
|
||||
|
||||
// Looks at the request's cache policy and any cached headers to determine if the cache data is still valid
|
||||
- (BOOL)canUseCachedDataForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// Removes cached data for a particular request
|
||||
- (void)removeCachedDataForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// Should return YES if the cache considers its cached response current for the request
|
||||
// Should return NO is the data is not cached, or (for example) if the cached headers state the request should have expired
|
||||
- (BOOL)isCachedDataCurrentForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// Should store the response for the passed request in the cache
|
||||
// When a non-zero maxAge is passed, it should be used as the expiry time for the cached response
|
||||
- (void)storeResponseForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge;
|
||||
|
||||
// Removes cached data for a particular url
|
||||
- (void)removeCachedDataForURL:(NSURL *)url;
|
||||
|
||||
// Should return an NSDictionary of cached headers for the passed URL, if it is stored in the cache
|
||||
- (NSDictionary *)cachedResponseHeadersForURL:(NSURL *)url;
|
||||
|
||||
// Should return the cached body of a response for the passed URL, if it is stored in the cache
|
||||
- (NSData *)cachedResponseDataForURL:(NSURL *)url;
|
||||
|
||||
// Returns a path to the cached response data, if it exists
|
||||
- (NSString *)pathToCachedResponseDataForURL:(NSURL *)url;
|
||||
|
||||
// Returns a path to the cached response headers, if they url
|
||||
- (NSString *)pathToCachedResponseHeadersForURL:(NSURL *)url;
|
||||
|
||||
// Returns the location to use to store cached response headers for a particular request
|
||||
- (NSString *)pathToStoreCachedResponseHeadersForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// Returns the location to use to store a cached response body for a particular request
|
||||
- (NSString *)pathToStoreCachedResponseDataForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// Clear cached data stored for the passed storage policy
|
||||
- (void)clearCachedResponsesForStoragePolicy:(ASICacheStoragePolicy)cachePolicy;
|
||||
|
||||
@end
|
|
@ -1,42 +0,0 @@
|
|||
//
|
||||
// ASIDataCompressor.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 17/08/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
// This is a helper class used by ASIHTTPRequest to handle deflating (compressing) data in memory and on disk
|
||||
// You may also find it helpful if you need to deflate data and files yourself - see the class methods below
|
||||
// Most of the zlib stuff is based on the sample code by Mark Adler available at http://zlib.net
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <zlib.h>
|
||||
|
||||
@interface ASIDataCompressor : NSObject {
|
||||
BOOL streamReady;
|
||||
z_stream zStream;
|
||||
}
|
||||
|
||||
// Convenience constructor will call setupStream for you
|
||||
+ (id)compressor;
|
||||
|
||||
// Compress the passed chunk of data
|
||||
// Passing YES for shouldFinish will finalize the deflated data - you must pass YES when you are on the last chunk of data
|
||||
- (NSData *)compressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err shouldFinish:(BOOL)shouldFinish;
|
||||
|
||||
// Convenience method - pass it some data, and you'll get deflated data back
|
||||
+ (NSData *)compressData:(NSData*)uncompressedData error:(NSError **)err;
|
||||
|
||||
// Convenience method - pass it a file containing the data to compress in sourcePath, and it will write deflated data to destinationPath
|
||||
+ (BOOL)compressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err;
|
||||
|
||||
// Sets up zlib to handle the inflating. You only need to call this yourself if you aren't using the convenience constructor 'compressor'
|
||||
- (NSError *)setupStream;
|
||||
|
||||
// Tells zlib to clean up. You need to call this if you need to cancel deflating part way through
|
||||
// If deflating finishes or fails, this method will be called automatically
|
||||
- (NSError *)closeStream;
|
||||
|
||||
@property (atomic, assign, readonly) BOOL streamReady;
|
||||
@end
|
|
@ -1,219 +0,0 @@
|
|||
//
|
||||
// ASIDataCompressor.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 17/08/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIDataCompressor.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
|
||||
#define DATA_CHUNK_SIZE 262144 // Deal with gzipped data in 256KB chunks
|
||||
#define COMPRESSION_AMOUNT Z_DEFAULT_COMPRESSION
|
||||
|
||||
@interface ASIDataCompressor ()
|
||||
+ (NSError *)deflateErrorWithCode:(int)code;
|
||||
@end
|
||||
|
||||
@implementation ASIDataCompressor
|
||||
|
||||
+ (id)compressor
|
||||
{
|
||||
ASIDataCompressor *compressor = [[[self alloc] init] autorelease];
|
||||
[compressor setupStream];
|
||||
return compressor;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (streamReady) {
|
||||
[self closeStream];
|
||||
}
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSError *)setupStream
|
||||
{
|
||||
if (streamReady) {
|
||||
return nil;
|
||||
}
|
||||
// Setup the inflate stream
|
||||
zStream.zalloc = Z_NULL;
|
||||
zStream.zfree = Z_NULL;
|
||||
zStream.opaque = Z_NULL;
|
||||
zStream.avail_in = 0;
|
||||
zStream.next_in = 0;
|
||||
int status = deflateInit2(&zStream, COMPRESSION_AMOUNT, Z_DEFLATED, (15+16), 8, Z_DEFAULT_STRATEGY);
|
||||
if (status != Z_OK) {
|
||||
return [[self class] deflateErrorWithCode:status];
|
||||
}
|
||||
streamReady = YES;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSError *)closeStream
|
||||
{
|
||||
if (!streamReady) {
|
||||
return nil;
|
||||
}
|
||||
// Close the deflate stream
|
||||
streamReady = NO;
|
||||
int status = deflateEnd(&zStream);
|
||||
if (status != Z_OK) {
|
||||
return [[self class] deflateErrorWithCode:status];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSData *)compressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err shouldFinish:(BOOL)shouldFinish
|
||||
{
|
||||
if (length == 0) return nil;
|
||||
|
||||
NSUInteger halfLength = length/2;
|
||||
|
||||
// We'll take a guess that the compressed data will fit in half the size of the original (ie the max to compress at once is half DATA_CHUNK_SIZE), if not, we'll increase it below
|
||||
NSMutableData *outputData = [NSMutableData dataWithLength:length/2];
|
||||
|
||||
int status;
|
||||
|
||||
zStream.next_in = bytes;
|
||||
zStream.avail_in = (unsigned int)length;
|
||||
zStream.avail_out = 0;
|
||||
|
||||
NSUInteger bytesProcessedAlready = zStream.total_out;
|
||||
while (zStream.avail_out == 0) {
|
||||
|
||||
if (zStream.total_out-bytesProcessedAlready >= [outputData length]) {
|
||||
[outputData increaseLengthBy:halfLength];
|
||||
}
|
||||
|
||||
zStream.next_out = (Bytef*)[outputData mutableBytes] + zStream.total_out-bytesProcessedAlready;
|
||||
zStream.avail_out = (unsigned int)([outputData length] - (zStream.total_out-bytesProcessedAlready));
|
||||
status = deflate(&zStream, shouldFinish ? Z_FINISH : Z_NO_FLUSH);
|
||||
|
||||
if (status == Z_STREAM_END) {
|
||||
break;
|
||||
} else if (status != Z_OK) {
|
||||
if (err) {
|
||||
*err = [[self class] deflateErrorWithCode:status];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
// Set real length
|
||||
[outputData setLength: zStream.total_out-bytesProcessedAlready];
|
||||
return outputData;
|
||||
}
|
||||
|
||||
|
||||
+ (NSData *)compressData:(NSData*)uncompressedData error:(NSError **)err
|
||||
{
|
||||
NSError *theError = nil;
|
||||
NSData *outputData = [[ASIDataCompressor compressor] compressBytes:(Bytef *)[uncompressedData bytes] length:[uncompressedData length] error:&theError shouldFinish:YES];
|
||||
if (theError) {
|
||||
if (err) {
|
||||
*err = theError;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
return outputData;
|
||||
}
|
||||
|
||||
|
||||
|
||||
+ (BOOL)compressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err
|
||||
{
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
// Create an empty file at the destination path
|
||||
if (![fileManager createFileAtPath:destinationPath contents:[NSData data] attributes:nil]) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed because we were to create a file at %@",sourcePath,destinationPath],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Ensure the source file exists
|
||||
if (![fileManager fileExistsAtPath:sourcePath]) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed the file does not exist",sourcePath],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
UInt8 inputData[DATA_CHUNK_SIZE];
|
||||
NSData *outputData;
|
||||
NSInteger readLength;
|
||||
NSError *theError = nil;
|
||||
|
||||
ASIDataCompressor *compressor = [ASIDataCompressor compressor];
|
||||
|
||||
NSInputStream *inputStream = [NSInputStream inputStreamWithFileAtPath:sourcePath];
|
||||
[inputStream open];
|
||||
NSOutputStream *outputStream = [NSOutputStream outputStreamToFileAtPath:destinationPath append:NO];
|
||||
[outputStream open];
|
||||
|
||||
while ([compressor streamReady]) {
|
||||
|
||||
// Read some data from the file
|
||||
readLength = [inputStream read:inputData maxLength:DATA_CHUNK_SIZE];
|
||||
|
||||
// Make sure nothing went wrong
|
||||
if ([inputStream streamStatus] == NSStreamStatusError) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed because we were unable to read from the source data file",sourcePath],NSLocalizedDescriptionKey,[inputStream streamError],NSUnderlyingErrorKey,nil]];
|
||||
}
|
||||
[compressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
// Have we reached the end of the input data?
|
||||
if (!readLength) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Attempt to deflate the chunk of data
|
||||
outputData = [compressor compressBytes:inputData length:(NSUInteger)readLength error:&theError shouldFinish:readLength < DATA_CHUNK_SIZE];
|
||||
if (theError) {
|
||||
if (err) {
|
||||
*err = theError;
|
||||
}
|
||||
[compressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Write the deflated data out to the destination file
|
||||
[outputStream write:(const uint8_t *)[outputData bytes] maxLength:[outputData length]];
|
||||
|
||||
// Make sure nothing went wrong
|
||||
if ([inputStream streamStatus] == NSStreamStatusError) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of %@ failed because we were unable to write to the destination data file at %@",sourcePath,destinationPath],NSLocalizedDescriptionKey,[outputStream streamError],NSUnderlyingErrorKey,nil]];
|
||||
}
|
||||
[compressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
|
||||
}
|
||||
[inputStream close];
|
||||
[outputStream close];
|
||||
|
||||
NSError *error = [compressor closeStream];
|
||||
if (error) {
|
||||
if (err) {
|
||||
*err = error;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (NSError *)deflateErrorWithCode:(int)code
|
||||
{
|
||||
return [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Compression of data failed with code %d",code],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
|
||||
@synthesize streamReady;
|
||||
@end
|
|
@ -1,41 +0,0 @@
|
|||
//
|
||||
// ASIDataDecompressor.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 17/08/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
// This is a helper class used by ASIHTTPRequest to handle inflating (decompressing) data in memory and on disk
|
||||
// You may also find it helpful if you need to inflate data and files yourself - see the class methods below
|
||||
// Most of the zlib stuff is based on the sample code by Mark Adler available at http://zlib.net
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <zlib.h>
|
||||
|
||||
@interface ASIDataDecompressor : NSObject {
|
||||
BOOL streamReady;
|
||||
z_stream zStream;
|
||||
}
|
||||
|
||||
// Convenience constructor will call setupStream for you
|
||||
+ (id)decompressor;
|
||||
|
||||
// Uncompress the passed chunk of data
|
||||
- (NSData *)uncompressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err;
|
||||
|
||||
// Convenience method - pass it some deflated data, and you'll get inflated data back
|
||||
+ (NSData *)uncompressData:(NSData*)compressedData error:(NSError **)err;
|
||||
|
||||
// Convenience method - pass it a file containing deflated data in sourcePath, and it will write inflated data to destinationPath
|
||||
+ (BOOL)uncompressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err;
|
||||
|
||||
// Sets up zlib to handle the inflating. You only need to call this yourself if you aren't using the convenience constructor 'decompressor'
|
||||
- (NSError *)setupStream;
|
||||
|
||||
// Tells zlib to clean up. You need to call this if you need to cancel inflating part way through
|
||||
// If inflating finishes or fails, this method will be called automatically
|
||||
- (NSError *)closeStream;
|
||||
|
||||
@property (atomic, assign, readonly) BOOL streamReady;
|
||||
@end
|
|
@ -1,218 +0,0 @@
|
|||
//
|
||||
// ASIDataDecompressor.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 17/08/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIDataDecompressor.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
|
||||
#define DATA_CHUNK_SIZE 262144 // Deal with gzipped data in 256KB chunks
|
||||
|
||||
@interface ASIDataDecompressor ()
|
||||
+ (NSError *)inflateErrorWithCode:(int)code;
|
||||
@end;
|
||||
|
||||
@implementation ASIDataDecompressor
|
||||
|
||||
+ (id)decompressor
|
||||
{
|
||||
ASIDataDecompressor *decompressor = [[[self alloc] init] autorelease];
|
||||
[decompressor setupStream];
|
||||
return decompressor;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
if (streamReady) {
|
||||
[self closeStream];
|
||||
}
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSError *)setupStream
|
||||
{
|
||||
if (streamReady) {
|
||||
return nil;
|
||||
}
|
||||
// Setup the inflate stream
|
||||
zStream.zalloc = Z_NULL;
|
||||
zStream.zfree = Z_NULL;
|
||||
zStream.opaque = Z_NULL;
|
||||
zStream.avail_in = 0;
|
||||
zStream.next_in = 0;
|
||||
int status = inflateInit2(&zStream, (15+32));
|
||||
if (status != Z_OK) {
|
||||
return [[self class] inflateErrorWithCode:status];
|
||||
}
|
||||
streamReady = YES;
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSError *)closeStream
|
||||
{
|
||||
if (!streamReady) {
|
||||
return nil;
|
||||
}
|
||||
// Close the inflate stream
|
||||
streamReady = NO;
|
||||
int status = inflateEnd(&zStream);
|
||||
if (status != Z_OK) {
|
||||
return [[self class] inflateErrorWithCode:status];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSData *)uncompressBytes:(Bytef *)bytes length:(NSUInteger)length error:(NSError **)err
|
||||
{
|
||||
if (length == 0) return nil;
|
||||
|
||||
NSUInteger halfLength = length/2;
|
||||
NSMutableData *outputData = [NSMutableData dataWithLength:length+halfLength];
|
||||
|
||||
int status;
|
||||
|
||||
zStream.next_in = bytes;
|
||||
zStream.avail_in = (unsigned int)length;
|
||||
zStream.avail_out = 0;
|
||||
|
||||
NSUInteger bytesProcessedAlready = zStream.total_out;
|
||||
while (zStream.avail_in != 0) {
|
||||
|
||||
if (zStream.total_out-bytesProcessedAlready >= [outputData length]) {
|
||||
[outputData increaseLengthBy:halfLength];
|
||||
}
|
||||
|
||||
zStream.next_out = (Bytef*)[outputData mutableBytes] + zStream.total_out-bytesProcessedAlready;
|
||||
zStream.avail_out = (unsigned int)([outputData length] - (zStream.total_out-bytesProcessedAlready));
|
||||
|
||||
status = inflate(&zStream, Z_NO_FLUSH);
|
||||
|
||||
if (status == Z_STREAM_END) {
|
||||
break;
|
||||
} else if (status != Z_OK) {
|
||||
if (err) {
|
||||
*err = [[self class] inflateErrorWithCode:status];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
}
|
||||
|
||||
// Set real length
|
||||
[outputData setLength: zStream.total_out-bytesProcessedAlready];
|
||||
return outputData;
|
||||
}
|
||||
|
||||
|
||||
+ (NSData *)uncompressData:(NSData*)compressedData error:(NSError **)err
|
||||
{
|
||||
NSError *theError = nil;
|
||||
NSData *outputData = [[ASIDataDecompressor decompressor] uncompressBytes:(Bytef *)[compressedData bytes] length:[compressedData length] error:&theError];
|
||||
if (theError) {
|
||||
if (err) {
|
||||
*err = theError;
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
return outputData;
|
||||
}
|
||||
|
||||
+ (BOOL)uncompressDataFromFile:(NSString *)sourcePath toFile:(NSString *)destinationPath error:(NSError **)err
|
||||
{
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
// Create an empty file at the destination path
|
||||
if (![fileManager createFileAtPath:destinationPath contents:[NSData data] attributes:nil]) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed because we were to create a file at %@",sourcePath,destinationPath],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Ensure the source file exists
|
||||
if (![fileManager fileExistsAtPath:sourcePath]) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed the file does not exist",sourcePath],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
UInt8 inputData[DATA_CHUNK_SIZE];
|
||||
NSData *outputData;
|
||||
NSInteger readLength;
|
||||
NSError *theError = nil;
|
||||
|
||||
|
||||
ASIDataDecompressor *decompressor = [ASIDataDecompressor decompressor];
|
||||
|
||||
NSInputStream *inputStream = [NSInputStream inputStreamWithFileAtPath:sourcePath];
|
||||
[inputStream open];
|
||||
NSOutputStream *outputStream = [NSOutputStream outputStreamToFileAtPath:destinationPath append:NO];
|
||||
[outputStream open];
|
||||
|
||||
while ([decompressor streamReady]) {
|
||||
|
||||
// Read some data from the file
|
||||
readLength = [inputStream read:inputData maxLength:DATA_CHUNK_SIZE];
|
||||
|
||||
// Make sure nothing went wrong
|
||||
if ([inputStream streamStatus] == NSStreamStatusError) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed because we were unable to read from the source data file",sourcePath],NSLocalizedDescriptionKey,[inputStream streamError],NSUnderlyingErrorKey,nil]];
|
||||
}
|
||||
[decompressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
// Have we reached the end of the input data?
|
||||
if (!readLength) {
|
||||
break;
|
||||
}
|
||||
|
||||
// Attempt to inflate the chunk of data
|
||||
outputData = [decompressor uncompressBytes:inputData length:(NSUInteger)readLength error:&theError];
|
||||
if (theError) {
|
||||
if (err) {
|
||||
*err = theError;
|
||||
}
|
||||
[decompressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
|
||||
// Write the inflated data out to the destination file
|
||||
[outputStream write:(Bytef*)[outputData bytes] maxLength:[outputData length]];
|
||||
|
||||
// Make sure nothing went wrong
|
||||
if ([inputStream streamStatus] == NSStreamStatusError) {
|
||||
if (err) {
|
||||
*err = [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of %@ failed because we were unable to write to the destination data file at %@",sourcePath,destinationPath],NSLocalizedDescriptionKey,[outputStream streamError],NSUnderlyingErrorKey,nil]];
|
||||
}
|
||||
[decompressor closeStream];
|
||||
return NO;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[inputStream close];
|
||||
[outputStream close];
|
||||
|
||||
NSError *error = [decompressor closeStream];
|
||||
if (error) {
|
||||
if (err) {
|
||||
*err = error;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
|
||||
+ (NSError *)inflateErrorWithCode:(int)code
|
||||
{
|
||||
return [NSError errorWithDomain:NetworkRequestErrorDomain code:ASICompressionError userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"Decompression of data failed with code %d",code],NSLocalizedDescriptionKey,nil]];
|
||||
}
|
||||
|
||||
@synthesize streamReady;
|
||||
@end
|
|
@ -1,46 +0,0 @@
|
|||
//
|
||||
// ASIDownloadCache.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 01/05/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ASICacheDelegate.h"
|
||||
|
||||
@interface ASIDownloadCache : NSObject <ASICacheDelegate> {
|
||||
|
||||
// The default cache policy for this cache
|
||||
// Requests that store data in the cache will use this cache policy if their cache policy is set to ASIUseDefaultCachePolicy
|
||||
// Defaults to ASIAskServerIfModifiedWhenStaleCachePolicy
|
||||
ASICachePolicy defaultCachePolicy;
|
||||
|
||||
// The directory in which cached data will be stored
|
||||
// Defaults to a directory called 'ASIHTTPRequestCache' in the temporary directory
|
||||
NSString *storagePath;
|
||||
|
||||
// Mediates access to the cache
|
||||
NSRecursiveLock *accessLock;
|
||||
|
||||
// When YES, the cache will look for cache-control / pragma: no-cache headers, and won't reuse store responses if it finds them
|
||||
BOOL shouldRespectCacheControlHeaders;
|
||||
}
|
||||
|
||||
// Returns a static instance of an ASIDownloadCache
|
||||
// In most circumstances, it will make sense to use this as a global cache, rather than creating your own cache
|
||||
// To make ASIHTTPRequests use it automatically, use [ASIHTTPRequest setDefaultCache:[ASIDownloadCache sharedCache]];
|
||||
+ (id)sharedCache;
|
||||
|
||||
// A helper function that determines if the server has requested data should not be cached by looking at the request's response headers
|
||||
+ (BOOL)serverAllowsResponseCachingForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
// A list of file extensions that we know won't be readable by a webview when accessed locally
|
||||
// If we're asking for a path to cache a particular url and it has one of these extensions, we change it to '.html'
|
||||
+ (NSArray *)fileExtensionsToHandleAsHTML;
|
||||
|
||||
@property (assign, nonatomic) ASICachePolicy defaultCachePolicy;
|
||||
@property (retain, nonatomic) NSString *storagePath;
|
||||
@property (atomic, retain) NSRecursiveLock *accessLock;
|
||||
@property (atomic, assign) BOOL shouldRespectCacheControlHeaders;
|
||||
@end
|
|
@ -1,514 +0,0 @@
|
|||
//
|
||||
// ASIDownloadCache.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 01/05/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIDownloadCache.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
#import <CommonCrypto/CommonHMAC.h>
|
||||
|
||||
static ASIDownloadCache *sharedCache = nil;
|
||||
|
||||
static NSString *sessionCacheFolder = @"SessionStore";
|
||||
static NSString *permanentCacheFolder = @"PermanentStore";
|
||||
static NSArray *fileExtensionsToHandleAsHTML = nil;
|
||||
|
||||
@interface ASIDownloadCache ()
|
||||
+ (NSString *)keyForURL:(NSURL *)url;
|
||||
- (NSString *)pathToFile:(NSString *)file;
|
||||
@end
|
||||
|
||||
@implementation ASIDownloadCache
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self == [ASIDownloadCache class]) {
|
||||
// Obviously this is not an exhaustive list, but hopefully these are the most commonly used and this will 'just work' for the widest range of people
|
||||
// I imagine many web developers probably use url rewriting anyway
|
||||
fileExtensionsToHandleAsHTML = [[NSArray alloc] initWithObjects:@"asp",@"aspx",@"jsp",@"php",@"rb",@"py",@"pl",@"cgi", nil];
|
||||
}
|
||||
}
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
[self setShouldRespectCacheControlHeaders:YES];
|
||||
[self setDefaultCachePolicy:ASIUseDefaultCachePolicy];
|
||||
[self setAccessLock:[[[NSRecursiveLock alloc] init] autorelease]];
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (id)sharedCache
|
||||
{
|
||||
if (!sharedCache) {
|
||||
@synchronized(self) {
|
||||
if (!sharedCache) {
|
||||
sharedCache = [[self alloc] init];
|
||||
[sharedCache setStoragePath:[[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) objectAtIndex:0] stringByAppendingPathComponent:@"ASIHTTPRequestCache"]];
|
||||
}
|
||||
}
|
||||
}
|
||||
return sharedCache;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[storagePath release];
|
||||
[accessLock release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (NSString *)storagePath
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
NSString *p = [[storagePath retain] autorelease];
|
||||
[[self accessLock] unlock];
|
||||
return p;
|
||||
}
|
||||
|
||||
|
||||
- (void)setStoragePath:(NSString *)path
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
[self clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy];
|
||||
[storagePath release];
|
||||
storagePath = [path retain];
|
||||
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
BOOL isDirectory = NO;
|
||||
NSArray *directories = [NSArray arrayWithObjects:path,[path stringByAppendingPathComponent:sessionCacheFolder],[path stringByAppendingPathComponent:permanentCacheFolder],nil];
|
||||
for (NSString *directory in directories) {
|
||||
BOOL exists = [fileManager fileExistsAtPath:directory isDirectory:&isDirectory];
|
||||
if (exists && !isDirectory) {
|
||||
[[self accessLock] unlock];
|
||||
[NSException raise:@"FileExistsAtCachePath" format:@"Cannot create a directory for the cache at '%@', because a file already exists",directory];
|
||||
} else if (!exists) {
|
||||
[fileManager createDirectoryAtPath:directory withIntermediateDirectories:NO attributes:nil error:nil];
|
||||
if (![fileManager fileExistsAtPath:directory]) {
|
||||
[[self accessLock] unlock];
|
||||
[NSException raise:@"FailedToCreateCacheDirectory" format:@"Failed to create a directory for the cache at '%@'",directory];
|
||||
}
|
||||
}
|
||||
}
|
||||
[self clearCachedResponsesForStoragePolicy:ASICacheForSessionDurationCacheStoragePolicy];
|
||||
[[self accessLock] unlock];
|
||||
}
|
||||
|
||||
- (void)updateExpiryForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge
|
||||
{
|
||||
NSString *headerPath = [self pathToStoreCachedResponseHeadersForRequest:request];
|
||||
NSMutableDictionary *cachedHeaders = [NSMutableDictionary dictionaryWithContentsOfFile:headerPath];
|
||||
if (!cachedHeaders) {
|
||||
return;
|
||||
}
|
||||
NSDate *expires = [self expiryDateForRequest:request maxAge:maxAge];
|
||||
if (!expires) {
|
||||
return;
|
||||
}
|
||||
[cachedHeaders setObject:[NSNumber numberWithDouble:[expires timeIntervalSince1970]] forKey:@"X-ASIHTTPRequest-Expires"];
|
||||
[cachedHeaders writeToFile:headerPath atomically:NO];
|
||||
}
|
||||
|
||||
- (NSDate *)expiryDateForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge
|
||||
{
|
||||
return [ASIHTTPRequest expiryDateForRequest:request maxAge:maxAge];
|
||||
}
|
||||
|
||||
- (void)storeResponseForRequest:(ASIHTTPRequest *)request maxAge:(NSTimeInterval)maxAge
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
|
||||
if ([request error] || ![request responseHeaders] || ([request cachePolicy] & ASIDoNotWriteToCacheCachePolicy)) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
|
||||
// We only cache 200/OK or redirect reponses (redirect responses are cached so the cache works better with no internet connection)
|
||||
int responseCode = [request responseStatusCode];
|
||||
if (responseCode != 200 && responseCode != 301 && responseCode != 302 && responseCode != 303 && responseCode != 307) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
|
||||
if ([self shouldRespectCacheControlHeaders] && ![[self class] serverAllowsResponseCachingForRequest:request]) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
|
||||
NSString *headerPath = [self pathToStoreCachedResponseHeadersForRequest:request];
|
||||
NSString *dataPath = [self pathToStoreCachedResponseDataForRequest:request];
|
||||
|
||||
NSMutableDictionary *responseHeaders = [NSMutableDictionary dictionaryWithDictionary:[request responseHeaders]];
|
||||
if ([request isResponseCompressed]) {
|
||||
[responseHeaders removeObjectForKey:@"Content-Encoding"];
|
||||
}
|
||||
|
||||
// Create a special 'X-ASIHTTPRequest-Expires' header
|
||||
// This is what we use for deciding if cached data is current, rather than parsing the expires / max-age headers individually each time
|
||||
// We store this as a timestamp to make reading it easier as NSDateFormatter is quite expensive
|
||||
|
||||
NSDate *expires = [self expiryDateForRequest:request maxAge:maxAge];
|
||||
if (expires) {
|
||||
[responseHeaders setObject:[NSNumber numberWithDouble:[expires timeIntervalSince1970]] forKey:@"X-ASIHTTPRequest-Expires"];
|
||||
}
|
||||
|
||||
// Store the response code in a custom header so we can reuse it later
|
||||
|
||||
// We'll change 304/Not Modified to 200/OK because this is likely to be us updating the cached headers with a conditional GET
|
||||
int statusCode = [request responseStatusCode];
|
||||
if (statusCode == 304) {
|
||||
statusCode = 200;
|
||||
}
|
||||
[responseHeaders setObject:[NSNumber numberWithInt:statusCode] forKey:@"X-ASIHTTPRequest-Response-Status-Code"];
|
||||
|
||||
[responseHeaders writeToFile:headerPath atomically:NO];
|
||||
|
||||
if ([request responseData]) {
|
||||
[[request responseData] writeToFile:dataPath atomically:NO];
|
||||
} else if ([request downloadDestinationPath] && ![[request downloadDestinationPath] isEqualToString:dataPath]) {
|
||||
NSError *error = nil;
|
||||
NSFileManager* manager = [[NSFileManager alloc] init];
|
||||
if ([manager fileExistsAtPath:dataPath]) {
|
||||
[manager removeItemAtPath:dataPath error:&error];
|
||||
}
|
||||
[manager copyItemAtPath:[request downloadDestinationPath] toPath:dataPath error:&error];
|
||||
[manager release];
|
||||
}
|
||||
[[self accessLock] unlock];
|
||||
}
|
||||
|
||||
- (NSDictionary *)cachedResponseHeadersForURL:(NSURL *)url
|
||||
{
|
||||
NSString *path = [self pathToCachedResponseHeadersForURL:url];
|
||||
if (path) {
|
||||
return [NSDictionary dictionaryWithContentsOfFile:path];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSData *)cachedResponseDataForURL:(NSURL *)url
|
||||
{
|
||||
NSString *path = [self pathToCachedResponseDataForURL:url];
|
||||
if (path) {
|
||||
return [NSData dataWithContentsOfFile:path];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
- (NSString *)pathToCachedResponseDataForURL:(NSURL *)url
|
||||
{
|
||||
// Grab the file extension, if there is one. We do this so we can save the cached response with the same file extension - this is important if you want to display locally cached data in a web view
|
||||
NSString *extension = [[url path] pathExtension];
|
||||
|
||||
// If the url doesn't have an extension, we'll add one so a webview can read it when locally cached
|
||||
// If the url has the extension of a common web scripting language, we'll change the extension on the cached path to html for the same reason
|
||||
if (![extension length] || [[[self class] fileExtensionsToHandleAsHTML] containsObject:[extension lowercaseString]]) {
|
||||
extension = @"html";
|
||||
}
|
||||
return [self pathToFile:[[[self class] keyForURL:url] stringByAppendingPathExtension:extension]];
|
||||
}
|
||||
|
||||
+ (NSArray *)fileExtensionsToHandleAsHTML
|
||||
{
|
||||
return fileExtensionsToHandleAsHTML;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *)pathToCachedResponseHeadersForURL:(NSURL *)url
|
||||
{
|
||||
return [self pathToFile:[[[self class] keyForURL:url] stringByAppendingPathExtension:@"cachedheaders"]];
|
||||
}
|
||||
|
||||
- (NSString *)pathToFile:(NSString *)file
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
// Look in the session store
|
||||
NSString *dataPath = [[[self storagePath] stringByAppendingPathComponent:sessionCacheFolder] stringByAppendingPathComponent:file];
|
||||
if ([fileManager fileExistsAtPath:dataPath]) {
|
||||
[[self accessLock] unlock];
|
||||
return dataPath;
|
||||
}
|
||||
// Look in the permanent store
|
||||
dataPath = [[[self storagePath] stringByAppendingPathComponent:permanentCacheFolder] stringByAppendingPathComponent:file];
|
||||
if ([fileManager fileExistsAtPath:dataPath]) {
|
||||
[[self accessLock] unlock];
|
||||
return dataPath;
|
||||
}
|
||||
[[self accessLock] unlock];
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
- (NSString *)pathToStoreCachedResponseDataForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSString *path = [[self storagePath] stringByAppendingPathComponent:([request cacheStoragePolicy] == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)];
|
||||
|
||||
// Grab the file extension, if there is one. We do this so we can save the cached response with the same file extension - this is important if you want to display locally cached data in a web view
|
||||
NSString *extension = [[[request url] path] pathExtension];
|
||||
|
||||
// If the url doesn't have an extension, we'll add one so a webview can read it when locally cached
|
||||
// If the url has the extension of a common web scripting language, we'll change the extension on the cached path to html for the same reason
|
||||
if (![extension length] || [[[self class] fileExtensionsToHandleAsHTML] containsObject:[extension lowercaseString]]) {
|
||||
extension = @"html";
|
||||
}
|
||||
path = [path stringByAppendingPathComponent:[[[self class] keyForURL:[request url]] stringByAppendingPathExtension:extension]];
|
||||
[[self accessLock] unlock];
|
||||
return path;
|
||||
}
|
||||
|
||||
- (NSString *)pathToStoreCachedResponseHeadersForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return nil;
|
||||
}
|
||||
NSString *path = [[self storagePath] stringByAppendingPathComponent:([request cacheStoragePolicy] == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)];
|
||||
path = [path stringByAppendingPathComponent:[[[self class] keyForURL:[request url]] stringByAppendingPathExtension:@"cachedheaders"]];
|
||||
[[self accessLock] unlock];
|
||||
return path;
|
||||
}
|
||||
|
||||
- (void)removeCachedDataForURL:(NSURL *)url
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
NSString *path = [self pathToCachedResponseHeadersForURL:url];
|
||||
if (path) {
|
||||
[fileManager removeItemAtPath:path error:NULL];
|
||||
}
|
||||
|
||||
path = [self pathToCachedResponseDataForURL:url];
|
||||
if (path) {
|
||||
[fileManager removeItemAtPath:path error:NULL];
|
||||
}
|
||||
[[self accessLock] unlock];
|
||||
}
|
||||
|
||||
- (void)removeCachedDataForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
[self removeCachedDataForURL:[request url]];
|
||||
}
|
||||
|
||||
- (BOOL)isCachedDataCurrentForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return NO;
|
||||
}
|
||||
NSDictionary *cachedHeaders = [self cachedResponseHeadersForURL:[request url]];
|
||||
if (!cachedHeaders) {
|
||||
[[self accessLock] unlock];
|
||||
return NO;
|
||||
}
|
||||
NSString *dataPath = [self pathToCachedResponseDataForURL:[request url]];
|
||||
if (!dataPath) {
|
||||
[[self accessLock] unlock];
|
||||
return NO;
|
||||
}
|
||||
|
||||
// New content is not different
|
||||
if ([request responseStatusCode] == 304) {
|
||||
[[self accessLock] unlock];
|
||||
return YES;
|
||||
}
|
||||
|
||||
// If we already have response headers for this request, check to see if the new content is different
|
||||
// We check [request complete] so that we don't end up comparing response headers from a redirection with these
|
||||
if ([request responseHeaders] && [request complete]) {
|
||||
|
||||
// If the Etag or Last-Modified date are different from the one we have, we'll have to fetch this resource again
|
||||
NSArray *headersToCompare = [NSArray arrayWithObjects:@"Etag",@"Last-Modified",nil];
|
||||
for (NSString *header in headersToCompare) {
|
||||
if (![[[request responseHeaders] objectForKey:header] isEqualToString:[cachedHeaders objectForKey:header]]) {
|
||||
[[self accessLock] unlock];
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ([self shouldRespectCacheControlHeaders]) {
|
||||
|
||||
// Look for X-ASIHTTPRequest-Expires header to see if the content is out of date
|
||||
NSNumber *expires = [cachedHeaders objectForKey:@"X-ASIHTTPRequest-Expires"];
|
||||
if (expires) {
|
||||
if ([[NSDate dateWithTimeIntervalSince1970:[expires doubleValue]] timeIntervalSinceNow] >= 0) {
|
||||
[[self accessLock] unlock];
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
|
||||
// No explicit expiration time sent by the server
|
||||
[[self accessLock] unlock];
|
||||
return NO;
|
||||
}
|
||||
|
||||
|
||||
[[self accessLock] unlock];
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (ASICachePolicy)defaultCachePolicy
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
ASICachePolicy cp = defaultCachePolicy;
|
||||
[[self accessLock] unlock];
|
||||
return cp;
|
||||
}
|
||||
|
||||
|
||||
- (void)setDefaultCachePolicy:(ASICachePolicy)cachePolicy
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (!cachePolicy) {
|
||||
defaultCachePolicy = ASIAskServerIfModifiedWhenStaleCachePolicy;
|
||||
} else {
|
||||
defaultCachePolicy = cachePolicy;
|
||||
}
|
||||
[[self accessLock] unlock];
|
||||
}
|
||||
|
||||
- (void)clearCachedResponsesForStoragePolicy:(ASICacheStoragePolicy)storagePolicy
|
||||
{
|
||||
[[self accessLock] lock];
|
||||
if (![self storagePath]) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
NSString *path = [[self storagePath] stringByAppendingPathComponent:(storagePolicy == ASICacheForSessionDurationCacheStoragePolicy ? sessionCacheFolder : permanentCacheFolder)];
|
||||
|
||||
NSFileManager *fileManager = [[[NSFileManager alloc] init] autorelease];
|
||||
|
||||
BOOL isDirectory = NO;
|
||||
BOOL exists = [fileManager fileExistsAtPath:path isDirectory:&isDirectory];
|
||||
if (!exists || !isDirectory) {
|
||||
[[self accessLock] unlock];
|
||||
return;
|
||||
}
|
||||
NSError *error = nil;
|
||||
NSArray *cacheFiles = [fileManager contentsOfDirectoryAtPath:path error:&error];
|
||||
if (error) {
|
||||
[[self accessLock] unlock];
|
||||
[NSException raise:@"FailedToTraverseCacheDirectory" format:@"Listing cache directory failed at path '%@'",path];
|
||||
}
|
||||
for (NSString *file in cacheFiles) {
|
||||
[fileManager removeItemAtPath:[path stringByAppendingPathComponent:file] error:&error];
|
||||
if (error) {
|
||||
[[self accessLock] unlock];
|
||||
[NSException raise:@"FailedToRemoveCacheFile" format:@"Failed to remove cached data at path '%@'",path];
|
||||
}
|
||||
}
|
||||
[[self accessLock] unlock];
|
||||
}
|
||||
|
||||
+ (BOOL)serverAllowsResponseCachingForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
NSString *cacheControl = [[[request responseHeaders] objectForKey:@"Cache-Control"] lowercaseString];
|
||||
if (cacheControl) {
|
||||
if ([cacheControl isEqualToString:@"no-cache"] || [cacheControl isEqualToString:@"no-store"]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
NSString *pragma = [[[request responseHeaders] objectForKey:@"Pragma"] lowercaseString];
|
||||
if (pragma) {
|
||||
if ([pragma isEqualToString:@"no-cache"]) {
|
||||
return NO;
|
||||
}
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
+ (NSString *)keyForURL:(NSURL *)url
|
||||
{
|
||||
NSString *urlString = [url absoluteString];
|
||||
if ([urlString length] == 0) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
// Strip trailing slashes so http://allseeing-i.com/ASIHTTPRequest/ is cached the same as http://allseeing-i.com/ASIHTTPRequest
|
||||
if ([[urlString substringFromIndex:[urlString length]-1] isEqualToString:@"/"]) {
|
||||
urlString = [urlString substringToIndex:[urlString length]-1];
|
||||
}
|
||||
|
||||
// Borrowed from: http://stackoverflow.com/questions/652300/using-md5-hash-on-a-string-in-cocoa
|
||||
const char *cStr = [urlString UTF8String];
|
||||
unsigned char result[16];
|
||||
CC_MD5(cStr, (CC_LONG)strlen(cStr), result);
|
||||
return [NSString stringWithFormat:@"%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X%02X",result[0], result[1], result[2], result[3], result[4], result[5], result[6], result[7],result[8], result[9], result[10], result[11],result[12], result[13], result[14], result[15]];
|
||||
}
|
||||
|
||||
- (BOOL)canUseCachedDataForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
// Ensure the request is allowed to read from the cache
|
||||
if ([request cachePolicy] & ASIDoNotReadFromCacheCachePolicy) {
|
||||
return NO;
|
||||
|
||||
// If we don't want to load the request whatever happens, always pretend we have cached data even if we don't
|
||||
} else if ([request cachePolicy] & ASIDontLoadCachePolicy) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
NSDictionary *headers = [self cachedResponseHeadersForURL:[request url]];
|
||||
if (!headers) {
|
||||
return NO;
|
||||
}
|
||||
NSString *dataPath = [self pathToCachedResponseDataForURL:[request url]];
|
||||
if (!dataPath) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
// If we get here, we have cached data
|
||||
|
||||
// If we have cached data, we can use it
|
||||
if ([request cachePolicy] & ASIOnlyLoadIfNotCachedCachePolicy) {
|
||||
return YES;
|
||||
|
||||
// If we want to fallback to the cache after an error
|
||||
} else if ([request complete] && [request cachePolicy] & ASIFallbackToCacheIfLoadFailsCachePolicy) {
|
||||
return YES;
|
||||
|
||||
// If we have cached data that is current, we can use it
|
||||
} else if ([request cachePolicy] & ASIAskServerIfModifiedWhenStaleCachePolicy) {
|
||||
if ([self isCachedDataCurrentForRequest:request]) {
|
||||
return YES;
|
||||
}
|
||||
|
||||
// If we've got headers from a conditional GET and the cached data is still current, we can use it
|
||||
} else if ([request cachePolicy] & ASIAskServerIfModifiedCachePolicy) {
|
||||
if (![request responseHeaders]) {
|
||||
return NO;
|
||||
} else if ([self isCachedDataCurrentForRequest:request]) {
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
|
||||
@synthesize storagePath;
|
||||
@synthesize defaultCachePolicy;
|
||||
@synthesize accessLock;
|
||||
@synthesize shouldRespectCacheControlHeaders;
|
||||
@end
|
|
@ -1,75 +0,0 @@
|
|||
//
|
||||
// ASIFormDataRequest.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 07/11/2008.
|
||||
// Copyright 2008-2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ASIHTTPRequest.h"
|
||||
#import "ASIHTTPRequestConfig.h"
|
||||
|
||||
typedef enum _ASIPostFormat {
|
||||
ASIMultipartFormDataPostFormat = 0,
|
||||
ASIURLEncodedPostFormat = 1
|
||||
|
||||
} ASIPostFormat;
|
||||
|
||||
@interface ASIFormDataRequest : ASIHTTPRequest <NSCopying> {
|
||||
|
||||
// Parameters that will be POSTed to the url
|
||||
NSMutableArray *postData;
|
||||
|
||||
// Files that will be POSTed to the url
|
||||
NSMutableArray *fileData;
|
||||
|
||||
ASIPostFormat postFormat;
|
||||
|
||||
NSStringEncoding stringEncoding;
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
// Will store a string version of the request body that will be printed to the console when ASIHTTPREQUEST_DEBUG is set in GCC_PREPROCESSOR_DEFINITIONS
|
||||
NSString *debugBodyString;
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#pragma mark utilities
|
||||
- (NSString*)encodeURL:(NSString *)string;
|
||||
|
||||
#pragma mark setup request
|
||||
|
||||
// Add a POST variable to the request
|
||||
- (void)addPostValue:(id <NSObject>)value forKey:(NSString *)key;
|
||||
|
||||
// Set a POST variable for this request, clearing any others with the same key
|
||||
- (void)setPostValue:(id <NSObject>)value forKey:(NSString *)key;
|
||||
|
||||
// Add the contents of a local file to the request
|
||||
- (void)addFile:(NSString *)filePath forKey:(NSString *)key;
|
||||
|
||||
// Same as above, but you can specify the content-type and file name
|
||||
- (void)addFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
|
||||
|
||||
// Add the contents of a local file to the request, clearing any others with the same key
|
||||
- (void)setFile:(NSString *)filePath forKey:(NSString *)key;
|
||||
|
||||
// Same as above, but you can specify the content-type and file name
|
||||
- (void)setFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
|
||||
|
||||
// Add the contents of an NSData object to the request
|
||||
- (void)addData:(NSData *)data forKey:(NSString *)key;
|
||||
|
||||
// Same as above, but you can specify the content-type and file name
|
||||
- (void)addData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
|
||||
|
||||
// Add the contents of an NSData object to the request, clearing any others with the same key
|
||||
- (void)setData:(NSData *)data forKey:(NSString *)key;
|
||||
|
||||
// Same as above, but you can specify the content-type and file name
|
||||
- (void)setData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key;
|
||||
|
||||
@property (atomic, assign) ASIPostFormat postFormat;
|
||||
@property (atomic, assign) NSStringEncoding stringEncoding;
|
||||
@end
|
|
@ -1,362 +0,0 @@
|
|||
//
|
||||
// ASIFormDataRequest.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 07/11/2008.
|
||||
// Copyright 2008-2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIFormDataRequest.h"
|
||||
|
||||
|
||||
// Private stuff
|
||||
@interface ASIFormDataRequest ()
|
||||
- (void)buildMultipartFormDataPostBody;
|
||||
- (void)buildURLEncodedPostBody;
|
||||
- (void)appendPostString:(NSString *)string;
|
||||
|
||||
@property (atomic, retain) NSMutableArray *postData;
|
||||
@property (atomic, retain) NSMutableArray *fileData;
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
- (void)addToDebugBody:(NSString *)string;
|
||||
@property (retain, nonatomic) NSString *debugBodyString;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
@implementation ASIFormDataRequest
|
||||
|
||||
#pragma mark utilities
|
||||
- (NSString*)encodeURL:(NSString *)string
|
||||
{
|
||||
NSString *newString = [NSMakeCollectable(CFURLCreateStringByAddingPercentEscapes(kCFAllocatorDefault, (CFStringRef)string, NULL, CFSTR(":/?#[]@!$ &'()*+,;=\"<>%{}|\\^~`"), CFStringConvertNSStringEncodingToEncoding([self stringEncoding]))) autorelease];
|
||||
if (newString) {
|
||||
return newString;
|
||||
}
|
||||
return @"";
|
||||
}
|
||||
|
||||
#pragma mark init / dealloc
|
||||
|
||||
+ (id)requestWithURL:(NSURL *)newURL
|
||||
{
|
||||
return [[[self alloc] initWithURL:newURL] autorelease];
|
||||
}
|
||||
|
||||
- (id)initWithURL:(NSURL *)newURL
|
||||
{
|
||||
self = [super initWithURL:newURL];
|
||||
[self setPostFormat:ASIURLEncodedPostFormat];
|
||||
[self setStringEncoding:NSUTF8StringEncoding];
|
||||
[self setRequestMethod:@"POST"];
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[debugBodyString release];
|
||||
#endif
|
||||
|
||||
[postData release];
|
||||
[fileData release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
#pragma mark setup request
|
||||
|
||||
- (void)addPostValue:(id <NSObject>)value forKey:(NSString *)key
|
||||
{
|
||||
if (!key) {
|
||||
return;
|
||||
}
|
||||
if (![self postData]) {
|
||||
[self setPostData:[NSMutableArray array]];
|
||||
}
|
||||
NSMutableDictionary *keyValuePair = [NSMutableDictionary dictionaryWithCapacity:2];
|
||||
[keyValuePair setValue:key forKey:@"key"];
|
||||
[keyValuePair setValue:[value description] forKey:@"value"];
|
||||
[[self postData] addObject:keyValuePair];
|
||||
}
|
||||
|
||||
- (void)setPostValue:(id <NSObject>)value forKey:(NSString *)key
|
||||
{
|
||||
// Remove any existing value
|
||||
NSUInteger i;
|
||||
for (i=0; i<[[self postData] count]; i++) {
|
||||
NSDictionary *val = [[self postData] objectAtIndex:i];
|
||||
if ([[val objectForKey:@"key"] isEqualToString:key]) {
|
||||
[[self postData] removeObjectAtIndex:i];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
[self addPostValue:value forKey:key];
|
||||
}
|
||||
|
||||
|
||||
- (void)addFile:(NSString *)filePath forKey:(NSString *)key
|
||||
{
|
||||
[self addFile:filePath withFileName:nil andContentType:nil forKey:key];
|
||||
}
|
||||
|
||||
- (void)addFile:(NSString *)filePath withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key
|
||||
{
|
||||
BOOL isDirectory = NO;
|
||||
BOOL fileExists = [[[[NSFileManager alloc] init] autorelease] fileExistsAtPath:filePath isDirectory:&isDirectory];
|
||||
if (!fileExists || isDirectory) {
|
||||
[self failWithError:[NSError errorWithDomain:NetworkRequestErrorDomain code:ASIInternalErrorWhileBuildingRequestType userInfo:[NSDictionary dictionaryWithObjectsAndKeys:[NSString stringWithFormat:@"No file exists at %@",filePath],NSLocalizedDescriptionKey,nil]]];
|
||||
}
|
||||
|
||||
// If the caller didn't specify a custom file name, we'll use the file name of the file we were passed
|
||||
if (!fileName) {
|
||||
fileName = [filePath lastPathComponent];
|
||||
}
|
||||
|
||||
// If we were given the path to a file, and the user didn't specify a mime type, we can detect it from the file extension
|
||||
if (!contentType) {
|
||||
contentType = [ASIHTTPRequest mimeTypeForFileAtPath:filePath];
|
||||
}
|
||||
[self addData:filePath withFileName:fileName andContentType:contentType forKey:key];
|
||||
}
|
||||
|
||||
- (void)setFile:(NSString *)filePath forKey:(NSString *)key
|
||||
{
|
||||
[self setFile:filePath withFileName:nil andContentType:nil forKey:key];
|
||||
}
|
||||
|
||||
- (void)setFile:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key
|
||||
{
|
||||
// Remove any existing value
|
||||
NSUInteger i;
|
||||
for (i=0; i<[[self fileData] count]; i++) {
|
||||
NSDictionary *val = [[self fileData] objectAtIndex:i];
|
||||
if ([[val objectForKey:@"key"] isEqualToString:key]) {
|
||||
[[self fileData] removeObjectAtIndex:i];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
[self addFile:data withFileName:fileName andContentType:contentType forKey:key];
|
||||
}
|
||||
|
||||
- (void)addData:(NSData *)data forKey:(NSString *)key
|
||||
{
|
||||
[self addData:data withFileName:@"file" andContentType:nil forKey:key];
|
||||
}
|
||||
|
||||
- (void)addData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key
|
||||
{
|
||||
if (![self fileData]) {
|
||||
[self setFileData:[NSMutableArray array]];
|
||||
}
|
||||
if (!contentType) {
|
||||
contentType = @"application/octet-stream";
|
||||
}
|
||||
|
||||
NSMutableDictionary *fileInfo = [NSMutableDictionary dictionaryWithCapacity:4];
|
||||
[fileInfo setValue:key forKey:@"key"];
|
||||
[fileInfo setValue:fileName forKey:@"fileName"];
|
||||
[fileInfo setValue:contentType forKey:@"contentType"];
|
||||
[fileInfo setValue:data forKey:@"data"];
|
||||
|
||||
[[self fileData] addObject:fileInfo];
|
||||
}
|
||||
|
||||
- (void)setData:(NSData *)data forKey:(NSString *)key
|
||||
{
|
||||
[self setData:data withFileName:@"file" andContentType:nil forKey:key];
|
||||
}
|
||||
|
||||
- (void)setData:(id)data withFileName:(NSString *)fileName andContentType:(NSString *)contentType forKey:(NSString *)key
|
||||
{
|
||||
// Remove any existing value
|
||||
NSUInteger i;
|
||||
for (i=0; i<[[self fileData] count]; i++) {
|
||||
NSDictionary *val = [[self fileData] objectAtIndex:i];
|
||||
if ([[val objectForKey:@"key"] isEqualToString:key]) {
|
||||
[[self fileData] removeObjectAtIndex:i];
|
||||
i--;
|
||||
}
|
||||
}
|
||||
[self addData:data withFileName:fileName andContentType:contentType forKey:key];
|
||||
}
|
||||
|
||||
- (void)buildPostBody
|
||||
{
|
||||
if ([self haveBuiltPostBody]) {
|
||||
return;
|
||||
}
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self setDebugBodyString:@""];
|
||||
#endif
|
||||
|
||||
if (![self postData] && ![self fileData]) {
|
||||
[super buildPostBody];
|
||||
return;
|
||||
}
|
||||
if ([[self fileData] count] > 0) {
|
||||
[self setShouldStreamPostDataFromDisk:YES];
|
||||
}
|
||||
|
||||
if ([self postFormat] == ASIURLEncodedPostFormat) {
|
||||
[self buildURLEncodedPostBody];
|
||||
} else {
|
||||
[self buildMultipartFormDataPostBody];
|
||||
}
|
||||
|
||||
[super buildPostBody];
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
ASI_DEBUG_LOG(@"%@",[self debugBodyString]);
|
||||
[self setDebugBodyString:nil];
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
- (void)buildMultipartFormDataPostBody
|
||||
{
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self addToDebugBody:@"\r\n==== Building a multipart/form-data body ====\r\n"];
|
||||
#endif
|
||||
|
||||
NSString *charset = (NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding([self stringEncoding]));
|
||||
|
||||
// We don't bother to check if post data contains the boundary, since it's pretty unlikely that it does.
|
||||
CFUUIDRef uuid = CFUUIDCreate(nil);
|
||||
NSString *uuidString = [(NSString*)CFUUIDCreateString(nil, uuid) autorelease];
|
||||
CFRelease(uuid);
|
||||
NSString *stringBoundary = [NSString stringWithFormat:@"0xKhTmLbOuNdArY-%@",uuidString];
|
||||
|
||||
[self addRequestHeader:@"Content-Type" value:[NSString stringWithFormat:@"multipart/form-data; charset=%@; boundary=%@", charset, stringBoundary]];
|
||||
|
||||
[self appendPostString:[NSString stringWithFormat:@"--%@\r\n",stringBoundary]];
|
||||
|
||||
// Adds post data
|
||||
NSString *endItemBoundary = [NSString stringWithFormat:@"\r\n--%@\r\n",stringBoundary];
|
||||
NSUInteger i=0;
|
||||
for (NSDictionary *val in [self postData]) {
|
||||
[self appendPostString:[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"\r\n\r\n",[val objectForKey:@"key"]]];
|
||||
[self appendPostString:[val objectForKey:@"value"]];
|
||||
i++;
|
||||
if (i != [[self postData] count] || [[self fileData] count] > 0) { //Only add the boundary if this is not the last item in the post body
|
||||
[self appendPostString:endItemBoundary];
|
||||
}
|
||||
}
|
||||
|
||||
// Adds files to upload
|
||||
i=0;
|
||||
for (NSDictionary *val in [self fileData]) {
|
||||
|
||||
[self appendPostString:[NSString stringWithFormat:@"Content-Disposition: form-data; name=\"%@\"; filename=\"%@\"\r\n", [val objectForKey:@"key"], [val objectForKey:@"fileName"]]];
|
||||
[self appendPostString:[NSString stringWithFormat:@"Content-Type: %@\r\n\r\n", [val objectForKey:@"contentType"]]];
|
||||
|
||||
id data = [val objectForKey:@"data"];
|
||||
if ([data isKindOfClass:[NSString class]]) {
|
||||
[self appendPostDataFromFile:data];
|
||||
} else {
|
||||
[self appendPostData:data];
|
||||
}
|
||||
i++;
|
||||
// Only add the boundary if this is not the last item in the post body
|
||||
if (i != [[self fileData] count]) {
|
||||
[self appendPostString:endItemBoundary];
|
||||
}
|
||||
}
|
||||
|
||||
[self appendPostString:[NSString stringWithFormat:@"\r\n--%@--\r\n",stringBoundary]];
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self addToDebugBody:@"==== End of multipart/form-data body ====\r\n"];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)buildURLEncodedPostBody
|
||||
{
|
||||
|
||||
// We can't post binary data using application/x-www-form-urlencoded
|
||||
if ([[self fileData] count] > 0) {
|
||||
[self setPostFormat:ASIMultipartFormDataPostFormat];
|
||||
[self buildMultipartFormDataPostBody];
|
||||
return;
|
||||
}
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self addToDebugBody:@"\r\n==== Building an application/x-www-form-urlencoded body ====\r\n"];
|
||||
#endif
|
||||
|
||||
|
||||
NSString *charset = (NSString *)CFStringConvertEncodingToIANACharSetName(CFStringConvertNSStringEncodingToEncoding([self stringEncoding]));
|
||||
|
||||
[self addRequestHeader:@"Content-Type" value:[NSString stringWithFormat:@"application/x-www-form-urlencoded; charset=%@",charset]];
|
||||
|
||||
|
||||
NSUInteger i=0;
|
||||
NSUInteger count = [[self postData] count]-1;
|
||||
for (NSDictionary *val in [self postData]) {
|
||||
NSString *data = [NSString stringWithFormat:@"%@=%@%@", [self encodeURL:[val objectForKey:@"key"]], [self encodeURL:[val objectForKey:@"value"]],(i<count ? @"&" : @"")];
|
||||
[self appendPostString:data];
|
||||
i++;
|
||||
}
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self addToDebugBody:@"\r\n==== End of application/x-www-form-urlencoded body ====\r\n"];
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)appendPostString:(NSString *)string
|
||||
{
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
[self addToDebugBody:string];
|
||||
#endif
|
||||
[super appendPostData:[string dataUsingEncoding:[self stringEncoding]]];
|
||||
}
|
||||
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
- (void)appendPostData:(NSData *)data
|
||||
{
|
||||
[self addToDebugBody:[NSString stringWithFormat:@"[%lu bytes of data]",(unsigned long)[data length]]];
|
||||
[super appendPostData:data];
|
||||
}
|
||||
|
||||
- (void)appendPostDataFromFile:(NSString *)file
|
||||
{
|
||||
NSError *err = nil;
|
||||
unsigned long long fileSize = [[[[[[NSFileManager alloc] init] autorelease] attributesOfItemAtPath:file error:&err] objectForKey:NSFileSize] unsignedLongLongValue];
|
||||
if (err) {
|
||||
[self addToDebugBody:[NSString stringWithFormat:@"[Error: Failed to obtain the size of the file at '%@']",file]];
|
||||
} else {
|
||||
[self addToDebugBody:[NSString stringWithFormat:@"[%llu bytes of data from file '%@']",fileSize,file]];
|
||||
}
|
||||
|
||||
[super appendPostDataFromFile:file];
|
||||
}
|
||||
|
||||
- (void)addToDebugBody:(NSString *)string
|
||||
{
|
||||
if (string) {
|
||||
[self setDebugBodyString:[[self debugBodyString] stringByAppendingString:string]];
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#pragma mark NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ASIFormDataRequest *newRequest = [super copyWithZone:zone];
|
||||
[newRequest setPostData:[[[self postData] mutableCopyWithZone:zone] autorelease]];
|
||||
[newRequest setFileData:[[[self fileData] mutableCopyWithZone:zone] autorelease]];
|
||||
[newRequest setPostFormat:[self postFormat]];
|
||||
[newRequest setStringEncoding:[self stringEncoding]];
|
||||
[newRequest setRequestMethod:[self requestMethod]];
|
||||
return newRequest;
|
||||
}
|
||||
|
||||
@synthesize postData;
|
||||
@synthesize fileData;
|
||||
@synthesize postFormat;
|
||||
@synthesize stringEncoding;
|
||||
#if DEBUG_FORM_DATA_REQUEST
|
||||
@synthesize debugBodyString;
|
||||
#endif
|
||||
@end
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
|
@ -1,43 +0,0 @@
|
|||
//
|
||||
// ASIHTTPRequestConfig.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 14/12/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
|
||||
// ======
|
||||
// Debug output configuration options
|
||||
// ======
|
||||
|
||||
// If defined will use the specified function for debug logging
|
||||
// Otherwise use NSLog
|
||||
#ifndef ASI_DEBUG_LOG
|
||||
#define ASI_DEBUG_LOG NSLog
|
||||
#endif
|
||||
|
||||
// When set to 1 ASIHTTPRequests will print information about what a request is doing
|
||||
#ifndef DEBUG_REQUEST_STATUS
|
||||
#define DEBUG_REQUEST_STATUS 0
|
||||
#endif
|
||||
|
||||
// When set to 1, ASIFormDataRequests will print information about the request body to the console
|
||||
#ifndef DEBUG_FORM_DATA_REQUEST
|
||||
#define DEBUG_FORM_DATA_REQUEST 0
|
||||
#endif
|
||||
|
||||
// When set to 1, ASIHTTPRequests will print information about bandwidth throttling to the console
|
||||
#ifndef DEBUG_THROTTLING
|
||||
#define DEBUG_THROTTLING 0
|
||||
#endif
|
||||
|
||||
// When set to 1, ASIHTTPRequests will print information about persistent connections to the console
|
||||
#ifndef DEBUG_PERSISTENT_CONNECTIONS
|
||||
#define DEBUG_PERSISTENT_CONNECTIONS 0
|
||||
#endif
|
||||
|
||||
// When set to 1, ASIHTTPRequests will print information about HTTP authentication (Basic, Digest or NTLM) to the console
|
||||
#ifndef DEBUG_HTTP_AUTHENTICATION
|
||||
#define DEBUG_HTTP_AUTHENTICATION 0
|
||||
#endif
|
|
@ -1,35 +0,0 @@
|
|||
//
|
||||
// ASIHTTPRequestDelegate.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 13/04/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
@class ASIHTTPRequest;
|
||||
|
||||
@protocol ASIHTTPRequestDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
// These are the default delegate methods for request status
|
||||
// You can use different ones by setting didStartSelector / didFinishSelector / didFailSelector
|
||||
- (void)requestStarted:(ASIHTTPRequest *)request;
|
||||
- (void)request:(ASIHTTPRequest *)request didReceiveResponseHeaders:(NSDictionary *)responseHeaders;
|
||||
- (void)request:(ASIHTTPRequest *)request willRedirectToURL:(NSURL *)newURL;
|
||||
- (void)requestFinished:(ASIHTTPRequest *)request;
|
||||
- (void)requestFailed:(ASIHTTPRequest *)request;
|
||||
- (void)requestRedirected:(ASIHTTPRequest *)request;
|
||||
|
||||
// When a delegate implements this method, it is expected to process all incoming data itself
|
||||
// This means that responseData / responseString / downloadDestinationPath etc are ignored
|
||||
// You can have the request call a different method by setting didReceiveDataSelector
|
||||
- (void)request:(ASIHTTPRequest *)request didReceiveData:(NSData *)data;
|
||||
|
||||
// If a delegate implements one of these, it will be asked to supply credentials when none are available
|
||||
// The delegate can then either restart the request ([request retryUsingSuppliedCredentials]) once credentials have been set
|
||||
// or cancel it ([request cancelAuthentication])
|
||||
- (void)authenticationNeededForRequest:(ASIHTTPRequest *)request;
|
||||
- (void)proxyAuthenticationNeededForRequest:(ASIHTTPRequest *)request;
|
||||
|
||||
@end
|
|
@ -1,26 +0,0 @@
|
|||
//
|
||||
// ASIInputStream.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 10/08/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
@class ASIHTTPRequest;
|
||||
|
||||
// This is a wrapper for NSInputStream that pretends to be an NSInputStream itself
|
||||
// Subclassing NSInputStream seems to be tricky, and may involve overriding undocumented methods, so we'll cheat instead.
|
||||
// It is used by ASIHTTPRequest whenever we have a request body, and handles measuring and throttling the bandwidth used for uploading
|
||||
|
||||
@interface ASIInputStream : NSObject {
|
||||
NSInputStream *stream;
|
||||
ASIHTTPRequest *request;
|
||||
}
|
||||
+ (id)inputStreamWithFileAtPath:(NSString *)path request:(ASIHTTPRequest *)request;
|
||||
+ (id)inputStreamWithData:(NSData *)data request:(ASIHTTPRequest *)request;
|
||||
|
||||
@property (retain, nonatomic) NSInputStream *stream;
|
||||
@property (assign, nonatomic) ASIHTTPRequest *request;
|
||||
@end
|
|
@ -1,138 +0,0 @@
|
|||
//
|
||||
// ASIInputStream.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 10/08/2009.
|
||||
// Copyright 2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASIInputStream.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
|
||||
// Used to ensure only one request can read data at once
|
||||
static NSLock *readLock = nil;
|
||||
|
||||
@implementation ASIInputStream
|
||||
|
||||
+ (void)initialize
|
||||
{
|
||||
if (self == [ASIInputStream class]) {
|
||||
readLock = [[NSLock alloc] init];
|
||||
}
|
||||
}
|
||||
|
||||
+ (id)inputStreamWithFileAtPath:(NSString *)path request:(ASIHTTPRequest *)theRequest
|
||||
{
|
||||
ASIInputStream *theStream = [[[self alloc] init] autorelease];
|
||||
[theStream setRequest:theRequest];
|
||||
[theStream setStream:[NSInputStream inputStreamWithFileAtPath:path]];
|
||||
return theStream;
|
||||
}
|
||||
|
||||
+ (id)inputStreamWithData:(NSData *)data request:(ASIHTTPRequest *)theRequest
|
||||
{
|
||||
ASIInputStream *theStream = [[[self alloc] init] autorelease];
|
||||
[theStream setRequest:theRequest];
|
||||
[theStream setStream:[NSInputStream inputStreamWithData:data]];
|
||||
return theStream;
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
[stream release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
// Called when CFNetwork wants to read more of our request body
|
||||
// When throttling is on, we ask ASIHTTPRequest for the maximum amount of data we can read
|
||||
- (NSInteger)read:(uint8_t *)buffer maxLength:(NSUInteger)len
|
||||
{
|
||||
[readLock lock];
|
||||
unsigned long toRead = len;
|
||||
if ([ASIHTTPRequest isBandwidthThrottled]) {
|
||||
toRead = [ASIHTTPRequest maxUploadReadLength];
|
||||
if (toRead > len) {
|
||||
toRead = len;
|
||||
} else if (toRead == 0) {
|
||||
toRead = 1;
|
||||
}
|
||||
[request performThrottling];
|
||||
}
|
||||
[readLock unlock];
|
||||
NSInteger rv = [stream read:buffer maxLength:toRead];
|
||||
if (rv > 0)
|
||||
[ASIHTTPRequest incrementBandwidthUsedInLastSecond:(NSUInteger)rv];
|
||||
return rv;
|
||||
}
|
||||
|
||||
/*
|
||||
* Implement NSInputStream mandatory methods to make sure they are implemented
|
||||
* (necessary for MacRuby for example) and avoid the overhead of method
|
||||
* forwarding for these common methods.
|
||||
*/
|
||||
- (void)open
|
||||
{
|
||||
[stream open];
|
||||
}
|
||||
|
||||
- (void)close
|
||||
{
|
||||
[stream close];
|
||||
}
|
||||
|
||||
- (id)delegate
|
||||
{
|
||||
return [stream delegate];
|
||||
}
|
||||
|
||||
- (void)setDelegate:(id)delegate
|
||||
{
|
||||
[stream setDelegate:delegate];
|
||||
}
|
||||
|
||||
- (void)scheduleInRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode
|
||||
{
|
||||
[stream scheduleInRunLoop:aRunLoop forMode:mode];
|
||||
}
|
||||
|
||||
- (void)removeFromRunLoop:(NSRunLoop *)aRunLoop forMode:(NSString *)mode
|
||||
{
|
||||
[stream removeFromRunLoop:aRunLoop forMode:mode];
|
||||
}
|
||||
|
||||
- (id)propertyForKey:(NSString *)key
|
||||
{
|
||||
return [stream propertyForKey:key];
|
||||
}
|
||||
|
||||
- (BOOL)setProperty:(id)property forKey:(NSString *)key
|
||||
{
|
||||
return [stream setProperty:property forKey:key];
|
||||
}
|
||||
|
||||
- (NSStreamStatus)streamStatus
|
||||
{
|
||||
return [stream streamStatus];
|
||||
}
|
||||
|
||||
- (NSError *)streamError
|
||||
{
|
||||
return [stream streamError];
|
||||
}
|
||||
|
||||
// If we get asked to perform a method we don't have (probably internal ones),
|
||||
// we'll just forward the message to our stream
|
||||
|
||||
- (NSMethodSignature *)methodSignatureForSelector:(SEL)aSelector
|
||||
{
|
||||
return [stream methodSignatureForSelector:aSelector];
|
||||
}
|
||||
|
||||
- (void)forwardInvocation:(NSInvocation *)anInvocation
|
||||
{
|
||||
[anInvocation invokeWithTarget:stream];
|
||||
}
|
||||
|
||||
@synthesize stream;
|
||||
@synthesize request;
|
||||
@end
|
|
@ -1,108 +0,0 @@
|
|||
//
|
||||
// ASINetworkQueue.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 07/11/2008.
|
||||
// Copyright 2008-2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import "ASIHTTPRequestDelegate.h"
|
||||
#import "ASIProgressDelegate.h"
|
||||
|
||||
@interface ASINetworkQueue : NSOperationQueue <ASIProgressDelegate, ASIHTTPRequestDelegate, NSCopying> {
|
||||
|
||||
// Delegate will get didFail + didFinish messages (if set)
|
||||
id delegate;
|
||||
|
||||
// Will be called when a request starts with the request as the argument
|
||||
SEL requestDidStartSelector;
|
||||
|
||||
// Will be called when a request receives response headers
|
||||
// Should take the form request:didRecieveResponseHeaders:, where the first argument is the request, and the second the headers dictionary
|
||||
SEL requestDidReceiveResponseHeadersSelector;
|
||||
|
||||
// Will be called when a request is about to redirect
|
||||
// Should take the form request:willRedirectToURL:, where the first argument is the request, and the second the new url
|
||||
SEL requestWillRedirectSelector;
|
||||
|
||||
// Will be called when a request completes with the request as the argument
|
||||
SEL requestDidFinishSelector;
|
||||
|
||||
// Will be called when a request fails with the request as the argument
|
||||
SEL requestDidFailSelector;
|
||||
|
||||
// Will be called when the queue finishes with the queue as the argument
|
||||
SEL queueDidFinishSelector;
|
||||
|
||||
// Upload progress indicator, probably an NSProgressIndicator or UIProgressView
|
||||
id uploadProgressDelegate;
|
||||
|
||||
// Total amount uploaded so far for all requests in this queue
|
||||
unsigned long long bytesUploadedSoFar;
|
||||
|
||||
// Total amount to be uploaded for all requests in this queue - requests add to this figure as they work out how much data they have to transmit
|
||||
unsigned long long totalBytesToUpload;
|
||||
|
||||
// Download progress indicator, probably an NSProgressIndicator or UIProgressView
|
||||
id downloadProgressDelegate;
|
||||
|
||||
// Total amount downloaded so far for all requests in this queue
|
||||
unsigned long long bytesDownloadedSoFar;
|
||||
|
||||
// Total amount to be downloaded for all requests in this queue - requests add to this figure as they receive Content-Length headers
|
||||
unsigned long long totalBytesToDownload;
|
||||
|
||||
// When YES, the queue will cancel all requests when a request fails. Default is YES
|
||||
BOOL shouldCancelAllRequestsOnFailure;
|
||||
|
||||
//Number of real requests (excludes HEAD requests created to manage showAccurateProgress)
|
||||
int requestsCount;
|
||||
|
||||
// When NO, this request will only update the progress indicator when it completes
|
||||
// When YES, this request will update the progress indicator according to how much data it has received so far
|
||||
// When YES, the queue will first perform HEAD requests for all GET requests in the queue, so it can calculate the total download size before it starts
|
||||
// NO means better performance, because it skips this step for GET requests, and it won't waste time updating the progress indicator until a request completes
|
||||
// Set to YES if the size of a requests in the queue varies greatly for much more accurate results
|
||||
// Default for requests in the queue is NO
|
||||
BOOL showAccurateProgress;
|
||||
|
||||
// Storage container for additional queue information.
|
||||
NSDictionary *userInfo;
|
||||
|
||||
}
|
||||
|
||||
// Convenience constructor
|
||||
+ (id)queue;
|
||||
|
||||
// Call this to reset a queue - it will cancel all operations, clear delegates, and suspend operation
|
||||
- (void)reset;
|
||||
|
||||
// Used internally to manage HEAD requests when showAccurateProgress is YES, do not use!
|
||||
- (void)addHEADOperation:(NSOperation *)operation;
|
||||
|
||||
// All ASINetworkQueues are paused when created so that total size can be calculated before the queue starts
|
||||
// This method will start the queue
|
||||
- (void)go;
|
||||
|
||||
@property (assign, nonatomic, setter=setUploadProgressDelegate:) id uploadProgressDelegate;
|
||||
@property (assign, nonatomic, setter=setDownloadProgressDelegate:) id downloadProgressDelegate;
|
||||
|
||||
@property (assign, atomic) SEL requestDidStartSelector;
|
||||
@property (assign, atomic) SEL requestDidReceiveResponseHeadersSelector;
|
||||
@property (assign, atomic) SEL requestWillRedirectSelector;
|
||||
@property (assign, atomic) SEL requestDidFinishSelector;
|
||||
@property (assign, atomic) SEL requestDidFailSelector;
|
||||
@property (assign, atomic) SEL queueDidFinishSelector;
|
||||
@property (assign, atomic) BOOL shouldCancelAllRequestsOnFailure;
|
||||
@property (assign, atomic) id delegate;
|
||||
@property (assign, atomic) BOOL showAccurateProgress;
|
||||
@property (assign, atomic, readonly) int requestsCount;
|
||||
@property (retain, atomic) NSDictionary *userInfo;
|
||||
|
||||
@property (assign, atomic) unsigned long long bytesUploadedSoFar;
|
||||
@property (assign, atomic) unsigned long long totalBytesToUpload;
|
||||
@property (assign, atomic) unsigned long long bytesDownloadedSoFar;
|
||||
@property (assign, atomic) unsigned long long totalBytesToDownload;
|
||||
|
||||
@end
|
|
@ -1,343 +0,0 @@
|
|||
//
|
||||
// ASINetworkQueue.m
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 07/11/2008.
|
||||
// Copyright 2008-2009 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
#import "ASINetworkQueue.h"
|
||||
#import "ASIHTTPRequest.h"
|
||||
|
||||
// Private stuff
|
||||
@interface ASINetworkQueue ()
|
||||
- (void)resetProgressDelegate:(id *)progressDelegate;
|
||||
@property (assign) int requestsCount;
|
||||
@end
|
||||
|
||||
@implementation ASINetworkQueue
|
||||
|
||||
- (id)init
|
||||
{
|
||||
self = [super init];
|
||||
[self setShouldCancelAllRequestsOnFailure:YES];
|
||||
[self setMaxConcurrentOperationCount:4];
|
||||
[self setSuspended:YES];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
+ (id)queue
|
||||
{
|
||||
return [[[self alloc] init] autorelease];
|
||||
}
|
||||
|
||||
- (void)dealloc
|
||||
{
|
||||
//We need to clear the queue on any requests that haven't got around to cleaning up yet, as otherwise they'll try to let us know if something goes wrong, and we'll be long gone by then
|
||||
for (ASIHTTPRequest *request in [self operations]) {
|
||||
[request setQueue:nil];
|
||||
}
|
||||
[userInfo release];
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
- (void)setSuspended:(BOOL)suspend
|
||||
{
|
||||
[super setSuspended:suspend];
|
||||
}
|
||||
|
||||
- (void)reset
|
||||
{
|
||||
[self cancelAllOperations];
|
||||
[self setDelegate:nil];
|
||||
[self setDownloadProgressDelegate:nil];
|
||||
[self setUploadProgressDelegate:nil];
|
||||
[self setRequestDidStartSelector:NULL];
|
||||
[self setRequestDidReceiveResponseHeadersSelector:NULL];
|
||||
[self setRequestDidFailSelector:NULL];
|
||||
[self setRequestDidFinishSelector:NULL];
|
||||
[self setQueueDidFinishSelector:NULL];
|
||||
[self setSuspended:YES];
|
||||
}
|
||||
|
||||
|
||||
- (void)go
|
||||
{
|
||||
[self setSuspended:NO];
|
||||
}
|
||||
|
||||
- (void)cancelAllOperations
|
||||
{
|
||||
[self setBytesUploadedSoFar:0];
|
||||
[self setTotalBytesToUpload:0];
|
||||
[self setBytesDownloadedSoFar:0];
|
||||
[self setTotalBytesToDownload:0];
|
||||
[super cancelAllOperations];
|
||||
}
|
||||
|
||||
- (void)setUploadProgressDelegate:(id)newDelegate
|
||||
{
|
||||
uploadProgressDelegate = newDelegate;
|
||||
[self resetProgressDelegate:&uploadProgressDelegate];
|
||||
|
||||
}
|
||||
|
||||
- (void)setDownloadProgressDelegate:(id)newDelegate
|
||||
{
|
||||
downloadProgressDelegate = newDelegate;
|
||||
[self resetProgressDelegate:&downloadProgressDelegate];
|
||||
}
|
||||
|
||||
- (void)resetProgressDelegate:(id *)progressDelegate
|
||||
{
|
||||
#if !TARGET_OS_IPHONE
|
||||
// If the uploadProgressDelegate is an NSProgressIndicator, we set its MaxValue to 1.0 so we can treat it similarly to UIProgressViews
|
||||
SEL selector = @selector(setMaxValue:);
|
||||
if ([*progressDelegate respondsToSelector:selector]) {
|
||||
double max = 1.0;
|
||||
[ASIHTTPRequest performSelector:selector onTarget:progressDelegate withObject:nil amount:&max callerToRetain:nil];
|
||||
}
|
||||
selector = @selector(setDoubleValue:);
|
||||
if ([*progressDelegate respondsToSelector:selector]) {
|
||||
double value = 0.0;
|
||||
[ASIHTTPRequest performSelector:selector onTarget:progressDelegate withObject:nil amount:&value callerToRetain:nil];
|
||||
}
|
||||
#else
|
||||
SEL selector = @selector(setProgress:);
|
||||
if ([*progressDelegate respondsToSelector:selector]) {
|
||||
float value = 0.0f;
|
||||
[ASIHTTPRequest performSelector:selector onTarget:progressDelegate withObject:nil amount:&value callerToRetain:nil];
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
- (void)addHEADOperation:(NSOperation *)operation
|
||||
{
|
||||
if ([operation isKindOfClass:[ASIHTTPRequest class]]) {
|
||||
|
||||
ASIHTTPRequest *request = (ASIHTTPRequest *)operation;
|
||||
[request setRequestMethod:@"HEAD"];
|
||||
[request setQueuePriority:10];
|
||||
[request setShowAccurateProgress:YES];
|
||||
[request setQueue:self];
|
||||
|
||||
// Important - we are calling NSOperation's add method - we don't want to add this as a normal request!
|
||||
[super addOperation:request];
|
||||
}
|
||||
}
|
||||
|
||||
// Only add ASIHTTPRequests to this queue!!
|
||||
- (void)addOperation:(NSOperation *)operation
|
||||
{
|
||||
if (![operation isKindOfClass:[ASIHTTPRequest class]]) {
|
||||
[NSException raise:@"AttemptToAddInvalidRequest" format:@"Attempted to add an object that was not an ASIHTTPRequest to an ASINetworkQueue"];
|
||||
}
|
||||
|
||||
[self setRequestsCount:[self requestsCount]+1];
|
||||
|
||||
ASIHTTPRequest *request = (ASIHTTPRequest *)operation;
|
||||
|
||||
if ([self showAccurateProgress]) {
|
||||
|
||||
// Force the request to build its body (this may change requestMethod)
|
||||
[request buildPostBody];
|
||||
|
||||
// If this is a GET request and we want accurate progress, perform a HEAD request first to get the content-length
|
||||
// We'll only do this before the queue is started
|
||||
// If requests are added after the queue is started they will probably move the overall progress backwards anyway, so there's no value performing the HEAD requests first
|
||||
// Instead, they'll update the total progress if and when they receive a content-length header
|
||||
if ([[request requestMethod] isEqualToString:@"GET"]) {
|
||||
if ([self isSuspended]) {
|
||||
ASIHTTPRequest *HEADRequest = [request HEADRequest];
|
||||
[self addHEADOperation:HEADRequest];
|
||||
[request addDependency:HEADRequest];
|
||||
if ([request shouldResetDownloadProgress]) {
|
||||
[self resetProgressDelegate:&downloadProgressDelegate];
|
||||
[request setShouldResetDownloadProgress:NO];
|
||||
}
|
||||
}
|
||||
}
|
||||
[request buildPostBody];
|
||||
[self request:nil incrementUploadSizeBy:(long long)[request postLength]];
|
||||
|
||||
|
||||
} else {
|
||||
[self request:nil incrementDownloadSizeBy:1];
|
||||
[self request:nil incrementUploadSizeBy:1];
|
||||
}
|
||||
// Tell the request not to increment the upload size when it starts, as we've already added its length
|
||||
if ([request shouldResetUploadProgress]) {
|
||||
[self resetProgressDelegate:&uploadProgressDelegate];
|
||||
[request setShouldResetUploadProgress:NO];
|
||||
}
|
||||
|
||||
[request setShowAccurateProgress:[self showAccurateProgress]];
|
||||
|
||||
[request setQueue:self];
|
||||
[super addOperation:request];
|
||||
|
||||
}
|
||||
|
||||
- (void)requestStarted:(ASIHTTPRequest *)request
|
||||
{
|
||||
if ([self requestDidStartSelector]) {
|
||||
[[self delegate] performSelector:[self requestDidStartSelector] withObject:request];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)request:(ASIHTTPRequest *)request didReceiveResponseHeaders:(NSDictionary *)responseHeaders
|
||||
{
|
||||
if ([self requestDidReceiveResponseHeadersSelector]) {
|
||||
[[self delegate] performSelector:[self requestDidReceiveResponseHeadersSelector] withObject:request withObject:responseHeaders];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)request:(ASIHTTPRequest *)request willRedirectToURL:(NSURL *)newURL
|
||||
{
|
||||
if ([self requestWillRedirectSelector]) {
|
||||
[[self delegate] performSelector:[self requestWillRedirectSelector] withObject:request withObject:newURL];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)requestFinished:(ASIHTTPRequest *)request
|
||||
{
|
||||
[self setRequestsCount:[self requestsCount]-1];
|
||||
if ([self requestDidFinishSelector]) {
|
||||
[[self delegate] performSelector:[self requestDidFinishSelector] withObject:request];
|
||||
}
|
||||
if ([self requestsCount] == 0) {
|
||||
if ([self queueDidFinishSelector]) {
|
||||
[[self delegate] performSelector:[self queueDidFinishSelector] withObject:self];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)requestFailed:(ASIHTTPRequest *)request
|
||||
{
|
||||
[self setRequestsCount:[self requestsCount]-1];
|
||||
if ([self requestDidFailSelector]) {
|
||||
[[self delegate] performSelector:[self requestDidFailSelector] withObject:request];
|
||||
}
|
||||
if ([self requestsCount] == 0) {
|
||||
if ([self queueDidFinishSelector]) {
|
||||
[[self delegate] performSelector:[self queueDidFinishSelector] withObject:self];
|
||||
}
|
||||
}
|
||||
if ([self shouldCancelAllRequestsOnFailure] && [self requestsCount] > 0) {
|
||||
[self cancelAllOperations];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
- (void)request:(ASIHTTPRequest *)request didReceiveBytes:(long long)bytes
|
||||
{
|
||||
[self setBytesDownloadedSoFar:[self bytesDownloadedSoFar]+(unsigned long long)bytes];
|
||||
if ([self downloadProgressDelegate]) {
|
||||
[ASIHTTPRequest updateProgressIndicator:&downloadProgressDelegate withProgress:[self bytesDownloadedSoFar] ofTotal:[self totalBytesToDownload]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)request:(ASIHTTPRequest *)request didSendBytes:(long long)bytes
|
||||
{
|
||||
[self setBytesUploadedSoFar:[self bytesUploadedSoFar]+(unsigned long long)bytes];
|
||||
if ([self uploadProgressDelegate]) {
|
||||
[ASIHTTPRequest updateProgressIndicator:&uploadProgressDelegate withProgress:[self bytesUploadedSoFar] ofTotal:[self totalBytesToUpload]];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)request:(ASIHTTPRequest *)request incrementDownloadSizeBy:(long long)newLength
|
||||
{
|
||||
[self setTotalBytesToDownload:[self totalBytesToDownload]+(unsigned long long)newLength];
|
||||
}
|
||||
|
||||
- (void)request:(ASIHTTPRequest *)request incrementUploadSizeBy:(long long)newLength
|
||||
{
|
||||
[self setTotalBytesToUpload:[self totalBytesToUpload]+(unsigned long long)newLength];
|
||||
}
|
||||
|
||||
|
||||
// Since this queue takes over as the delegate for all requests it contains, it should forward authorisation requests to its own delegate
|
||||
- (void)authenticationNeededForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
if ([[self delegate] respondsToSelector:@selector(authenticationNeededForRequest:)]) {
|
||||
[[self delegate] performSelector:@selector(authenticationNeededForRequest:) withObject:request];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)proxyAuthenticationNeededForRequest:(ASIHTTPRequest *)request
|
||||
{
|
||||
if ([[self delegate] respondsToSelector:@selector(proxyAuthenticationNeededForRequest:)]) {
|
||||
[[self delegate] performSelector:@selector(proxyAuthenticationNeededForRequest:) withObject:request];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
- (BOOL)respondsToSelector:(SEL)selector
|
||||
{
|
||||
// We handle certain methods differently because whether our delegate implements them or not can affect how the request should behave
|
||||
|
||||
// If the delegate implements this, the request will stop to wait for credentials
|
||||
if (selector == @selector(authenticationNeededForRequest:)) {
|
||||
if ([[self delegate] respondsToSelector:@selector(authenticationNeededForRequest:)]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
|
||||
// If the delegate implements this, the request will to wait for credentials
|
||||
} else if (selector == @selector(proxyAuthenticationNeededForRequest:)) {
|
||||
if ([[self delegate] respondsToSelector:@selector(proxyAuthenticationNeededForRequest:)]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
|
||||
// If the delegate implements requestWillRedirectSelector, the request will stop to allow the delegate to change the url
|
||||
} else if (selector == @selector(request:willRedirectToURL:)) {
|
||||
if ([self requestWillRedirectSelector] && [[self delegate] respondsToSelector:[self requestWillRedirectSelector]]) {
|
||||
return YES;
|
||||
}
|
||||
return NO;
|
||||
}
|
||||
return [super respondsToSelector:selector];
|
||||
}
|
||||
|
||||
#pragma mark NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone
|
||||
{
|
||||
ASINetworkQueue *newQueue = [[[self class] alloc] init];
|
||||
[newQueue setDelegate:[self delegate]];
|
||||
[newQueue setRequestDidStartSelector:[self requestDidStartSelector]];
|
||||
[newQueue setRequestWillRedirectSelector:[self requestWillRedirectSelector]];
|
||||
[newQueue setRequestDidReceiveResponseHeadersSelector:[self requestDidReceiveResponseHeadersSelector]];
|
||||
[newQueue setRequestDidFinishSelector:[self requestDidFinishSelector]];
|
||||
[newQueue setRequestDidFailSelector:[self requestDidFailSelector]];
|
||||
[newQueue setQueueDidFinishSelector:[self queueDidFinishSelector]];
|
||||
[newQueue setUploadProgressDelegate:[self uploadProgressDelegate]];
|
||||
[newQueue setDownloadProgressDelegate:[self downloadProgressDelegate]];
|
||||
[newQueue setShouldCancelAllRequestsOnFailure:[self shouldCancelAllRequestsOnFailure]];
|
||||
[newQueue setShowAccurateProgress:[self showAccurateProgress]];
|
||||
[newQueue setUserInfo:[[[self userInfo] copyWithZone:zone] autorelease]];
|
||||
return newQueue;
|
||||
}
|
||||
|
||||
|
||||
@synthesize requestsCount;
|
||||
@synthesize bytesUploadedSoFar;
|
||||
@synthesize totalBytesToUpload;
|
||||
@synthesize bytesDownloadedSoFar;
|
||||
@synthesize totalBytesToDownload;
|
||||
@synthesize shouldCancelAllRequestsOnFailure;
|
||||
@synthesize uploadProgressDelegate;
|
||||
@synthesize downloadProgressDelegate;
|
||||
@synthesize requestDidStartSelector;
|
||||
@synthesize requestDidReceiveResponseHeadersSelector;
|
||||
@synthesize requestWillRedirectSelector;
|
||||
@synthesize requestDidFinishSelector;
|
||||
@synthesize requestDidFailSelector;
|
||||
@synthesize queueDidFinishSelector;
|
||||
@synthesize delegate;
|
||||
@synthesize showAccurateProgress;
|
||||
@synthesize userInfo;
|
||||
@end
|
|
@ -1,38 +0,0 @@
|
|||
//
|
||||
// ASIProgressDelegate.h
|
||||
// Part of ASIHTTPRequest -> http://allseeing-i.com/ASIHTTPRequest
|
||||
//
|
||||
// Created by Ben Copsey on 13/04/2010.
|
||||
// Copyright 2010 All-Seeing Interactive. All rights reserved.
|
||||
//
|
||||
|
||||
@class ASIHTTPRequest;
|
||||
|
||||
@protocol ASIProgressDelegate <NSObject>
|
||||
|
||||
@optional
|
||||
|
||||
// These methods are used to update UIProgressViews (iPhone OS) or NSProgressIndicators (Mac OS X)
|
||||
// If you are using a custom progress delegate, you may find it easier to implement didReceiveBytes / didSendBytes instead
|
||||
#if TARGET_OS_IPHONE
|
||||
- (void)setProgress:(float)newProgress;
|
||||
#else
|
||||
- (void)setDoubleValue:(double)newProgress;
|
||||
- (void)setMaxValue:(double)newMax;
|
||||
#endif
|
||||
|
||||
// Called when the request receives some data - bytes is the length of that data
|
||||
- (void)request:(ASIHTTPRequest *)request didReceiveBytes:(long long)bytes;
|
||||
|
||||
// Called when the request sends some data
|
||||
// The first 32KB (128KB on older platforms) of data sent is not included in this amount because of limitations with the CFNetwork API
|
||||
// bytes may be less than zero if a request needs to remove upload progress (probably because the request needs to run again)
|
||||
- (void)request:(ASIHTTPRequest *)request didSendBytes:(long long)bytes;
|
||||
|
||||
// Called when a request needs to change the length of the content to download
|
||||
- (void)request:(ASIHTTPRequest *)request incrementDownloadSizeBy:(long long)newLength;
|
||||
|
||||
// Called when a request needs to change the length of the content to upload
|
||||
// newLength may be less than zero when a request needs to remove the size of the internal buffer from progress tracking
|
||||
- (void)request:(ASIHTTPRequest *)request incrementUploadSizeBy:(long long)newLength;
|
||||
@end
|
|
@ -32,8 +32,8 @@
|
|||
- (void)refreshWithActivities:(NSArray *)activities;
|
||||
|
||||
- (void)fetchActivitiesDetail:(int)page;
|
||||
- (void)finishLoadActivities:(ASIHTTPRequest *)request;
|
||||
- (void)requestFailed:(ASIHTTPRequest *)request;
|
||||
- (void)finishLoadActivities:(NSURLSessionDataTask *)request;
|
||||
- (void)requestFailed:(NSURLSessionDataTask *)request;
|
||||
|
||||
- (void)checkScroll;
|
||||
|
||||
|
|
|
@ -101,26 +101,18 @@
|
|||
[appDelegate.dictSocialProfile objectForKey:@"user_id"],
|
||||
page];
|
||||
|
||||
NSURL *url = [NSURL URLWithString:urlString];
|
||||
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
|
||||
[request setValidatesSecureCertificate:NO];
|
||||
[request setDidFinishSelector:@selector(finishLoadActivities:)];
|
||||
[request setDidFailSelector:@selector(requestFailed:)];
|
||||
[request setDelegate:self];
|
||||
[request startAsynchronous];
|
||||
AFHTTPSessionManager *manager = [AFHTTPSessionManager manager];
|
||||
[manager GET:urlString parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
|
||||
[self finishLoadActivities:task];
|
||||
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
|
||||
[self requestFailed:task];
|
||||
}];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)finishLoadActivities:(ASIHTTPRequest *)request {
|
||||
- (void)finishLoadActivities:(NSDictionary *)results {
|
||||
self.pageFetching = NO;
|
||||
NSString *responseString = [request responseString];
|
||||
NSData *responseData = [responseString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSError *error;
|
||||
NSDictionary *results = [NSJSONSerialization
|
||||
JSONObjectWithData:responseData
|
||||
options:kNilOptions
|
||||
error:&error];
|
||||
|
||||
|
||||
// check for last page
|
||||
if (![[results objectForKey:@"has_next_page"] intValue]) {
|
||||
self.pageFinished = YES;
|
||||
|
@ -151,7 +143,7 @@
|
|||
[self refreshWithActivities:appDelegate.userActivitiesArray];
|
||||
}
|
||||
|
||||
- (void)requestFailed:(ASIHTTPRequest *)request {
|
||||
- (void)requestFailed:(NSURLSessionDataTask *)request {
|
||||
NSError *error = [request error];
|
||||
NSLog(@"Error: %@", error);
|
||||
[appDelegate informError:error];
|
||||
|
|
|
@ -1,18 +1,13 @@
|
|||
#import <UIKit/UIKit.h>
|
||||
#import "ASIHTTPRequest.h"
|
||||
#import "ASIFormDataRequest.h"
|
||||
#import "MBProgressHUD.h"
|
||||
#import "AFNetworking.h"
|
||||
|
||||
@interface BaseViewController : UIViewController {
|
||||
|
||||
NSMutableArray* requests;
|
||||
AFHTTPSessionManager *manager;
|
||||
|
||||
}
|
||||
|
||||
- (ASIHTTPRequest*) requestWithURL:(NSString*) s;
|
||||
- (ASIFormDataRequest*) formRequestWithURL:(NSString*) s;
|
||||
- (void) addRequest:(ASIHTTPRequest*)request;
|
||||
- (void) clearFinishedRequests;
|
||||
- (void) cancelRequests;
|
||||
|
||||
- (void)informError:(id)error;
|
||||
|
|
|
@ -6,48 +6,17 @@
|
|||
#pragma mark -
|
||||
#pragma mark HTTP requests
|
||||
|
||||
- (ASIHTTPRequest*) requestWithURL:(NSString*) s {
|
||||
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:[NSURL URLWithString:s]];
|
||||
[request setValidatesSecureCertificate:NO];
|
||||
[self addRequest:request];
|
||||
return request;
|
||||
}
|
||||
|
||||
- (ASIFormDataRequest*) formRequestWithURL:(NSString*) s {
|
||||
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:[NSURL URLWithString:s]];
|
||||
[self addRequest:request];
|
||||
return request;
|
||||
}
|
||||
|
||||
- (void) addRequest:(ASIHTTPRequest*)request {
|
||||
[request setDelegate:self];
|
||||
if (!requests) {
|
||||
requests = [[NSMutableArray alloc] initWithCapacity:3];
|
||||
} else {
|
||||
[self clearFinishedRequests];
|
||||
}
|
||||
[requests addObject:request];
|
||||
}
|
||||
|
||||
- (void) clearFinishedRequests {
|
||||
NSMutableArray* toremove = [[NSMutableArray alloc] initWithCapacity:[requests count]];
|
||||
for (ASIHTTPRequest* r in requests) {
|
||||
if ([r isFinished]) {
|
||||
[toremove addObject:r];
|
||||
}
|
||||
}
|
||||
|
||||
for (ASIHTTPRequest* r in toremove) {
|
||||
[requests removeObject:r];
|
||||
}
|
||||
- (instancetype)init {
|
||||
if (self = [super init]) {
|
||||
manager = [AFHTTPSessionManager manager];
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void) cancelRequests {
|
||||
for (ASIHTTPRequest* r in requests) {
|
||||
r.delegate = nil;
|
||||
[r cancel];
|
||||
}
|
||||
[requests removeAllObjects];
|
||||
[manager invalidateSessionCancelingTasks:YES];
|
||||
manager = [AFHTTPSessionManager manager];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
|
|
@ -108,10 +108,10 @@
|
|||
- (void)markFeedsReadFromTimestamp:(NSInteger)cutoffTimestamp andOlder:(BOOL)older;
|
||||
- (void)saveAndDrawFavicons:(ASIHTTPRequest *)request;
|
||||
- (void)requestFailed:(ASIHTTPRequest *)request;
|
||||
- (void)finishMarkAsSaved:(ASIFormDataRequest *)request;
|
||||
- (void)failedMarkAsSaved:(ASIFormDataRequest *)request;
|
||||
- (void)finishMarkAsUnsaved:(ASIFormDataRequest *)request;
|
||||
- (void)failedMarkAsUnsaved:(ASIFormDataRequest *)request;
|
||||
- (void)failedMarkAsUnread:(ASIFormDataRequest *)request;
|
||||
- (void)finishMarkAsSaved:(NSURLSessionDataTask *)request;
|
||||
- (void)failedMarkAsSaved:(NSURLSessionDataTask *)request;
|
||||
- (void)finishMarkAsUnsaved:(NSURLSessionDataTask *)request;
|
||||
- (void)failedMarkAsUnsaved:(NSURLSessionDataTask *)request;
|
||||
- (void)failedMarkAsUnread:(NSURLSessionDataTask *)request;
|
||||
|
||||
@end
|
||||
|
|
|
@ -12,7 +12,6 @@
|
|||
#import "NBContainerViewController.h"
|
||||
#import "NewsBlurViewController.h"
|
||||
#import "FeedDetailTableCell.h"
|
||||
#import "ASIFormDataRequest.h"
|
||||
#import "UserProfileViewController.h"
|
||||
#import "StoryDetailViewController.h"
|
||||
#import "StoryPageControl.h"
|
||||
|
@ -707,36 +706,21 @@
|
|||
[storiesCollection.searchQuery stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLHostAllowedCharacterSet]]];
|
||||
}
|
||||
[self cancelRequests];
|
||||
__weak ASIHTTPRequest *request = [self requestWithURL:theFeedDetailURL];
|
||||
[request setDelegate:self];
|
||||
[request setResponseEncoding:NSUTF8StringEncoding];
|
||||
[request setDefaultResponseEncoding:NSUTF8StringEncoding];
|
||||
[request setValidatesSecureCertificate:NO];
|
||||
[request setUserInfo:@{@"feedPage": [NSNumber numberWithInt:storiesCollection.feedPage]}];
|
||||
[request setFailedBlock:^(void) {
|
||||
NSLog(@"in failed block %@", request);
|
||||
if (request.isCancelled) {
|
||||
NSLog(@"Cancelled");
|
||||
return;
|
||||
} else {
|
||||
self.isOnline = NO;
|
||||
storiesCollection.feedPage = 1;
|
||||
[self loadOfflineStories];
|
||||
[self showOfflineNotifier];
|
||||
}
|
||||
[self.storyTitlesTable reloadData];
|
||||
}];
|
||||
[request setCompletionBlock:^(void) {
|
||||
[manager GET:theFeedDetailURL parameters:nil progress:nil success:^(NSURLSessionTask *task, id responseObject) {
|
||||
if (!storiesCollection.activeFeed) return;
|
||||
[self finishedLoadingFeed:request];
|
||||
[self finishedLoadingFeed:responseObject withResponse:task.response];
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
} failure:^(NSURLSessionTask *operation, NSError *error) {
|
||||
NSLog(@"in failed block %@", operation);
|
||||
self.isOnline = NO;
|
||||
storiesCollection.feedPage = 1;
|
||||
[self loadOfflineStories];
|
||||
[self showOfflineNotifier];
|
||||
[self.storyTitlesTable reloadData];
|
||||
}];
|
||||
[request setTimeOutSeconds:30];
|
||||
[request setTag:[[[storiesCollection activeFeed] objectForKey:@"id"] intValue]];
|
||||
[request startAsynchronous];
|
||||
[requests addObject:request];
|
||||
[request setUserInfo:@{@"feedPage": [NSNumber numberWithInt:storiesCollection.feedPage], @"feedId": [[storiesCollection activeFeed] objectForKey:@"id"]}];
|
||||
}
|
||||
|
||||
- (void)loadOfflineStories {
|
||||
|
@ -925,48 +909,41 @@
|
|||
}
|
||||
|
||||
[self cancelRequests];
|
||||
__weak ASIHTTPRequest *request = [self requestWithURL:theFeedDetailURL];
|
||||
[request setValidatesSecureCertificate:NO];
|
||||
[request setDelegate:self];
|
||||
[request setResponseEncoding:NSUTF8StringEncoding];
|
||||
[request setDefaultResponseEncoding:NSUTF8StringEncoding];
|
||||
[request setUserInfo:@{@"feedPage": [NSNumber numberWithInt:storiesCollection.feedPage]}];
|
||||
[request setFailedBlock:^(void) {
|
||||
if (request.isCancelled) {
|
||||
NSLog(@"Cancelled");
|
||||
return;
|
||||
} else {
|
||||
self.isOnline = NO;
|
||||
self.isShowingFetching = NO;
|
||||
// storiesCollection.feedPage = 1;
|
||||
[self loadOfflineStories];
|
||||
[self showOfflineNotifier];
|
||||
}
|
||||
}];
|
||||
[request setCompletionBlock:^(void) {
|
||||
[self finishedLoadingFeed:request];
|
||||
|
||||
|
||||
NSURLSessionDataTask *request = [manager GET:theFeedDetailURL parameters:nil progress:nil success:^(NSURLSessionTask *task, id responseObject) {
|
||||
[self finishedLoadingFeed:responseObject withResponse:task.response];
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
} failure:^(NSURLSessionTask *operation, NSError *error) {
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)operation.response;
|
||||
self.isOnline = NO;
|
||||
self.isShowingFetching = NO;
|
||||
// storiesCollection.feedPage = 1;
|
||||
[self loadOfflineStories];
|
||||
[self showOfflineNotifier];
|
||||
if (httpResponse.statusCode == 503) {
|
||||
[self informError:@"In maintenance mode"];
|
||||
self.pageFinished = YES;
|
||||
} else if (httpResponse.statusCode >= 500) {
|
||||
[self informError:@"The server barfed."];
|
||||
}
|
||||
}];
|
||||
[request setTimeOutSeconds:30];
|
||||
[request startAsynchronous];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark Processing Stories
|
||||
|
||||
- (void)finishedLoadingFeed:(ASIHTTPRequest *)request {
|
||||
if (request.isCancelled) {
|
||||
NSLog(@"Cancelled");
|
||||
return;
|
||||
} else if ([request responseStatusCode] >= 500 || [request responseStatusCode] == 404) {
|
||||
- (void)finishedLoadingFeed:(NSDictionary *)results withResponse:(NSURLResponse *)response {
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
||||
if (httpResponse.statusCode >= 500 || httpResponse.statusCode == 404) {
|
||||
self.isOnline = NO;
|
||||
self.isShowingFetching = NO;
|
||||
// storiesCollection.feedPage = 1;
|
||||
[self loadOfflineStories];
|
||||
[self showOfflineNotifier];
|
||||
if ([request responseStatusCode] == 503) {
|
||||
if (httpResponse.statusCode == 503) {
|
||||
[self informError:@"In maintenance mode"];
|
||||
self.pageFinished = YES;
|
||||
} else {
|
||||
|
@ -979,14 +956,7 @@
|
|||
appDelegate.hasLoadedFeedDetail = YES;
|
||||
self.isOnline = YES;
|
||||
self.isShowingFetching = NO;
|
||||
storiesCollection.feedPage = [[request.userInfo objectForKey:@"feedPage"] intValue];
|
||||
NSString *responseString = [request responseString];
|
||||
NSData *responseData = [responseString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSError *error;
|
||||
NSDictionary *results = [NSJSONSerialization
|
||||
JSONObjectWithData:responseData
|
||||
options:kNilOptions
|
||||
error:&error];
|
||||
// storiesCollection.feedPage = [[request.userInfo objectForKey:@"feedPage"] intValue];
|
||||
|
||||
// if (storiesCollection.isSavedView &&
|
||||
// ![[results objectForKey:@"stories"] count] &&
|
||||
|
@ -997,14 +967,15 @@
|
|||
id feedId = [results objectForKey:@"feed_id"];
|
||||
NSString *feedIdStr = [NSString stringWithFormat:@"%@",feedId];
|
||||
|
||||
if (!(storiesCollection.isRiverView ||
|
||||
storiesCollection.isSavedView ||
|
||||
storiesCollection.isReadView ||
|
||||
storiesCollection.isSocialView ||
|
||||
storiesCollection.isSocialRiverView)
|
||||
&& request.tag != [feedId intValue]) {
|
||||
return;
|
||||
}
|
||||
// Ignoring below during AFNetworking 3.0 migration because we don't know the feed id anymore.
|
||||
// if (!(storiesCollection.isRiverView ||
|
||||
// storiesCollection.isSavedView ||
|
||||
// storiesCollection.isReadView ||
|
||||
// storiesCollection.isSocialView ||
|
||||
// storiesCollection.isSocialRiverView)
|
||||
// && request.tag != [feedId intValue]) {
|
||||
// return;
|
||||
// }
|
||||
if (storiesCollection.isSocialView ||
|
||||
storiesCollection.isSocialRiverView ||
|
||||
storiesCollection.isSavedView ||
|
||||
|
@ -1791,9 +1762,8 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
- (void)markFeedsReadFromTimestamp:(NSInteger)cutoffTimestamp andOlder:(BOOL)older {
|
||||
NSString *urlString = [NSString stringWithFormat:@"%@/reader/mark_feed_as_read",
|
||||
self.appDelegate.url];
|
||||
NSURL *url = [NSURL URLWithString:urlString];
|
||||
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
|
||||
NSMutableArray *feedIds = [NSMutableArray array];
|
||||
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
||||
|
||||
if (storiesCollection.isRiverView) {
|
||||
if ([storiesCollection.activeFolder isEqual:@"everything"]) {
|
||||
|
@ -1814,33 +1784,19 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
}
|
||||
|
||||
for (id feedId in feedIds) {
|
||||
[request addPostValue:feedId forKey:@"feed_id"];
|
||||
[params setObject:feedId forKey:@"feed_id"];
|
||||
}
|
||||
|
||||
[params setObject:@(cutoffTimestamp) forKey:@"cutoff_timestamp"];
|
||||
NSString *direction = older ? @"older" : @"newest";
|
||||
[request setPostValue:@(cutoffTimestamp) forKey:@"cutoff_timestamp"];
|
||||
[request setPostValue:direction forKey:@"direction"];
|
||||
[request setDidFinishSelector:@selector(finishMarkOlderNewerAsRead:)];
|
||||
[request setDidFailSelector:@selector(requestFailed:)];
|
||||
[request setUserInfo:@{@"feeds" : feedIds, @"cutoffTimestamp" : @(cutoffTimestamp), @"older" : @(older)}];
|
||||
[request setDelegate:self];
|
||||
[request startAsynchronous];
|
||||
}
|
||||
|
||||
- (void)finishMarkOlderNewerAsRead:(ASIFormDataRequest *)request {
|
||||
if (request.responseStatusCode != 200) {
|
||||
[self requestFailed:request];
|
||||
return;
|
||||
}
|
||||
[params setObject:direction forKey:@"direction"];
|
||||
|
||||
if ([request.userInfo objectForKey:@"feeds"]) {
|
||||
[appDelegate markFeedReadInCache:request.userInfo[@"feeds"] cutoffTimestamp:[request.userInfo[@"cutoffTimestamp"] integerValue] older:[request.userInfo[@"older"] boolValue]];
|
||||
}
|
||||
|
||||
// is there a better way to refresh the detail view?
|
||||
[self reloadStories];
|
||||
// [appDelegate reloadFeedsView:YES];
|
||||
// [appDelegate loadFeedDetailView];
|
||||
[manager POST:urlString parameters:params progress:nil success:^(NSURLSessionTask *task, id responseObject) {
|
||||
[appDelegate markFeedReadInCache:feedIds cutoffTimestamp:cutoffTimestamp older:older];
|
||||
// is there a better way to refresh the detail view?
|
||||
[self reloadStories];
|
||||
} failure:^(NSURLSessionTask *operation, NSError *error) {
|
||||
[self requestFailed:error];
|
||||
}];
|
||||
}
|
||||
|
||||
- (IBAction)doOpenMarkReadMenu:(id)sender {
|
||||
|
@ -1944,20 +1900,18 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
if (storiesCollection.isRiverView) {
|
||||
urlString = [NSString stringWithFormat:@"%@/reader/rename_folder", self.appDelegate.url];
|
||||
}
|
||||
NSURL *url = [NSURL URLWithString:urlString];
|
||||
|
||||
__block ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
|
||||
[request setDelegate:self];
|
||||
|
||||
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
||||
if (storiesCollection.isRiverView) {
|
||||
[request addPostValue:[appDelegate extractFolderName:storiesCollection.activeFolder] forKey:@"folder_name"];
|
||||
[request addPostValue:[appDelegate extractParentFolderName:storiesCollection.activeFolder] forKey:@"in_folder"];
|
||||
[request addPostValue:newTitle forKey:@"new_folder_name"];
|
||||
[params setObject:[appDelegate extractFolderName:storiesCollection.activeFolder] forKey:@"folder_name"];
|
||||
[params setObject:[appDelegate extractParentFolderName:storiesCollection.activeFolder] forKey:@"in_folder"];
|
||||
[params setObject:newTitle forKey:@"new_folder_name"];
|
||||
} else {
|
||||
[request addPostValue:[storiesCollection.activeFeed objectForKey:@"id"] forKey:@"feed_id"];
|
||||
[request addPostValue:newTitle forKey:@"feed_title"];
|
||||
[params setObject:[storiesCollection.activeFeed objectForKey:@"id"] forKey:@"feed_id"];
|
||||
[params setObject:newTitle forKey:@"feed_title"];
|
||||
}
|
||||
[request setDidFailSelector:@selector(requestFailed:)];
|
||||
[request setCompletionBlock:^(void) {
|
||||
|
||||
[manager POST:urlString parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
|
||||
[appDelegate reloadFeedsView:YES];
|
||||
if (storiesCollection.isRiverView) {
|
||||
[appDelegate renameFolder:newTitle];
|
||||
|
@ -1972,11 +1926,9 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
}
|
||||
[self.navigationController.view setNeedsDisplay];
|
||||
[MBProgressHUD hideHUDForView:self.view animated:YES];
|
||||
|
||||
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
|
||||
[self requestFailed:error];
|
||||
}];
|
||||
[request setTimeOutSeconds:30];
|
||||
[request setTag:[[storiesCollection.activeFeed objectForKey:@"id"] intValue]];
|
||||
[request startAsynchronous];
|
||||
}
|
||||
|
||||
- (void)deleteSite {
|
||||
|
@ -1984,26 +1936,22 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
|
||||
HUD.labelText = @"Deleting...";
|
||||
|
||||
NSString *theFeedDetailURL = [NSString stringWithFormat:@"%@/reader/delete_feed",
|
||||
NSString *urlString = [NSString stringWithFormat:@"%@/reader/delete_feed",
|
||||
self.appDelegate.url];
|
||||
NSURL *urlFeedDetail = [NSURL URLWithString:theFeedDetailURL];
|
||||
|
||||
__block ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:urlFeedDetail];
|
||||
[request setDelegate:self];
|
||||
[request addPostValue:[storiesCollection.activeFeed objectForKey:@"id"] forKey:@"feed_id"];
|
||||
[request addPostValue:[appDelegate extractFolderName:storiesCollection.activeFolder] forKey:@"in_folder"];
|
||||
[request setDidFailSelector:@selector(requestFailed:)];
|
||||
[request setCompletionBlock:^(void) {
|
||||
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
||||
[params setObject:[storiesCollection.activeFeed objectForKey:@"id"] forKey:@"feed_id"];
|
||||
[params setObject:[appDelegate extractFolderName:storiesCollection.activeFolder] forKey:@"in_folder"];
|
||||
|
||||
[manager POST:urlString parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
|
||||
[appDelegate reloadFeedsView:YES];
|
||||
[appDelegate.navigationController
|
||||
popToViewController:[appDelegate.navigationController.viewControllers
|
||||
objectAtIndex:0]
|
||||
[appDelegate.navigationController
|
||||
popToViewController:[appDelegate.navigationController.viewControllers
|
||||
objectAtIndex:0]
|
||||
animated:YES];
|
||||
[MBProgressHUD hideHUDForView:self.view animated:YES];
|
||||
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
|
||||
[self requestFailed:error];
|
||||
}];
|
||||
[request setTimeOutSeconds:30];
|
||||
[request setTag:[[storiesCollection.activeFeed objectForKey:@"id"] intValue]];
|
||||
[request startAsynchronous];
|
||||
}
|
||||
|
||||
- (void)deleteFolder {
|
||||
|
@ -2011,28 +1959,25 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
|
||||
HUD.labelText = @"Deleting...";
|
||||
|
||||
NSString *theFeedDetailURL = [NSString stringWithFormat:@"%@/reader/delete_folder",
|
||||
NSString *urlString = [NSString stringWithFormat:@"%@/reader/delete_folder",
|
||||
self.appDelegate.url];
|
||||
NSURL *urlFeedDetail = [NSURL URLWithString:theFeedDetailURL];
|
||||
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
||||
[params setObject:[appDelegate extractFolderName:storiesCollection.activeFolder]
|
||||
forKey:@"folder_to_delete"];
|
||||
[params setObject:[appDelegate extractFolderName:[appDelegate
|
||||
extractParentFolderName:storiesCollection.activeFolder]]
|
||||
forKey:@"in_folder"];
|
||||
|
||||
__block ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:urlFeedDetail];
|
||||
[request setDelegate:self];
|
||||
[request addPostValue:[appDelegate extractFolderName:storiesCollection.activeFolder]
|
||||
forKey:@"folder_to_delete"];
|
||||
[request addPostValue:[appDelegate extractFolderName:[appDelegate
|
||||
extractParentFolderName:storiesCollection.activeFolder]]
|
||||
forKey:@"in_folder"];
|
||||
[request setDidFailSelector:@selector(requestFailed:)];
|
||||
[request setCompletionBlock:^(void) {
|
||||
[manager POST:urlString parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
|
||||
[appDelegate reloadFeedsView:YES];
|
||||
[appDelegate.navigationController
|
||||
popToViewController:[appDelegate.navigationController.viewControllers
|
||||
objectAtIndex:0]
|
||||
[appDelegate.navigationController
|
||||
popToViewController:[appDelegate.navigationController.viewControllers
|
||||
objectAtIndex:0]
|
||||
animated:YES];
|
||||
[MBProgressHUD hideHUDForView:self.view animated:YES];
|
||||
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
|
||||
[self requestFailed:error];
|
||||
}];
|
||||
[request setTimeOutSeconds:30];
|
||||
[request startAsynchronous];
|
||||
}
|
||||
|
||||
- (void)muteSite {
|
||||
|
@ -2044,80 +1989,59 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
NSString *thisIdentifier = [NSString stringWithFormat:@"%@", storiesCollection.activeFeed[@"id"]];
|
||||
[activeIdentifiers removeObject:thisIdentifier];
|
||||
|
||||
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
||||
NSString *urlString = [NSString stringWithFormat:@"%@/reader/save_feed_chooser", self.appDelegate.url];
|
||||
NSURL *url = [NSURL URLWithString:urlString];
|
||||
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
|
||||
for (id identifier in activeIdentifiers) {
|
||||
[request addPostValue:identifier forKey:@"approved_feeds"];
|
||||
}
|
||||
[request setCompletionBlock:^(void) {
|
||||
|
||||
[params setObject:activeIdentifiers forKey:@"approved_feeds"];
|
||||
[manager POST:urlString parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
|
||||
[self.appDelegate reloadFeedsView:YES];
|
||||
[self.appDelegate.navigationController popToViewController:[appDelegate.navigationController.viewControllers objectAtIndex:0]
|
||||
animated:YES];
|
||||
animated:YES];
|
||||
[MBProgressHUD hideHUDForView:self.view animated:YES];
|
||||
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
|
||||
[self requestFailed:error];
|
||||
}];
|
||||
request.didFailSelector = @selector(requestFailed:);
|
||||
request.timeOutSeconds = 30;
|
||||
[request startAsynchronous];
|
||||
}
|
||||
|
||||
- (void)performMoveToFolder:(id)toFolder {
|
||||
[MBProgressHUD hideHUDForView:self.view animated:YES];
|
||||
MBProgressHUD *HUD = [MBProgressHUD showHUDAddedTo:self.view animated:YES];
|
||||
ASIFormDataRequest *request = nil;
|
||||
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
||||
NSString *urlString;
|
||||
|
||||
if (self.appDelegate.storiesCollection.isRiverView) {
|
||||
HUD.labelText = @"Moving folder...";
|
||||
NSString *urlString = [NSString stringWithFormat:@"%@/reader/move_folder_to_folder", self.appDelegate.url];
|
||||
NSURL *url = [NSURL URLWithString:urlString];
|
||||
request = [ASIFormDataRequest requestWithURL:url];
|
||||
urlString = [NSString stringWithFormat:@"%@/reader/move_folder_to_folder", self.appDelegate.url];
|
||||
NSString *activeFolder = self.appDelegate.storiesCollection.activeFolder;
|
||||
NSString *parentFolderName = [self.appDelegate extractParentFolderName:activeFolder];
|
||||
NSString *fromFolder = [self.appDelegate extractFolderName:parentFolderName];
|
||||
NSString *toFolderIdentifier = [self.appDelegate extractFolderName:toFolder];
|
||||
NSString *folderName = [self.appDelegate extractFolderName:activeFolder];
|
||||
[request setPostValue:fromFolder forKey:@"in_folder"];
|
||||
[request setPostValue:toFolderIdentifier forKey:@"to_folder"];
|
||||
[request setPostValue:folderName forKey:@"folder_name"];
|
||||
[params setObject:fromFolder forKey:@"in_folder"];
|
||||
[params setObject:toFolderIdentifier forKey:@"to_folder"];
|
||||
[params setObject:folderName forKey:@"folder_name"];
|
||||
} else {
|
||||
HUD.labelText = @"Moving site...";
|
||||
NSString *urlString = [NSString stringWithFormat:@"%@/reader/move_feed_to_folder", self.appDelegate.url];
|
||||
NSURL *url = [NSURL URLWithString:urlString];
|
||||
request = [ASIFormDataRequest requestWithURL:url];
|
||||
urlString = [NSString stringWithFormat:@"%@/reader/move_feed_to_folder", self.appDelegate.url];
|
||||
NSString *fromFolder = [self.appDelegate extractFolderName:self.appDelegate.storiesCollection.activeFolder];
|
||||
NSString *toFolderIdentifier = [self.appDelegate extractFolderName:toFolder];
|
||||
NSString *feedIdentifier = [self.appDelegate.storiesCollection.activeFeed objectForKey:@"id"];
|
||||
[request setPostValue:fromFolder forKey:@"in_folder"];
|
||||
[request setPostValue:toFolderIdentifier forKey:@"to_folder"];
|
||||
[request setPostValue:feedIdentifier forKey:@"feed_id"];
|
||||
[params setObject:fromFolder forKey:@"in_folder"];
|
||||
[params setObject:toFolderIdentifier forKey:@"to_folder"];
|
||||
[params setObject:feedIdentifier forKey:@"feed_id"];
|
||||
}
|
||||
|
||||
[request setDelegate:self];
|
||||
[request setDidFinishSelector:@selector(moveToFolderFinished:)];
|
||||
[request setDidFailSelector:@selector(requestFailed:)];
|
||||
[request setUserInfo:@{@"toFolder" : toFolder}];
|
||||
[request startAsynchronous];
|
||||
}
|
||||
|
||||
- (void)moveToFolderFinished:(ASIHTTPRequest *)request {
|
||||
if ([request responseStatusCode] >= 500) {
|
||||
return [self requestFailed:request];
|
||||
}
|
||||
|
||||
[MBProgressHUD hideHUDForView:self.view animated:YES];
|
||||
|
||||
NSString *responseString = [request responseString];
|
||||
NSData *responseData = [responseString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSError *error;
|
||||
NSDictionary *results = [NSJSONSerialization
|
||||
JSONObjectWithData:responseData
|
||||
options:kNilOptions
|
||||
error:&error];
|
||||
int code = [[results valueForKey:@"code"] intValue];
|
||||
if (code != -1) {
|
||||
self.appDelegate.storiesCollection.activeFolder = request.userInfo[@"toFolder"];
|
||||
[self.appDelegate reloadFeedsView:NO];
|
||||
}
|
||||
[manager POST:urlString parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
|
||||
[MBProgressHUD hideHUDForView:self.view animated:YES];
|
||||
|
||||
int code = [[responseObject valueForKey:@"code"] intValue];
|
||||
if (code != -1) {
|
||||
self.appDelegate.storiesCollection.activeFolder = toFolder;
|
||||
[self.appDelegate reloadFeedsView:NO];
|
||||
}
|
||||
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
|
||||
[self requestFailed:error];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)openMoveView {
|
||||
|
@ -2248,27 +2172,27 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
#pragma mark -
|
||||
#pragma mark Story Actions - save
|
||||
|
||||
- (void)finishMarkAsSaved:(ASIFormDataRequest *)request {
|
||||
- (void)finishMarkAsSaved:(NSURLSessionDataTask *)request {
|
||||
|
||||
}
|
||||
|
||||
- (void)failedMarkAsSaved:(ASIFormDataRequest *)request {
|
||||
- (void)failedMarkAsSaved:(NSURLSessionDataTask *)request {
|
||||
[self informError:@"Failed to save story"];
|
||||
|
||||
[self.storyTitlesTable reloadData];
|
||||
}
|
||||
|
||||
- (void)finishMarkAsUnsaved:(ASIFormDataRequest *)request {
|
||||
- (void)finishMarkAsUnsaved:(NSURLSessionDataTask *)request {
|
||||
|
||||
}
|
||||
|
||||
- (void)failedMarkAsUnsaved:(ASIFormDataRequest *)request {
|
||||
- (void)failedMarkAsUnsaved:(NSURLSessionDataTask *)request {
|
||||
[self informError:@"Failed to unsave story"];
|
||||
|
||||
[self.storyTitlesTable reloadData];
|
||||
}
|
||||
|
||||
- (void)failedMarkAsUnread:(ASIFormDataRequest *)request {
|
||||
- (void)failedMarkAsUnread:(NSURLSessionDataTask *)request {
|
||||
[self informError:@"Failed to unread story"];
|
||||
|
||||
[self.storyTitlesTable reloadData];
|
||||
|
@ -2285,15 +2209,13 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
self.appDelegate.url,
|
||||
[storiesCollection.activeFeed objectForKey:@"id"]];
|
||||
[self cancelRequests];
|
||||
ASIHTTPRequest *request = [self requestWithURL:urlString];
|
||||
[request setValidatesSecureCertificate:NO];
|
||||
[request setDelegate:self];
|
||||
[request setResponseEncoding:NSUTF8StringEncoding];
|
||||
[request setDefaultResponseEncoding:NSUTF8StringEncoding];
|
||||
[request setDidFinishSelector:@selector(finishedRefreshingFeed:)];
|
||||
[request setDidFailSelector:@selector(failRefreshingFeed:)];
|
||||
[request setTimeOutSeconds:60];
|
||||
[request startAsynchronous];
|
||||
[manager GET:theFeedDetailURL parameters:nil progress:nil success:^(NSURLSessionTask *task, id responseObject) {
|
||||
[self renderStories:[responseObject objectForKey:@"stories"]];
|
||||
} failure:^(NSURLSessionTask *operation, NSError *error) {
|
||||
NSLog(@"Fail: %@", request);
|
||||
[self informError:[operation error]];
|
||||
[self fetchFeedDetail:1 withCallback:nil];
|
||||
}];
|
||||
|
||||
[storiesCollection setStories:nil];
|
||||
storiesCollection.feedPage = 1;
|
||||
|
@ -2302,24 +2224,6 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
[storyTitlesTable scrollRectToVisible:CGRectMake(0, 0, 1, 1) animated:YES];
|
||||
}
|
||||
|
||||
- (void)finishedRefreshingFeed:(ASIHTTPRequest *)request {
|
||||
NSString *responseString = [request responseString];
|
||||
NSData *responseData = [responseString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSError *error;
|
||||
NSDictionary *results = [NSJSONSerialization
|
||||
JSONObjectWithData:responseData
|
||||
options:kNilOptions
|
||||
error:&error];
|
||||
|
||||
[self renderStories:[results objectForKey:@"stories"]];
|
||||
}
|
||||
|
||||
- (void)failRefreshingFeed:(ASIHTTPRequest *)request {
|
||||
NSLog(@"Fail: %@", request);
|
||||
[self informError:[request error]];
|
||||
[self fetchFeedDetail:1 withCallback:nil];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
#pragma mark loadSocial Feeds
|
||||
|
||||
|
@ -2336,25 +2240,15 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
NSString *urlString = [NSString stringWithFormat:@"%@/reader/favicons%@",
|
||||
self.appDelegate.url,
|
||||
feedIdsQuery];
|
||||
NSURL *url = [NSURL URLWithString:urlString];
|
||||
ASIHTTPRequest *request = [ASIHTTPRequest requestWithURL:url];
|
||||
|
||||
[request setDidFinishSelector:@selector(saveAndDrawFavicons:)];
|
||||
[request setDidFailSelector:@selector(requestFailed:)];
|
||||
[request setDelegate:self];
|
||||
[request startAsynchronous];
|
||||
[manager GET:urlString parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
|
||||
[self saveAndDrawFavicons:responseObject];
|
||||
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
|
||||
[self requestFailed:error];
|
||||
}];
|
||||
}
|
||||
|
||||
- (void)saveAndDrawFavicons:(ASIHTTPRequest *)request {
|
||||
|
||||
NSString *responseString = [request responseString];
|
||||
NSData *responseData = [responseString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSError *error;
|
||||
NSDictionary *results = [NSJSONSerialization
|
||||
JSONObjectWithData:responseData
|
||||
options:kNilOptions
|
||||
error:&error];
|
||||
|
||||
- (void)saveAndDrawFavicons:(NSDictionary *)results {
|
||||
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0ul);
|
||||
dispatch_async(queue, ^{
|
||||
for (id feed_id in results) {
|
||||
|
@ -2377,9 +2271,8 @@ didEndSwipingSwipingWithState:(MCSwipeTableViewCellState)state
|
|||
|
||||
}
|
||||
|
||||
- (void)requestFailed:(ASIHTTPRequest *)request {
|
||||
- (void)requestFailed:(NSError *)error {
|
||||
[MBProgressHUD hideHUDForView:self.view animated:YES];
|
||||
NSError *error = [request error];
|
||||
NSLog(@"Error: %@", error);
|
||||
[appDelegate informError:error];
|
||||
}
|
||||
|
|
|
@ -354,15 +354,13 @@ SFSafariViewControllerDelegate> {
|
|||
- (void)markFeedReadInCache:(NSArray *)feedIds cutoffTimestamp:(NSInteger)cutoff;
|
||||
- (void)markFeedReadInCache:(NSArray *)feedIds cutoffTimestamp:(NSInteger)cutoff older:(BOOL)older;
|
||||
- (void)markStoriesRead:(NSDictionary *)stories inFeeds:(NSArray *)feeds cutoffTimestamp:(NSInteger)cutoff;
|
||||
- (void)requestFailedMarkStoryRead:(ASIFormDataRequest *)request;
|
||||
- (void)finishMarkAllAsRead:(ASIHTTPRequest *)request;
|
||||
- (void)finishMarkAsRead:(NSDictionary *)story;
|
||||
- (void)finishMarkAsUnread:(NSDictionary *)story;
|
||||
- (void)failedMarkAsUnread:(ASIFormDataRequest *)request;
|
||||
- (void)finishMarkAsSaved:(ASIFormDataRequest *)request;
|
||||
- (void)failedMarkAsSaved:(ASIFormDataRequest *)request;
|
||||
- (void)finishMarkAsUnsaved:(ASIFormDataRequest *)request;
|
||||
- (void)failedMarkAsUnsaved:(ASIFormDataRequest *)request;
|
||||
- (void)failedMarkAsUnread:(NSURLSessionDataTask *)request;
|
||||
- (void)finishMarkAsSaved:(NSURLSessionDataTask *)request;
|
||||
- (void)failedMarkAsSaved:(NSURLSessionDataTask *)request;
|
||||
- (void)finishMarkAsUnsaved:(NSURLSessionDataTask *)request;
|
||||
- (void)failedMarkAsUnsaved:(NSURLSessionDataTask *)request;
|
||||
- (NSInteger)adjustSavedStoryCount:(NSString *)tagName direction:(NSInteger)direction;
|
||||
- (NSArray *)updateStarredStoryCounts:(NSDictionary *)results;
|
||||
- (void)renameFeed:(NSString *)newTitle;
|
||||
|
@ -400,7 +398,6 @@ SFSafariViewControllerDelegate> {
|
|||
- (void)toggleTagClassifier:(NSString *)tag feedId:(NSString *)feedId;
|
||||
- (void)toggleTitleClassifier:(NSString *)title feedId:(NSString *)feedId score:(NSInteger)score;
|
||||
- (void)toggleFeedClassifier:(NSString *)feedId;
|
||||
- (void)requestClassifierResponse:(ASIHTTPRequest *)request withFeed:(NSString *)feedId;
|
||||
|
||||
- (NSInteger)databaseSchemaVersion:(FMDatabase *)db;
|
||||
- (void)createDatabaseConnection;
|
||||
|
|
|
@ -2864,7 +2864,7 @@
|
|||
@"remove_like_author"];
|
||||
[request setPostValue:feedId forKey:@"feed_id"];
|
||||
[request setCompletionBlock:^{
|
||||
[self requestClassifierResponse:_request withFeed:feedId];
|
||||
[self.feedsViewController refreshFeedList:feedId];
|
||||
}];
|
||||
[request setFailedBlock:^{
|
||||
[self requestClassifierResponse:_request withFeed:feedId];
|
||||
|
@ -2912,7 +2912,7 @@
|
|||
@"remove_like_tag"];
|
||||
[request setPostValue:feedId forKey:@"feed_id"];
|
||||
[request setCompletionBlock:^{
|
||||
[self requestClassifierResponse:_request withFeed:feedId];
|
||||
[self.feedsViewController refreshFeedList:feedId];
|
||||
}];
|
||||
[request setFailedBlock:^{
|
||||
[self requestClassifierResponse:_request withFeed:feedId];
|
||||
|
@ -2964,7 +2964,7 @@
|
|||
@"remove_like_title"];
|
||||
[request setPostValue:feedId forKey:@"feed_id"];
|
||||
[request setCompletionBlock:^{
|
||||
[self requestClassifierResponse:_request withFeed:feedId];
|
||||
[self.feedsViewController refreshFeedList:feedId];
|
||||
}];
|
||||
[request setFailedBlock:^{
|
||||
[self requestClassifierResponse:_request withFeed:feedId];
|
||||
|
@ -3001,41 +3001,36 @@
|
|||
|
||||
NSString *urlString = [NSString stringWithFormat:@"%@/classifier/save",
|
||||
self.url];
|
||||
NSURL *url = [NSURL URLWithString:urlString];
|
||||
__block ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
|
||||
__weak ASIFormDataRequest *_request = request;
|
||||
[request setPostValue:feedId
|
||||
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
||||
[params setObject:feedId
|
||||
forKey:feedScore >= 1 ? @"like_feed" :
|
||||
feedScore <= -1 ? @"dislike_feed" :
|
||||
@"remove_like_feed"];
|
||||
[request setPostValue:feedId forKey:@"feed_id"];
|
||||
[request setCompletionBlock:^{
|
||||
[self requestClassifierResponse:_request withFeed:feedId];
|
||||
}];
|
||||
[request setFailedBlock:^{
|
||||
[self requestClassifierResponse:_request withFeed:feedId];
|
||||
}];
|
||||
[request setDelegate:self];
|
||||
[request startAsynchronous];
|
||||
[params setObject:feedId forKey:@"feed_id"];
|
||||
|
||||
[manager POST:urlString parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
|
||||
[self.feedsViewController refreshFeedList:feedId];
|
||||
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
|
||||
[self failedRequest:task.response];
|
||||
}];
|
||||
|
||||
[self recalculateIntelligenceScores:feedId];
|
||||
[self.feedDetailViewController.storyTitlesTable reloadData];
|
||||
}
|
||||
|
||||
- (void)requestClassifierResponse:(ASIHTTPRequest *)request withFeed:(NSString *)feedId {
|
||||
- (void)failedRequest:(NSURLResponse *)response {
|
||||
NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
|
||||
BaseViewController *view;
|
||||
if (self.trainerViewController.isViewLoaded && self.trainerViewController.view.window) {
|
||||
view = self.trainerViewController;
|
||||
} else {
|
||||
view = self.storyPageControl.currentPage;
|
||||
}
|
||||
if ([request responseStatusCode] == 503) {
|
||||
if (httpResponse.statusCode == 503) {
|
||||
return [view informError:@"In maintenance mode"];
|
||||
} else if ([request responseStatusCode] != 200) {
|
||||
} else if (httpResponse.statusCode != 200) {
|
||||
return [view informError:@"The server barfed!"];
|
||||
}
|
||||
|
||||
[self.feedsViewController refreshFeedList:feedId];
|
||||
}
|
||||
|
||||
- (void)requestFailed:(ASIHTTPRequest *)request {
|
||||
|
@ -3411,31 +3406,21 @@
|
|||
}
|
||||
NSLog(@"Marking %lu queued read stories as read...", (unsigned long)[completedHashes count]);
|
||||
NSString *completedHashesStr = [completedHashes componentsJoinedByString:@"\",\""];
|
||||
ASIFormDataRequest *request = [ASIFormDataRequest requestWithURL:url];
|
||||
__weak ASIHTTPRequest *_request = request;
|
||||
[request setPostValue:[hashes JSONRepresentation] forKey:@"feeds_stories"];
|
||||
[request setDelegate:self];
|
||||
[request setValidatesSecureCertificate:NO];
|
||||
[request setCompletionBlock:^{
|
||||
if ([_request responseStatusCode] == 200) {
|
||||
NSLog(@"Completed clearing %@ hashes", completedHashesStr);
|
||||
[db executeUpdate:[NSString stringWithFormat:@"DELETE FROM queued_read_hashes "
|
||||
"WHERE story_hash in (\"%@\")", completedHashesStr]];
|
||||
[self pruneQueuedReadHashes];
|
||||
} else {
|
||||
NSLog(@"Failed mark read queued.");
|
||||
self.hasQueuedReadStories = YES;
|
||||
[self pruneQueuedReadHashes];
|
||||
}
|
||||
NSMutableDictionary *params = [NSMutableDictionary dictionary];
|
||||
[params setObject:[hashes JSONRepresentation] forKey:@"feeds_stories"];
|
||||
|
||||
[manager POST:urlString parameters:params progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
|
||||
NSLog(@"Completed clearing %@ hashes", completedHashesStr);
|
||||
[db executeUpdate:[NSString stringWithFormat:@"DELETE FROM queued_read_hashes "
|
||||
"WHERE story_hash in (\"%@\")", completedHashesStr]];
|
||||
[self pruneQueuedReadHashes];
|
||||
if (callback) callback();
|
||||
}];
|
||||
[request setFailedBlock:^{
|
||||
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
|
||||
NSLog(@"Failed mark read queued.");
|
||||
self.hasQueuedReadStories = YES;
|
||||
[self pruneQueuedReadHashes];
|
||||
if (callback) callback();
|
||||
}];
|
||||
[request startAsynchronous];
|
||||
}
|
||||
|
||||
- (void)pruneQueuedReadHashes {
|
||||
|
|
|
@ -101,11 +101,6 @@
|
|||
- (void)setNextPreviousButtons;
|
||||
- (void)setTextButton;
|
||||
- (void)setTextButton:(StoryDetailViewController *)storyViewController;
|
||||
- (void)finishMarkAsSaved:(ASIFormDataRequest *)request;
|
||||
- (BOOL)failedMarkAsSaved:(ASIFormDataRequest *)request;
|
||||
- (void)finishMarkAsUnsaved:(ASIFormDataRequest *)request;
|
||||
- (BOOL)failedMarkAsUnsaved:(ASIFormDataRequest *)request;
|
||||
- (BOOL)failedMarkAsUnread:(ASIFormDataRequest *)request;
|
||||
- (void)subscribeToBlurblog;
|
||||
|
||||
- (IBAction)toggleFontSize:(id)sender;
|
||||
|
|
|
@ -207,12 +207,6 @@
|
|||
43F44B1C159D8DBC00F48F8A /* FeedTableCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 43F44B1B159D8D7200F48F8A /* FeedTableCell.m */; };
|
||||
43F6A79D15B0CDC60092EE91 /* ActivityCell.m in Sources */ = {isa = PBXBuildFile; fileRef = 43F6A79C15B0CDC60092EE91 /* ActivityCell.m */; };
|
||||
43F6A7A915B0E1ED0092EE91 /* CoreText.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 43F6A7A815B0E1ED0092EE91 /* CoreText.framework */; };
|
||||
78095E34128EF30C00230C8E /* ASIAuthenticationDialog.m in Sources */ = {isa = PBXBuildFile; fileRef = 78095E25128EF30C00230C8E /* ASIAuthenticationDialog.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
78095E35128EF30D00230C8E /* ASIDownloadCache.m in Sources */ = {isa = PBXBuildFile; fileRef = 78095E28128EF30C00230C8E /* ASIDownloadCache.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
78095E36128EF30D00230C8E /* ASIFormDataRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 78095E2A128EF30C00230C8E /* ASIFormDataRequest.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
78095E37128EF30D00230C8E /* ASIHTTPRequest.m in Sources */ = {isa = PBXBuildFile; fileRef = 78095E2C128EF30C00230C8E /* ASIHTTPRequest.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
78095E38128EF30D00230C8E /* ASIInputStream.m in Sources */ = {isa = PBXBuildFile; fileRef = 78095E30128EF30C00230C8E /* ASIInputStream.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
78095E39128EF30D00230C8E /* ASINetworkQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = 78095E32128EF30C00230C8E /* ASINetworkQueue.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
78095E3F128EF35400230C8E /* CFNetwork.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 78095E3E128EF35400230C8E /* CFNetwork.framework */; };
|
||||
78095E43128EF37E00230C8E /* MobileCoreServices.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 78095E42128EF37E00230C8E /* MobileCoreServices.framework */; };
|
||||
78095E45128EF37E00230C8E /* SystemConfiguration.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 78095E44128EF37E00230C8E /* SystemConfiguration.framework */; };
|
||||
|
@ -392,8 +386,6 @@
|
|||
FF753CD0175858FC00344EC9 /* FMDatabasePool.m in Sources */ = {isa = PBXBuildFile; fileRef = FF753CC8175858FC00344EC9 /* FMDatabasePool.m */; };
|
||||
FF753CD1175858FC00344EC9 /* FMDatabaseQueue.m in Sources */ = {isa = PBXBuildFile; fileRef = FF753CCA175858FC00344EC9 /* FMDatabaseQueue.m */; };
|
||||
FF753CD3175858FC00344EC9 /* FMResultSet.m in Sources */ = {isa = PBXBuildFile; fileRef = FF753CCD175858FC00344EC9 /* FMResultSet.m */; };
|
||||
FF793E1B13F1A9F700F282D2 /* ASIDataCompressor.m in Sources */ = {isa = PBXBuildFile; fileRef = FF793E1813F1A9F700F282D2 /* ASIDataCompressor.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
FF793E1C13F1A9F700F282D2 /* ASIDataDecompressor.m in Sources */ = {isa = PBXBuildFile; fileRef = FF793E1A13F1A9F700F282D2 /* ASIDataDecompressor.m */; settings = {COMPILER_FLAGS = "-fno-objc-arc"; }; };
|
||||
FF8364BB1755759A008F5C58 /* traverse_text.png in Resources */ = {isa = PBXBuildFile; fileRef = FF8364B91755759A008F5C58 /* traverse_text.png */; };
|
||||
FF8364BC1755759A008F5C58 /* traverse_text@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = FF8364BA1755759A008F5C58 /* traverse_text@2x.png */; };
|
||||
FF8364BF1756949E008F5C58 /* traverse_text_on.png in Resources */ = {isa = PBXBuildFile; fileRef = FF8364BD1756949E008F5C58 /* traverse_text_on.png */; };
|
||||
|
@ -825,22 +817,6 @@
|
|||
43F6A79B15B0CDC60092EE91 /* ActivityCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ActivityCell.h; sourceTree = "<group>"; };
|
||||
43F6A79C15B0CDC60092EE91 /* ActivityCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ActivityCell.m; sourceTree = "<group>"; };
|
||||
43F6A7A815B0E1ED0092EE91 /* CoreText.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreText.framework; path = System/Library/Frameworks/CoreText.framework; sourceTree = SDKROOT; };
|
||||
78095E24128EF30C00230C8E /* ASIAuthenticationDialog.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIAuthenticationDialog.h; sourceTree = "<group>"; };
|
||||
78095E25128EF30C00230C8E /* ASIAuthenticationDialog.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIAuthenticationDialog.m; sourceTree = "<group>"; };
|
||||
78095E26128EF30C00230C8E /* ASICacheDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASICacheDelegate.h; sourceTree = "<group>"; };
|
||||
78095E27128EF30C00230C8E /* ASIDownloadCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIDownloadCache.h; sourceTree = "<group>"; };
|
||||
78095E28128EF30C00230C8E /* ASIDownloadCache.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIDownloadCache.m; sourceTree = "<group>"; };
|
||||
78095E29128EF30C00230C8E /* ASIFormDataRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIFormDataRequest.h; sourceTree = "<group>"; };
|
||||
78095E2A128EF30C00230C8E /* ASIFormDataRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIFormDataRequest.m; sourceTree = "<group>"; };
|
||||
78095E2B128EF30C00230C8E /* ASIHTTPRequest.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIHTTPRequest.h; sourceTree = "<group>"; };
|
||||
78095E2C128EF30C00230C8E /* ASIHTTPRequest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIHTTPRequest.m; sourceTree = "<group>"; };
|
||||
78095E2D128EF30C00230C8E /* ASIHTTPRequestConfig.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIHTTPRequestConfig.h; sourceTree = "<group>"; };
|
||||
78095E2E128EF30C00230C8E /* ASIHTTPRequestDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIHTTPRequestDelegate.h; sourceTree = "<group>"; };
|
||||
78095E2F128EF30C00230C8E /* ASIInputStream.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIInputStream.h; sourceTree = "<group>"; };
|
||||
78095E30128EF30C00230C8E /* ASIInputStream.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIInputStream.m; sourceTree = "<group>"; };
|
||||
78095E31128EF30C00230C8E /* ASINetworkQueue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASINetworkQueue.h; sourceTree = "<group>"; };
|
||||
78095E32128EF30C00230C8E /* ASINetworkQueue.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASINetworkQueue.m; sourceTree = "<group>"; };
|
||||
78095E33128EF30C00230C8E /* ASIProgressDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIProgressDelegate.h; sourceTree = "<group>"; };
|
||||
78095E3E128EF35400230C8E /* CFNetwork.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CFNetwork.framework; path = System/Library/Frameworks/CFNetwork.framework; sourceTree = SDKROOT; };
|
||||
78095E42128EF37E00230C8E /* MobileCoreServices.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = MobileCoreServices.framework; path = System/Library/Frameworks/MobileCoreServices.framework; sourceTree = SDKROOT; };
|
||||
78095E44128EF37E00230C8E /* SystemConfiguration.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SystemConfiguration.framework; path = System/Library/Frameworks/SystemConfiguration.framework; sourceTree = SDKROOT; };
|
||||
|
@ -1109,10 +1085,6 @@
|
|||
FF753CCB175858FC00344EC9 /* fmdb.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = fmdb.m; sourceTree = "<group>"; };
|
||||
FF753CCC175858FC00344EC9 /* FMResultSet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FMResultSet.h; sourceTree = "<group>"; };
|
||||
FF753CCD175858FC00344EC9 /* FMResultSet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FMResultSet.m; sourceTree = "<group>"; };
|
||||
FF793E1713F1A9F700F282D2 /* ASIDataCompressor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIDataCompressor.h; sourceTree = "<group>"; };
|
||||
FF793E1813F1A9F700F282D2 /* ASIDataCompressor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIDataCompressor.m; sourceTree = "<group>"; };
|
||||
FF793E1913F1A9F700F282D2 /* ASIDataDecompressor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ASIDataDecompressor.h; sourceTree = "<group>"; };
|
||||
FF793E1A13F1A9F700F282D2 /* ASIDataDecompressor.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ASIDataDecompressor.m; sourceTree = "<group>"; };
|
||||
FF81FB1C1DDE9BF9003FA6B8 /* NewsBlur.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; name = NewsBlur.entitlements; path = NewsBlur/NewsBlur.entitlements; sourceTree = "<group>"; };
|
||||
FF8364B91755759A008F5C58 /* traverse_text.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = traverse_text.png; sourceTree = "<group>"; };
|
||||
FF8364BA1755759A008F5C58 /* traverse_text@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "traverse_text@2x.png"; sourceTree = "<group>"; };
|
||||
|
@ -1552,7 +1524,6 @@
|
|||
78095E44128EF37E00230C8E /* SystemConfiguration.framework */,
|
||||
FF2D8C6B1487F05100057B80 /* Twitter.framework */,
|
||||
1DF5F4DF0D08C38300B7A737 /* UIKit.framework */,
|
||||
78095E23128EF30C00230C8E /* ASI */,
|
||||
FF8D1EBC1BAA311000725D8A /* SBJSON */,
|
||||
FF8D1EA41BAA304E00725D8A /* Reachability */,
|
||||
);
|
||||
|
@ -2069,33 +2040,6 @@
|
|||
name = Models;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
78095E23128EF30C00230C8E /* ASI */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
78095E24128EF30C00230C8E /* ASIAuthenticationDialog.h */,
|
||||
78095E25128EF30C00230C8E /* ASIAuthenticationDialog.m */,
|
||||
FF793E1713F1A9F700F282D2 /* ASIDataCompressor.h */,
|
||||
FF793E1813F1A9F700F282D2 /* ASIDataCompressor.m */,
|
||||
FF793E1913F1A9F700F282D2 /* ASIDataDecompressor.h */,
|
||||
FF793E1A13F1A9F700F282D2 /* ASIDataDecompressor.m */,
|
||||
78095E26128EF30C00230C8E /* ASICacheDelegate.h */,
|
||||
78095E27128EF30C00230C8E /* ASIDownloadCache.h */,
|
||||
78095E28128EF30C00230C8E /* ASIDownloadCache.m */,
|
||||
78095E29128EF30C00230C8E /* ASIFormDataRequest.h */,
|
||||
78095E2A128EF30C00230C8E /* ASIFormDataRequest.m */,
|
||||
78095E2B128EF30C00230C8E /* ASIHTTPRequest.h */,
|
||||
78095E2C128EF30C00230C8E /* ASIHTTPRequest.m */,
|
||||
78095E2D128EF30C00230C8E /* ASIHTTPRequestConfig.h */,
|
||||
78095E2E128EF30C00230C8E /* ASIHTTPRequestDelegate.h */,
|
||||
78095E2F128EF30C00230C8E /* ASIInputStream.h */,
|
||||
78095E30128EF30C00230C8E /* ASIInputStream.m */,
|
||||
78095E31128EF30C00230C8E /* ASINetworkQueue.h */,
|
||||
78095E32128EF30C00230C8E /* ASINetworkQueue.m */,
|
||||
78095E33128EF30C00230C8E /* ASIProgressDelegate.h */,
|
||||
);
|
||||
path = ASI;
|
||||
sourceTree = "<group>";
|
||||
};
|
||||
FF03AFE619F87F2E0063002A /* TUSafariActivity */ = {
|
||||
isa = PBXGroup;
|
||||
children = (
|
||||
|
@ -2993,24 +2937,16 @@
|
|||
FFD6606C1BACA49C006E4B8D /* UIImageView+AFNetworking.m in Sources */,
|
||||
7843F50511EEB1A000675F64 /* FeedDetailTableCell.m in Sources */,
|
||||
784B50ED127E3F68008F90EA /* LoginViewController.m in Sources */,
|
||||
78095E34128EF30C00230C8E /* ASIAuthenticationDialog.m in Sources */,
|
||||
78095E35128EF30D00230C8E /* ASIDownloadCache.m in Sources */,
|
||||
FF5ACC241DE5F0C000FBD044 /* NotificationsViewController.m in Sources */,
|
||||
FF2EB7B41AA65504002549A7 /* IASKSettingsReader.m in Sources */,
|
||||
78095E36128EF30D00230C8E /* ASIFormDataRequest.m in Sources */,
|
||||
FFD660691BACA46D006E4B8D /* AFURLSessionManager.m in Sources */,
|
||||
78095E37128EF30D00230C8E /* ASIHTTPRequest.m in Sources */,
|
||||
FFCDD8FE17F6368F000C6483 /* MCSwipeTableViewCell.m in Sources */,
|
||||
FFD660681BACA46D006E4B8D /* AFURLResponseSerialization.m in Sources */,
|
||||
78095E38128EF30D00230C8E /* ASIInputStream.m in Sources */,
|
||||
FFD660611BACA46D006E4B8D /* AFHTTPRequestOperation.m in Sources */,
|
||||
78095E39128EF30D00230C8E /* ASINetworkQueue.m in Sources */,
|
||||
78095EC9128F30B500230C8E /* OriginalStoryViewController.m in Sources */,
|
||||
FF1C4E171A3FB1F4000995E3 /* NBActivityItemSource.m in Sources */,
|
||||
17C4954B1C129863004805A7 /* UISearchBar+Field.m in Sources */,
|
||||
FF793E1B13F1A9F700F282D2 /* ASIDataCompressor.m in Sources */,
|
||||
FF3A3E171BFC3F1300ADC01A /* NSNull+JSON.m in Sources */,
|
||||
FF793E1C13F1A9F700F282D2 /* ASIDataDecompressor.m in Sources */,
|
||||
FF5EA47F143B691000B7563D /* AddSiteViewController.m in Sources */,
|
||||
FF1F13D818AAC97900FDA816 /* UIImage+Resize.m in Sources */,
|
||||
FFD887F01445F1E800385399 /* AddSiteAutocompleteCell.m in Sources */,
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// AFHTTPSessionManager.h
|
||||
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
|
||||
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -23,9 +23,9 @@
|
|||
#if !TARGET_OS_WATCH
|
||||
#import <SystemConfiguration/SystemConfiguration.h>
|
||||
#endif
|
||||
#import <Availability.h>
|
||||
#import <TargetConditionals.h>
|
||||
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED
|
||||
#if TARGET_OS_IOS || TARGET_OS_WATCH || TARGET_OS_TV
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
#else
|
||||
#import <CoreServices/CoreServices.h>
|
||||
|
@ -33,14 +33,6 @@
|
|||
|
||||
#import "AFURLSessionManager.h"
|
||||
|
||||
#ifndef NS_DESIGNATED_INITIALIZER
|
||||
#if __has_attribute(objc_designated_initializer)
|
||||
#define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
|
||||
#else
|
||||
#define NS_DESIGNATED_INITIALIZER
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
`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.
|
||||
|
||||
|
@ -52,7 +44,7 @@
|
|||
|
||||
## Methods to Override
|
||||
|
||||
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:`.
|
||||
To change the behavior of all data task operation construction, which is also used in the `GET` / `POST` / et al. convenience methods, override `dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:`.
|
||||
|
||||
## Serialization
|
||||
|
||||
|
@ -79,8 +71,6 @@
|
|||
@warning Managers for background sessions must be owned for the duration of their use. This can be accomplished by creating an application-wide or shared singleton instance.
|
||||
*/
|
||||
|
||||
#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) || TARGET_OS_WATCH
|
||||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AFHTTPSessionManager : AFURLSessionManager <NSSecureCoding, NSCopying>
|
||||
|
@ -104,6 +94,15 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
@property (nonatomic, strong) AFHTTPResponseSerializer <AFURLResponseSerialization> * responseSerializer;
|
||||
|
||||
///-------------------------------
|
||||
/// @name Managing Security Policy
|
||||
///-------------------------------
|
||||
|
||||
/**
|
||||
The security policy used by created session to evaluate server trust for secure connections. `AFURLSessionManager` uses the `defaultPolicy` unless otherwise specified. A security policy configured with `AFSSLPinningModePublicKey` or `AFSSLPinningModeCertificate` can only be applied on a session manager initialized with a secure base URL (i.e. https). Applying a security policy with pinning enabled on an insecure session manager throws an `Invalid Security Policy` exception.
|
||||
*/
|
||||
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
|
||||
|
||||
///---------------------
|
||||
/// @name Initialization
|
||||
///---------------------
|
||||
|
@ -151,8 +150,26 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
- (nullable NSURLSessionDataTask *)GET:(NSString *)URLString
|
||||
parameters:(nullable id)parameters
|
||||
success:(nullable void (^)(NSURLSessionDataTask *task, id responseObject))success
|
||||
failure:(nullable void (^)(NSURLSessionDataTask *task, NSError *error))failure;
|
||||
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
|
||||
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure DEPRECATED_ATTRIBUTE;
|
||||
|
||||
|
||||
/**
|
||||
Creates and runs an `NSURLSessionDataTask` with a `GET` request.
|
||||
|
||||
@param URLString The URL string used to create the request URL.
|
||||
@param parameters The parameters to be encoded according to the client request serializer.
|
||||
@param downloadProgress A block object to be executed when the download progress is updated. Note this block is called on the session queue, not the main queue.
|
||||
@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.
|
||||
@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.
|
||||
|
||||
@see -dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:
|
||||
*/
|
||||
- (nullable NSURLSessionDataTask *)GET:(NSString *)URLString
|
||||
parameters:(nullable id)parameters
|
||||
progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgress
|
||||
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
|
||||
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
|
||||
|
||||
/**
|
||||
Creates and runs an `NSURLSessionDataTask` with a `HEAD` request.
|
||||
|
@ -167,7 +184,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
- (nullable NSURLSessionDataTask *)HEAD:(NSString *)URLString
|
||||
parameters:(nullable id)parameters
|
||||
success:(nullable void (^)(NSURLSessionDataTask *task))success
|
||||
failure:(nullable void (^)(NSURLSessionDataTask *task, NSError *error))failure;
|
||||
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
|
||||
|
||||
/**
|
||||
Creates and runs an `NSURLSessionDataTask` with a `POST` request.
|
||||
|
@ -181,8 +198,25 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
|
||||
parameters:(nullable id)parameters
|
||||
success:(nullable void (^)(NSURLSessionDataTask *task, id responseObject))success
|
||||
failure:(nullable void (^)(NSURLSessionDataTask *task, NSError *error))failure;
|
||||
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
|
||||
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure DEPRECATED_ATTRIBUTE;
|
||||
|
||||
/**
|
||||
Creates and runs an `NSURLSessionDataTask` with a `POST` request.
|
||||
|
||||
@param URLString The URL string used to create the request URL.
|
||||
@param parameters The parameters to be encoded according to the client request serializer.
|
||||
@param uploadProgress A block object to be executed when the upload progress is updated. Note this block is called on the session queue, not the main queue.
|
||||
@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.
|
||||
@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.
|
||||
|
||||
@see -dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:
|
||||
*/
|
||||
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
|
||||
parameters:(nullable id)parameters
|
||||
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
|
||||
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
|
||||
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
|
||||
|
||||
/**
|
||||
Creates and runs an `NSURLSessionDataTask` with a multipart `POST` request.
|
||||
|
@ -198,8 +232,27 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
|
||||
parameters:(nullable id)parameters
|
||||
constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
|
||||
success:(nullable void (^)(NSURLSessionDataTask *task, id responseObject))success
|
||||
failure:(nullable void (^)(NSURLSessionDataTask *task, NSError *error))failure;
|
||||
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
|
||||
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure DEPRECATED_ATTRIBUTE;
|
||||
|
||||
/**
|
||||
Creates and runs an `NSURLSessionDataTask` with a multipart `POST` request.
|
||||
|
||||
@param URLString The URL string used to create the request URL.
|
||||
@param parameters The parameters to be encoded according to the client request serializer.
|
||||
@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.
|
||||
@param uploadProgress A block object to be executed when the upload progress is updated. Note this block is called on the session queue, not the main queue.
|
||||
@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.
|
||||
@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.
|
||||
|
||||
@see -dataTaskWithRequest:uploadProgress:downloadProgress:completionHandler:
|
||||
*/
|
||||
- (nullable NSURLSessionDataTask *)POST:(NSString *)URLString
|
||||
parameters:(nullable id)parameters
|
||||
constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
|
||||
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgress
|
||||
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
|
||||
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
|
||||
|
||||
/**
|
||||
Creates and runs an `NSURLSessionDataTask` with a `PUT` request.
|
||||
|
@ -213,8 +266,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
- (nullable NSURLSessionDataTask *)PUT:(NSString *)URLString
|
||||
parameters:(nullable id)parameters
|
||||
success:(nullable void (^)(NSURLSessionDataTask *task, id responseObject))success
|
||||
failure:(nullable void (^)(NSURLSessionDataTask *task, NSError *error))failure;
|
||||
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
|
||||
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
|
||||
|
||||
/**
|
||||
Creates and runs an `NSURLSessionDataTask` with a `PATCH` request.
|
||||
|
@ -228,8 +281,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
- (nullable NSURLSessionDataTask *)PATCH:(NSString *)URLString
|
||||
parameters:(nullable id)parameters
|
||||
success:(nullable void (^)(NSURLSessionDataTask *task, id responseObject))success
|
||||
failure:(nullable void (^)(NSURLSessionDataTask *task, NSError *error))failure;
|
||||
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
|
||||
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
|
||||
|
||||
/**
|
||||
Creates and runs an `NSURLSessionDataTask` with a `DELETE` request.
|
||||
|
@ -243,11 +296,9 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
- (nullable NSURLSessionDataTask *)DELETE:(NSString *)URLString
|
||||
parameters:(nullable id)parameters
|
||||
success:(nullable void (^)(NSURLSessionDataTask *task, id responseObject))success
|
||||
failure:(nullable void (^)(NSURLSessionDataTask *task, NSError *error))failure;
|
||||
success:(nullable void (^)(NSURLSessionDataTask *task, id _Nullable responseObject))success
|
||||
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable task, NSError *error))failure;
|
||||
|
||||
@end
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// AFHTTPSessionManager.m
|
||||
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
|
||||
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -21,23 +21,20 @@
|
|||
|
||||
#import "AFHTTPSessionManager.h"
|
||||
|
||||
#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) || TARGET_WATCH_OS
|
||||
|
||||
#import "AFURLRequestSerialization.h"
|
||||
#import "AFURLResponseSerialization.h"
|
||||
|
||||
#import <Availability.h>
|
||||
#import <TargetConditionals.h>
|
||||
#import <Security/Security.h>
|
||||
|
||||
#ifdef _SYSTEMCONFIGURATION_H
|
||||
#import <netinet/in.h>
|
||||
#import <netinet6/in6.h>
|
||||
#import <arpa/inet.h>
|
||||
#import <ifaddrs.h>
|
||||
#import <netdb.h>
|
||||
#endif
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
#if TARGET_OS_IOS || TARGET_OS_TV
|
||||
#import <UIKit/UIKit.h>
|
||||
#elif TARGET_OS_WATCH
|
||||
#import <WatchKit/WatchKit.h>
|
||||
|
@ -89,9 +86,6 @@
|
|||
|
||||
#pragma mark -
|
||||
|
||||
#ifdef _SYSTEMCONFIGURATION_H
|
||||
#endif
|
||||
|
||||
- (void)setRequestSerializer:(AFHTTPRequestSerializer <AFURLRequestSerialization> *)requestSerializer {
|
||||
NSParameterAssert(requestSerializer);
|
||||
|
||||
|
@ -104,6 +98,23 @@
|
|||
[super setResponseSerializer:responseSerializer];
|
||||
}
|
||||
|
||||
@dynamic securityPolicy;
|
||||
|
||||
- (void)setSecurityPolicy:(AFSecurityPolicy *)securityPolicy {
|
||||
if (securityPolicy.SSLPinningMode != AFSSLPinningModeNone && ![self.baseURL.scheme isEqualToString:@"https"]) {
|
||||
NSString *pinningMode = @"Unknown Pinning Mode";
|
||||
switch (securityPolicy.SSLPinningMode) {
|
||||
case AFSSLPinningModeNone: pinningMode = @"AFSSLPinningModeNone"; break;
|
||||
case AFSSLPinningModeCertificate: pinningMode = @"AFSSLPinningModeCertificate"; break;
|
||||
case AFSSLPinningModePublicKey: pinningMode = @"AFSSLPinningModePublicKey"; break;
|
||||
}
|
||||
NSString *reason = [NSString stringWithFormat:@"A security policy configured with `%@` can only be applied on a manager with a secure base URL (i.e. https)", pinningMode];
|
||||
@throw [NSException exceptionWithName:@"Invalid Security Policy" reason:reason userInfo:nil];
|
||||
}
|
||||
|
||||
[super setSecurityPolicy:securityPolicy];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (NSURLSessionDataTask *)GET:(NSString *)URLString
|
||||
|
@ -111,7 +122,24 @@
|
|||
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
|
||||
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
|
||||
{
|
||||
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET" URLString:URLString parameters:parameters success:success failure:failure];
|
||||
|
||||
return [self GET:URLString parameters:parameters progress:nil success:success failure:failure];
|
||||
}
|
||||
|
||||
- (NSURLSessionDataTask *)GET:(NSString *)URLString
|
||||
parameters:(id)parameters
|
||||
progress:(void (^)(NSProgress * _Nonnull))downloadProgress
|
||||
success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
|
||||
failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
|
||||
{
|
||||
|
||||
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"GET"
|
||||
URLString:URLString
|
||||
parameters:parameters
|
||||
uploadProgress:nil
|
||||
downloadProgress:downloadProgress
|
||||
success:success
|
||||
failure:failure];
|
||||
|
||||
[dataTask resume];
|
||||
|
||||
|
@ -123,7 +151,7 @@
|
|||
success:(void (^)(NSURLSessionDataTask *task))success
|
||||
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
|
||||
{
|
||||
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"HEAD" URLString:URLString parameters:parameters success:^(NSURLSessionDataTask *task, __unused id responseObject) {
|
||||
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"HEAD" URLString:URLString parameters:parameters uploadProgress:nil downloadProgress:nil success:^(NSURLSessionDataTask *task, __unused id responseObject) {
|
||||
if (success) {
|
||||
success(task);
|
||||
}
|
||||
|
@ -139,16 +167,35 @@
|
|||
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
|
||||
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
|
||||
{
|
||||
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"POST" URLString:URLString parameters:parameters success:success failure:failure];
|
||||
return [self POST:URLString parameters:parameters progress:nil success:success failure:failure];
|
||||
}
|
||||
|
||||
- (NSURLSessionDataTask *)POST:(NSString *)URLString
|
||||
parameters:(id)parameters
|
||||
progress:(void (^)(NSProgress * _Nonnull))uploadProgress
|
||||
success:(void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
|
||||
failure:(void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
|
||||
{
|
||||
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"POST" URLString:URLString parameters:parameters uploadProgress:uploadProgress downloadProgress:nil success:success failure:failure];
|
||||
|
||||
[dataTask resume];
|
||||
|
||||
return dataTask;
|
||||
}
|
||||
|
||||
- (NSURLSessionDataTask *)POST:(NSString *)URLString
|
||||
parameters:(nullable id)parameters
|
||||
constructingBodyWithBlock:(nullable void (^)(id<AFMultipartFormData> _Nonnull))block
|
||||
success:(nullable void (^)(NSURLSessionDataTask * _Nonnull, id _Nullable))success
|
||||
failure:(nullable void (^)(NSURLSessionDataTask * _Nullable, NSError * _Nonnull))failure
|
||||
{
|
||||
return [self POST:URLString parameters:parameters constructingBodyWithBlock:block progress:nil success:success failure:failure];
|
||||
}
|
||||
|
||||
- (NSURLSessionDataTask *)POST:(NSString *)URLString
|
||||
parameters:(id)parameters
|
||||
constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block
|
||||
progress:(nullable void (^)(NSProgress * _Nonnull))uploadProgress
|
||||
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
|
||||
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
|
||||
{
|
||||
|
@ -156,18 +203,15 @@
|
|||
NSMutableURLRequest *request = [self.requestSerializer multipartFormRequestWithMethod:@"POST" URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters constructingBodyWithBlock:block error:&serializationError];
|
||||
if (serializationError) {
|
||||
if (failure) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wgnu"
|
||||
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
|
||||
failure(nil, serializationError);
|
||||
});
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
__block NSURLSessionDataTask *task = [self uploadTaskWithStreamedRequest:request progress:nil completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
|
||||
__block NSURLSessionDataTask *task = [self uploadTaskWithStreamedRequest:request progress:uploadProgress completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
|
||||
if (error) {
|
||||
if (failure) {
|
||||
failure(task, error);
|
||||
|
@ -189,7 +233,7 @@
|
|||
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
|
||||
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
|
||||
{
|
||||
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"PUT" URLString:URLString parameters:parameters success:success failure:failure];
|
||||
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"PUT" URLString:URLString parameters:parameters uploadProgress:nil downloadProgress:nil success:success failure:failure];
|
||||
|
||||
[dataTask resume];
|
||||
|
||||
|
@ -201,7 +245,7 @@
|
|||
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
|
||||
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
|
||||
{
|
||||
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"PATCH" URLString:URLString parameters:parameters success:success failure:failure];
|
||||
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"PATCH" URLString:URLString parameters:parameters uploadProgress:nil downloadProgress:nil success:success failure:failure];
|
||||
|
||||
[dataTask resume];
|
||||
|
||||
|
@ -213,7 +257,7 @@
|
|||
success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
|
||||
failure:(void (^)(NSURLSessionDataTask *task, NSError *error))failure
|
||||
{
|
||||
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"DELETE" URLString:URLString parameters:parameters success:success failure:failure];
|
||||
NSURLSessionDataTask *dataTask = [self dataTaskWithHTTPMethod:@"DELETE" URLString:URLString parameters:parameters uploadProgress:nil downloadProgress:nil success:success failure:failure];
|
||||
|
||||
[dataTask resume];
|
||||
|
||||
|
@ -223,6 +267,8 @@
|
|||
- (NSURLSessionDataTask *)dataTaskWithHTTPMethod:(NSString *)method
|
||||
URLString:(NSString *)URLString
|
||||
parameters:(id)parameters
|
||||
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgress
|
||||
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgress
|
||||
success:(void (^)(NSURLSessionDataTask *, id))success
|
||||
failure:(void (^)(NSURLSessionDataTask *, NSError *))failure
|
||||
{
|
||||
|
@ -230,19 +276,19 @@
|
|||
NSMutableURLRequest *request = [self.requestSerializer requestWithMethod:method URLString:[[NSURL URLWithString:URLString relativeToURL:self.baseURL] absoluteString] parameters:parameters error:&serializationError];
|
||||
if (serializationError) {
|
||||
if (failure) {
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wgnu"
|
||||
dispatch_async(self.completionQueue ?: dispatch_get_main_queue(), ^{
|
||||
failure(nil, serializationError);
|
||||
});
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
return nil;
|
||||
}
|
||||
|
||||
__block NSURLSessionDataTask *dataTask = nil;
|
||||
dataTask = [self dataTaskWithRequest:request completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
|
||||
dataTask = [self dataTaskWithRequest:request
|
||||
uploadProgress:uploadProgress
|
||||
downloadProgress:downloadProgress
|
||||
completionHandler:^(NSURLResponse * __unused response, id responseObject, NSError *error) {
|
||||
if (error) {
|
||||
if (failure) {
|
||||
failure(dataTask, error);
|
||||
|
@ -269,7 +315,7 @@
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder {
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder {
|
||||
NSURL *baseURL = [decoder decodeObjectOfClass:[NSURL class] forKey:NSStringFromSelector(@selector(baseURL))];
|
||||
NSURLSessionConfiguration *configuration = [decoder decodeObjectOfClass:[NSURLSessionConfiguration class] forKey:@"sessionConfiguration"];
|
||||
if (!configuration) {
|
||||
|
@ -290,6 +336,10 @@
|
|||
|
||||
self.requestSerializer = [decoder decodeObjectOfClass:[AFHTTPRequestSerializer class] forKey:NSStringFromSelector(@selector(requestSerializer))];
|
||||
self.responseSerializer = [decoder decodeObjectOfClass:[AFHTTPResponseSerializer class] forKey:NSStringFromSelector(@selector(responseSerializer))];
|
||||
AFSecurityPolicy *decodedPolicy = [decoder decodeObjectOfClass:[AFSecurityPolicy class] forKey:NSStringFromSelector(@selector(securityPolicy))];
|
||||
if (decodedPolicy) {
|
||||
self.securityPolicy = decodedPolicy;
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -305,19 +355,18 @@
|
|||
}
|
||||
[coder encodeObject:self.requestSerializer forKey:NSStringFromSelector(@selector(requestSerializer))];
|
||||
[coder encodeObject:self.responseSerializer forKey:NSStringFromSelector(@selector(responseSerializer))];
|
||||
[coder encodeObject:self.securityPolicy forKey:NSStringFromSelector(@selector(securityPolicy))];
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
- (instancetype)copyWithZone:(NSZone *)zone {
|
||||
AFHTTPSessionManager *HTTPClient = [[[self class] allocWithZone:zone] initWithBaseURL:self.baseURL sessionConfiguration:self.session.configuration];
|
||||
|
||||
HTTPClient.requestSerializer = [self.requestSerializer copyWithZone:zone];
|
||||
HTTPClient.responseSerializer = [self.responseSerializer copyWithZone:zone];
|
||||
|
||||
HTTPClient.securityPolicy = [self.securityPolicy copyWithZone:zone];
|
||||
return HTTPClient;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// AFNetworkReachabilityManager.h
|
||||
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
|
||||
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -24,14 +24,6 @@
|
|||
#if !TARGET_OS_WATCH
|
||||
#import <SystemConfiguration/SystemConfiguration.h>
|
||||
|
||||
#ifndef NS_DESIGNATED_INITIALIZER
|
||||
#if __has_attribute(objc_designated_initializer)
|
||||
#define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
|
||||
#else
|
||||
#define NS_DESIGNATED_INITIALIZER
|
||||
#endif
|
||||
#endif
|
||||
|
||||
typedef NS_ENUM(NSInteger, AFNetworkReachabilityStatus) {
|
||||
AFNetworkReachabilityStatusUnknown = -1,
|
||||
AFNetworkReachabilityStatusNotReachable = 0,
|
||||
|
@ -46,7 +38,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
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.
|
||||
|
||||
See Apple's Reachability Sample Code (https://developer.apple.com/library/ios/samplecode/reachability/)
|
||||
See Apple's Reachability Sample Code ( https://developer.apple.com/library/ios/samplecode/reachability/ )
|
||||
|
||||
@warning Instances of `AFNetworkReachabilityManager` must be started with `-startMonitoring` before reachability status can be determined.
|
||||
*/
|
||||
|
@ -81,6 +73,13 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
+ (instancetype)sharedManager;
|
||||
|
||||
/**
|
||||
Creates and returns a network reachability manager with the default socket address.
|
||||
|
||||
@return An initialized network reachability manager, actively monitoring the default socket address.
|
||||
*/
|
||||
+ (instancetype)manager;
|
||||
|
||||
/**
|
||||
Creates and returns a network reachability manager for the specified domain.
|
||||
|
||||
|
@ -93,7 +92,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
/**
|
||||
Creates and returns a network reachability manager for the socket address.
|
||||
|
||||
@param address The socket address (`sockaddr_in`) used to evaluate network reachability.
|
||||
@param address The socket address (`sockaddr_in6`) used to evaluate network reachability.
|
||||
|
||||
@return An initialized network reachability manager, actively monitoring the specified socket address.
|
||||
*/
|
||||
|
@ -108,6 +107,13 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability NS_DESIGNATED_INITIALIZER;
|
||||
|
||||
/**
|
||||
* Initializes an instance of a network reachability manager
|
||||
*
|
||||
* @return nil as this method is unavailable
|
||||
*/
|
||||
- (nullable instancetype)init NS_UNAVAILABLE;
|
||||
|
||||
///--------------------------------------------------
|
||||
/// @name Starting & Stopping Reachability Monitoring
|
||||
///--------------------------------------------------
|
||||
|
@ -191,8 +197,8 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@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 <SystemConfiguration/SystemConfiguration.h>` to the header prefix of the project (`Prefix.pch`).
|
||||
*/
|
||||
extern NSString * const AFNetworkingReachabilityDidChangeNotification;
|
||||
extern NSString * const AFNetworkingReachabilityNotificationStatusItem;
|
||||
FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityDidChangeNotification;
|
||||
FOUNDATION_EXPORT NSString * const AFNetworkingReachabilityNotificationStatusItem;
|
||||
|
||||
///--------------------
|
||||
/// @name Functions
|
||||
|
@ -201,7 +207,7 @@ extern NSString * const AFNetworkingReachabilityNotificationStatusItem;
|
|||
/**
|
||||
Returns a localized string representation of an `AFNetworkReachabilityStatus` value.
|
||||
*/
|
||||
extern NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status);
|
||||
FOUNDATION_EXPORT NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status);
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
#endif
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// AFNetworkReachabilityManager.m
|
||||
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
|
||||
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -33,12 +33,6 @@ NSString * const AFNetworkingReachabilityNotificationStatusItem = @"AFNetworking
|
|||
|
||||
typedef void (^AFNetworkReachabilityStatusBlock)(AFNetworkReachabilityStatus status);
|
||||
|
||||
typedef NS_ENUM(NSUInteger, AFNetworkReachabilityAssociation) {
|
||||
AFNetworkReachabilityForAddress = 1,
|
||||
AFNetworkReachabilityForAddressPair = 2,
|
||||
AFNetworkReachabilityForName = 3,
|
||||
};
|
||||
|
||||
NSString * AFStringFromNetworkReachabilityStatus(AFNetworkReachabilityStatus status) {
|
||||
switch (status) {
|
||||
case AFNetworkReachabilityStatusNotReachable:
|
||||
|
@ -76,22 +70,31 @@ static AFNetworkReachabilityStatus AFNetworkReachabilityStatusForFlags(SCNetwork
|
|||
return status;
|
||||
}
|
||||
|
||||
static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) {
|
||||
/**
|
||||
* Queue a status change notification for the main thread.
|
||||
*
|
||||
* This is done to ensure that the notifications are received in the same order
|
||||
* as they are sent. If notifications are sent directly, it is possible that
|
||||
* a queued notification (for an earlier status condition) is processed after
|
||||
* the later update, resulting in the listener being left in the wrong state.
|
||||
*/
|
||||
static void AFPostReachabilityStatusChange(SCNetworkReachabilityFlags flags, AFNetworkReachabilityStatusBlock block) {
|
||||
AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags);
|
||||
AFNetworkReachabilityStatusBlock block = (__bridge AFNetworkReachabilityStatusBlock)info;
|
||||
if (block) {
|
||||
block(status);
|
||||
}
|
||||
|
||||
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (block) {
|
||||
block(status);
|
||||
}
|
||||
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
|
||||
NSDictionary *userInfo = @{ AFNetworkingReachabilityNotificationStatusItem: @(status) };
|
||||
[notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:userInfo];
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
static void AFNetworkReachabilityCallback(SCNetworkReachabilityRef __unused target, SCNetworkReachabilityFlags flags, void *info) {
|
||||
AFPostReachabilityStatusChange(flags, (__bridge AFNetworkReachabilityStatusBlock)info);
|
||||
}
|
||||
|
||||
|
||||
static const void * AFNetworkReachabilityRetainCallback(const void *info) {
|
||||
return Block_copy(info);
|
||||
}
|
||||
|
@ -103,8 +106,7 @@ static void AFNetworkReachabilityReleaseCallback(const void *info) {
|
|||
}
|
||||
|
||||
@interface AFNetworkReachabilityManager ()
|
||||
@property (readwrite, nonatomic, strong) id networkReachability;
|
||||
@property (readwrite, nonatomic, assign) AFNetworkReachabilityAssociation networkReachabilityAssociation;
|
||||
@property (readonly, nonatomic, assign) SCNetworkReachabilityRef networkReachability;
|
||||
@property (readwrite, nonatomic, assign) AFNetworkReachabilityStatus networkReachabilityStatus;
|
||||
@property (readwrite, nonatomic, copy) AFNetworkReachabilityStatusBlock networkReachabilityStatusBlock;
|
||||
@end
|
||||
|
@ -115,12 +117,7 @@ static void AFNetworkReachabilityReleaseCallback(const void *info) {
|
|||
static AFNetworkReachabilityManager *_sharedManager = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
struct sockaddr_in address;
|
||||
bzero(&address, sizeof(address));
|
||||
address.sin_len = sizeof(address);
|
||||
address.sin_family = AF_INET;
|
||||
|
||||
_sharedManager = [self managerForAddress:&address];
|
||||
_sharedManager = [self manager];
|
||||
});
|
||||
|
||||
return _sharedManager;
|
||||
|
@ -130,24 +127,37 @@ static void AFNetworkReachabilityReleaseCallback(const void *info) {
|
|||
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, [domain UTF8String]);
|
||||
|
||||
AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
|
||||
manager.networkReachabilityAssociation = AFNetworkReachabilityForName;
|
||||
|
||||
CFRelease(reachability);
|
||||
|
||||
|
||||
return manager;
|
||||
}
|
||||
|
||||
+ (instancetype)managerForAddress:(const void *)address {
|
||||
SCNetworkReachabilityRef reachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, (const struct sockaddr *)address);
|
||||
|
||||
AFNetworkReachabilityManager *manager = [[self alloc] initWithReachability:reachability];
|
||||
manager.networkReachabilityAssociation = AFNetworkReachabilityForAddress;
|
||||
|
||||
|
||||
CFRelease(reachability);
|
||||
|
||||
return manager;
|
||||
}
|
||||
|
||||
+ (instancetype)manager
|
||||
{
|
||||
#if (defined(__IPHONE_OS_VERSION_MIN_REQUIRED) && __IPHONE_OS_VERSION_MIN_REQUIRED >= 90000) || (defined(__MAC_OS_X_VERSION_MIN_REQUIRED) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 101100)
|
||||
struct sockaddr_in6 address;
|
||||
bzero(&address, sizeof(address));
|
||||
address.sin6_len = sizeof(address);
|
||||
address.sin6_family = AF_INET6;
|
||||
#else
|
||||
struct sockaddr_in address;
|
||||
bzero(&address, sizeof(address));
|
||||
address.sin_len = sizeof(address);
|
||||
address.sin_family = AF_INET;
|
||||
#endif
|
||||
return [self managerForAddress:&address];
|
||||
}
|
||||
|
||||
- (instancetype)initWithReachability:(SCNetworkReachabilityRef)reachability {
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
|
@ -167,6 +177,10 @@ static void AFNetworkReachabilityReleaseCallback(const void *info) {
|
|||
|
||||
- (void)dealloc {
|
||||
[self stopMonitoring];
|
||||
|
||||
if (_networkReachability != NULL) {
|
||||
CFRelease(_networkReachability);
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
@ -203,33 +217,16 @@ static void AFNetworkReachabilityReleaseCallback(const void *info) {
|
|||
|
||||
};
|
||||
|
||||
id networkReachability = self.networkReachability;
|
||||
SCNetworkReachabilityContext context = {0, (__bridge void *)callback, AFNetworkReachabilityRetainCallback, AFNetworkReachabilityReleaseCallback, NULL};
|
||||
SCNetworkReachabilitySetCallback((__bridge SCNetworkReachabilityRef)networkReachability, AFNetworkReachabilityCallback, &context);
|
||||
SCNetworkReachabilityScheduleWithRunLoop((__bridge SCNetworkReachabilityRef)networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
|
||||
SCNetworkReachabilitySetCallback(self.networkReachability, AFNetworkReachabilityCallback, &context);
|
||||
SCNetworkReachabilityScheduleWithRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
|
||||
|
||||
switch (self.networkReachabilityAssociation) {
|
||||
case AFNetworkReachabilityForName:
|
||||
break;
|
||||
case AFNetworkReachabilityForAddress:
|
||||
case AFNetworkReachabilityForAddressPair:
|
||||
default: {
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
|
||||
SCNetworkReachabilityFlags flags;
|
||||
SCNetworkReachabilityGetFlags((__bridge SCNetworkReachabilityRef)networkReachability, &flags);
|
||||
AFNetworkReachabilityStatus status = AFNetworkReachabilityStatusForFlags(flags);
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
callback(status);
|
||||
|
||||
NSNotificationCenter *notificationCenter = [NSNotificationCenter defaultCenter];
|
||||
[notificationCenter postNotificationName:AFNetworkingReachabilityDidChangeNotification object:nil userInfo:@{ AFNetworkingReachabilityNotificationStatusItem: @(status) }];
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0),^{
|
||||
SCNetworkReachabilityFlags flags;
|
||||
if (SCNetworkReachabilityGetFlags(self.networkReachability, &flags)) {
|
||||
AFPostReachabilityStatusChange(flags, callback);
|
||||
}
|
||||
break;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
- (void)stopMonitoring {
|
||||
|
@ -237,7 +234,7 @@ static void AFNetworkReachabilityReleaseCallback(const void *info) {
|
|||
return;
|
||||
}
|
||||
|
||||
SCNetworkReachabilityUnscheduleFromRunLoop((__bridge SCNetworkReachabilityRef)self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
|
||||
SCNetworkReachabilityUnscheduleFromRunLoop(self.networkReachability, CFRunLoopGetMain(), kCFRunLoopCommonModes);
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <Availability.h>
|
||||
#import <TargetConditionals.h>
|
||||
|
||||
#ifndef _AFNETWORKING_
|
||||
#define _AFNETWORKING_
|
||||
|
@ -29,18 +30,12 @@
|
|||
#import "AFURLRequestSerialization.h"
|
||||
#import "AFURLResponseSerialization.h"
|
||||
#import "AFSecurityPolicy.h"
|
||||
|
||||
#if !TARGET_OS_WATCH
|
||||
#import "AFNetworkReachabilityManager.h"
|
||||
#import "AFURLConnectionOperation.h"
|
||||
#import "AFHTTPRequestOperation.h"
|
||||
#import "AFHTTPRequestOperationManager.h"
|
||||
#endif
|
||||
|
||||
#if ( ( defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1090) || \
|
||||
( defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 70000 ) || \
|
||||
TARGET_OS_WATCH )
|
||||
#import "AFURLSessionManager.h"
|
||||
#import "AFHTTPSessionManager.h"
|
||||
#endif
|
||||
|
||||
#endif /* _AFNETWORKING_ */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// AFSecurityPolicy.h
|
||||
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
|
||||
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -36,7 +36,7 @@ typedef NS_ENUM(NSUInteger, AFSSLPinningMode) {
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
@interface AFSecurityPolicy : NSObject
|
||||
@interface AFSecurityPolicy : NSObject <NSSecureCoding, NSCopying>
|
||||
|
||||
/**
|
||||
The criteria by which server trust should be evaluated against the pinned SSL certificates. Defaults to `AFSSLPinningModeNone`.
|
||||
|
@ -44,9 +44,13 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@property (readonly, nonatomic, assign) AFSSLPinningMode SSLPinningMode;
|
||||
|
||||
/**
|
||||
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. Note that if you create an array with duplicate certificates, the duplicate certificates will be removed. Note that if pinning is enabled, `evaluateServerTrust:forDomain:` will return true if any pinned certificate matches.
|
||||
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 target compiling AFNetworking. Note that if you are using AFNetworking as embedded framework, no certificates will be pinned by default. Use `certificatesInBundle` to load certificates from your target, and then create a new policy by calling `policyWithPinningMode:withPinnedCertificates`.
|
||||
|
||||
Note that if pinning is enabled, `evaluateServerTrust:forDomain:` will return true if any pinned certificate matches.
|
||||
*/
|
||||
@property (nonatomic, strong, nullable) NSArray *pinnedCertificates;
|
||||
@property (nonatomic, strong, nullable) NSSet <NSData *> *pinnedCertificates;
|
||||
|
||||
/**
|
||||
Whether or not to trust servers with an invalid or expired SSL certificates. Defaults to `NO`.
|
||||
|
@ -58,6 +62,17 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
@property (nonatomic, assign) BOOL validatesDomainName;
|
||||
|
||||
///-----------------------------------------
|
||||
/// @name Getting Certificates from the Bundle
|
||||
///-----------------------------------------
|
||||
|
||||
/**
|
||||
Returns any certificates included in the bundle. If you are using AFNetworking as an embedded framework, you must use this method to find the certificates you have included in your app bundle, and use them when creating your security policy by calling `policyWithPinningMode:withPinnedCertificates`.
|
||||
|
||||
@return The certificates included in the given bundle.
|
||||
*/
|
||||
+ (NSSet <NSData *> *)certificatesInBundle:(NSBundle *)bundle;
|
||||
|
||||
///-----------------------------------------
|
||||
/// @name Getting Specific Security Policies
|
||||
///-----------------------------------------
|
||||
|
@ -82,23 +97,20 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode;
|
||||
|
||||
/**
|
||||
Creates and returns a security policy with the specified pinning mode.
|
||||
|
||||
@param pinningMode The SSL pinning mode.
|
||||
@param pinnedCertificates The certificates to pin against.
|
||||
|
||||
@return A new security policy.
|
||||
*/
|
||||
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet <NSData *> *)pinnedCertificates;
|
||||
|
||||
///------------------------------
|
||||
/// @name Evaluating Server Trust
|
||||
///------------------------------
|
||||
|
||||
/**
|
||||
Whether or not the specified server trust should be accepted, based on the security policy.
|
||||
|
||||
This method should be used when responding to an authentication challenge from a server.
|
||||
|
||||
@param serverTrust The X.509 certificate trust of the server.
|
||||
|
||||
@return Whether or not to trust the server.
|
||||
|
||||
@warning This method has been deprecated in favor of `-evaluateServerTrust:forDomain:`.
|
||||
*/
|
||||
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust DEPRECATED_ATTRIBUTE;
|
||||
|
||||
/**
|
||||
Whether or not the specified server trust should be accepted, based on the security policy.
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// AFSecurityPolicy.m
|
||||
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
|
||||
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -23,7 +23,7 @@
|
|||
|
||||
#import <AssertMacros.h>
|
||||
|
||||
#if !TARGET_OS_IOS && !TARGET_OS_WATCH
|
||||
#if !TARGET_OS_IOS && !TARGET_OS_WATCH && !TARGET_OS_TV
|
||||
static NSData * AFSecKeyGetData(SecKeyRef key) {
|
||||
CFDataRef data = NULL;
|
||||
|
||||
|
@ -41,7 +41,7 @@ _out:
|
|||
#endif
|
||||
|
||||
static BOOL AFSecKeyIsEqualToKey(SecKeyRef key1, SecKeyRef key2) {
|
||||
#if TARGET_OS_IOS || TARGET_OS_WATCH
|
||||
#if TARGET_OS_IOS || TARGET_OS_WATCH || TARGET_OS_TV
|
||||
return [(__bridge id)key1 isEqual:(__bridge id)key2];
|
||||
#else
|
||||
return [AFSecKeyGetData(key1) isEqual:AFSecKeyGetData(key2)];
|
||||
|
@ -51,8 +51,6 @@ static BOOL AFSecKeyIsEqualToKey(SecKeyRef key1, SecKeyRef key2) {
|
|||
static id AFPublicKeyForCertificate(NSData *certificate) {
|
||||
id allowedPublicKey = nil;
|
||||
SecCertificateRef allowedCertificate;
|
||||
SecCertificateRef allowedCertificates[1];
|
||||
CFArrayRef tempCertificates = nil;
|
||||
SecPolicyRef policy = nil;
|
||||
SecTrustRef allowedTrust = nil;
|
||||
SecTrustResultType result;
|
||||
|
@ -60,11 +58,8 @@ static id AFPublicKeyForCertificate(NSData *certificate) {
|
|||
allowedCertificate = SecCertificateCreateWithData(NULL, (__bridge CFDataRef)certificate);
|
||||
__Require_Quiet(allowedCertificate != NULL, _out);
|
||||
|
||||
allowedCertificates[0] = allowedCertificate;
|
||||
tempCertificates = CFArrayCreate(NULL, (const void **)allowedCertificates, 1, NULL);
|
||||
|
||||
policy = SecPolicyCreateBasicX509();
|
||||
__Require_noErr_Quiet(SecTrustCreateWithCertificates(tempCertificates, policy, &allowedTrust), _out);
|
||||
__Require_noErr_Quiet(SecTrustCreateWithCertificates(allowedCertificate, policy, &allowedTrust), _out);
|
||||
__Require_noErr_Quiet(SecTrustEvaluate(allowedTrust, &result), _out);
|
||||
|
||||
allowedPublicKey = (__bridge_transfer id)SecTrustCopyPublicKey(allowedTrust);
|
||||
|
@ -78,10 +73,6 @@ _out:
|
|||
CFRelease(policy);
|
||||
}
|
||||
|
||||
if (tempCertificates) {
|
||||
CFRelease(tempCertificates);
|
||||
}
|
||||
|
||||
if (allowedCertificate) {
|
||||
CFRelease(allowedCertificate);
|
||||
}
|
||||
|
@ -150,25 +141,29 @@ static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
|
|||
|
||||
@interface AFSecurityPolicy()
|
||||
@property (readwrite, nonatomic, assign) AFSSLPinningMode SSLPinningMode;
|
||||
@property (readwrite, nonatomic, strong) NSArray *pinnedPublicKeys;
|
||||
@property (readwrite, nonatomic, strong) NSSet *pinnedPublicKeys;
|
||||
@end
|
||||
|
||||
@implementation AFSecurityPolicy
|
||||
|
||||
+ (NSArray *)defaultPinnedCertificates {
|
||||
static NSArray *_defaultPinnedCertificates = nil;
|
||||
+ (NSSet *)certificatesInBundle:(NSBundle *)bundle {
|
||||
NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"."];
|
||||
|
||||
NSMutableSet *certificates = [NSMutableSet setWithCapacity:[paths count]];
|
||||
for (NSString *path in paths) {
|
||||
NSData *certificateData = [NSData dataWithContentsOfFile:path];
|
||||
[certificates addObject:certificateData];
|
||||
}
|
||||
|
||||
return [NSSet setWithSet:certificates];
|
||||
}
|
||||
|
||||
+ (NSSet *)defaultPinnedCertificates {
|
||||
static NSSet *_defaultPinnedCertificates = nil;
|
||||
static dispatch_once_t onceToken;
|
||||
dispatch_once(&onceToken, ^{
|
||||
NSBundle *bundle = [NSBundle bundleForClass:[self class]];
|
||||
NSArray *paths = [bundle pathsForResourcesOfType:@"cer" inDirectory:@"."];
|
||||
|
||||
NSMutableArray *certificates = [NSMutableArray arrayWithCapacity:[paths count]];
|
||||
for (NSString *path in paths) {
|
||||
NSData *certificateData = [NSData dataWithContentsOfFile:path];
|
||||
[certificates addObject:certificateData];
|
||||
}
|
||||
|
||||
_defaultPinnedCertificates = [[NSArray alloc] initWithArray:certificates];
|
||||
_defaultPinnedCertificates = [self certificatesInBundle:bundle];
|
||||
});
|
||||
|
||||
return _defaultPinnedCertificates;
|
||||
|
@ -182,15 +177,19 @@ static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
|
|||
}
|
||||
|
||||
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode {
|
||||
return [self policyWithPinningMode:pinningMode withPinnedCertificates:[self defaultPinnedCertificates]];
|
||||
}
|
||||
|
||||
+ (instancetype)policyWithPinningMode:(AFSSLPinningMode)pinningMode withPinnedCertificates:(NSSet *)pinnedCertificates {
|
||||
AFSecurityPolicy *securityPolicy = [[self alloc] init];
|
||||
securityPolicy.SSLPinningMode = pinningMode;
|
||||
|
||||
[securityPolicy setPinnedCertificates:[self defaultPinnedCertificates]];
|
||||
[securityPolicy setPinnedCertificates:pinnedCertificates];
|
||||
|
||||
return securityPolicy;
|
||||
}
|
||||
|
||||
- (id)init {
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return nil;
|
||||
|
@ -201,11 +200,11 @@ static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
|
|||
return self;
|
||||
}
|
||||
|
||||
- (void)setPinnedCertificates:(NSArray *)pinnedCertificates {
|
||||
_pinnedCertificates = [[NSOrderedSet orderedSetWithArray:pinnedCertificates] array];
|
||||
- (void)setPinnedCertificates:(NSSet *)pinnedCertificates {
|
||||
_pinnedCertificates = pinnedCertificates;
|
||||
|
||||
if (self.pinnedCertificates) {
|
||||
NSMutableArray *mutablePinnedPublicKeys = [NSMutableArray arrayWithCapacity:[self.pinnedCertificates count]];
|
||||
NSMutableSet *mutablePinnedPublicKeys = [NSMutableSet setWithCapacity:[self.pinnedCertificates count]];
|
||||
for (NSData *certificate in self.pinnedCertificates) {
|
||||
id publicKey = AFPublicKeyForCertificate(certificate);
|
||||
if (!publicKey) {
|
||||
|
@ -213,7 +212,7 @@ static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
|
|||
}
|
||||
[mutablePinnedPublicKeys addObject:publicKey];
|
||||
}
|
||||
self.pinnedPublicKeys = [NSArray arrayWithArray:mutablePinnedPublicKeys];
|
||||
self.pinnedPublicKeys = [NSSet setWithSet:mutablePinnedPublicKeys];
|
||||
} else {
|
||||
self.pinnedPublicKeys = nil;
|
||||
}
|
||||
|
@ -221,10 +220,6 @@ static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
|
|||
|
||||
#pragma mark -
|
||||
|
||||
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust {
|
||||
return [self evaluateServerTrust:serverTrust forDomain:nil];
|
||||
}
|
||||
|
||||
- (BOOL)evaluateServerTrust:(SecTrustRef)serverTrust
|
||||
forDomain:(NSString *)domain
|
||||
{
|
||||
|
@ -251,16 +246,11 @@ static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
|
|||
SecTrustSetPolicies(serverTrust, (__bridge CFArrayRef)policies);
|
||||
|
||||
if (self.SSLPinningMode == AFSSLPinningModeNone) {
|
||||
if (self.allowInvalidCertificates || AFServerTrustIsValid(serverTrust)){
|
||||
return YES;
|
||||
} else {
|
||||
return NO;
|
||||
}
|
||||
return self.allowInvalidCertificates || AFServerTrustIsValid(serverTrust);
|
||||
} else if (!AFServerTrustIsValid(serverTrust) && !self.allowInvalidCertificates) {
|
||||
return NO;
|
||||
}
|
||||
|
||||
NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);
|
||||
switch (self.SSLPinningMode) {
|
||||
case AFSSLPinningModeNone:
|
||||
default:
|
||||
|
@ -276,13 +266,16 @@ static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
|
|||
return NO;
|
||||
}
|
||||
|
||||
NSUInteger trustedCertificateCount = 0;
|
||||
for (NSData *trustChainCertificate in serverCertificates) {
|
||||
// obtain the chain after being validated, which *should* contain the pinned certificate in the last position (if it's the Root CA)
|
||||
NSArray *serverCertificates = AFCertificateTrustChainForServerTrust(serverTrust);
|
||||
|
||||
for (NSData *trustChainCertificate in [serverCertificates reverseObjectEnumerator]) {
|
||||
if ([self.pinnedCertificates containsObject:trustChainCertificate]) {
|
||||
trustedCertificateCount++;
|
||||
return YES;
|
||||
}
|
||||
}
|
||||
return trustedCertificateCount > 0;
|
||||
|
||||
return NO;
|
||||
}
|
||||
case AFSSLPinningModePublicKey: {
|
||||
NSUInteger trustedPublicKeyCount = 0;
|
||||
|
@ -308,4 +301,44 @@ static NSArray * AFPublicKeyTrustChainForServerTrust(SecTrustRef serverTrust) {
|
|||
return [NSSet setWithObject:@"pinnedCertificates"];
|
||||
}
|
||||
|
||||
#pragma mark - NSSecureCoding
|
||||
|
||||
+ (BOOL)supportsSecureCoding {
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder {
|
||||
|
||||
self = [self init];
|
||||
if (!self) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
self.SSLPinningMode = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(SSLPinningMode))] unsignedIntegerValue];
|
||||
self.allowInvalidCertificates = [decoder decodeBoolForKey:NSStringFromSelector(@selector(allowInvalidCertificates))];
|
||||
self.validatesDomainName = [decoder decodeBoolForKey:NSStringFromSelector(@selector(validatesDomainName))];
|
||||
self.pinnedCertificates = [decoder decodeObjectOfClass:[NSArray class] forKey:NSStringFromSelector(@selector(pinnedCertificates))];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)coder {
|
||||
[coder encodeObject:[NSNumber numberWithUnsignedInteger:self.SSLPinningMode] forKey:NSStringFromSelector(@selector(SSLPinningMode))];
|
||||
[coder encodeBool:self.allowInvalidCertificates forKey:NSStringFromSelector(@selector(allowInvalidCertificates))];
|
||||
[coder encodeBool:self.validatesDomainName forKey:NSStringFromSelector(@selector(validatesDomainName))];
|
||||
[coder encodeObject:self.pinnedCertificates forKey:NSStringFromSelector(@selector(pinnedCertificates))];
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (instancetype)copyWithZone:(NSZone *)zone {
|
||||
AFSecurityPolicy *securityPolicy = [[[self class] allocWithZone:zone] init];
|
||||
securityPolicy.SSLPinningMode = self.SSLPinningMode;
|
||||
securityPolicy.allowInvalidCertificates = self.allowInvalidCertificates;
|
||||
securityPolicy.validatesDomainName = self.validatesDomainName;
|
||||
securityPolicy.pinnedCertificates = [self.pinnedCertificates copyWithZone:zone];
|
||||
|
||||
return securityPolicy;
|
||||
}
|
||||
|
||||
@end
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// AFURLRequestSerialization.h
|
||||
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
|
||||
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -20,7 +20,9 @@
|
|||
// THE SOFTWARE.
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
#if TARGET_OS_IOS
|
||||
#import <TargetConditionals.h>
|
||||
|
||||
#if TARGET_OS_IOS || TARGET_OS_TV
|
||||
#import <UIKit/UIKit.h>
|
||||
#elif TARGET_OS_WATCH
|
||||
#import <WatchKit/WatchKit.h>
|
||||
|
@ -28,6 +30,31 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
/**
|
||||
Returns a percent-escaped string following RFC 3986 for a query string key or value.
|
||||
RFC 3986 states that the following characters are "reserved" characters.
|
||||
- General Delimiters: ":", "#", "[", "]", "@", "?", "/"
|
||||
- Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
|
||||
|
||||
In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow
|
||||
query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/"
|
||||
should be percent-escaped in the query string.
|
||||
|
||||
@param string The string to be percent-escaped.
|
||||
|
||||
@return The percent-escaped string.
|
||||
*/
|
||||
FOUNDATION_EXPORT NSString * AFPercentEscapedStringFromString(NSString *string);
|
||||
|
||||
/**
|
||||
A helper method to generate encoded url query parameters for appending to the end of a URL.
|
||||
|
||||
@param parameters A dictionary of key/values to be encoded.
|
||||
|
||||
@return A url encoded query string
|
||||
*/
|
||||
FOUNDATION_EXPORT NSString * AFQueryStringFromParameters(NSDictionary *parameters);
|
||||
|
||||
/**
|
||||
The `AFURLRequestSerialization` protocol is adopted by an object that encodes parameters for a specified HTTP requests. Request serializers may encode parameters as query strings, HTTP bodies, setting the appropriate HTTP header fields as necessary.
|
||||
|
||||
|
@ -46,7 +73,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
- (nullable NSURLRequest *)requestBySerializingRequest:(NSURLRequest *)request
|
||||
withParameters:(nullable id)parameters
|
||||
error:(NSError * __nullable __autoreleasing *)error;
|
||||
error:(NSError * _Nullable __autoreleasing *)error NS_SWIFT_NOTHROW;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -127,7 +154,7 @@ typedef NS_ENUM(NSUInteger, AFHTTPRequestQueryStringSerializationStyle) {
|
|||
|
||||
@discussion To add or remove default request headers, use `setValue:forHTTPHeaderField:`.
|
||||
*/
|
||||
@property (readonly, nonatomic, strong) NSDictionary *HTTPRequestHeaders;
|
||||
@property (readonly, nonatomic, strong) NSDictionary <NSString *, NSString *> *HTTPRequestHeaders;
|
||||
|
||||
/**
|
||||
Creates and returns a serializer with default configuration.
|
||||
|
@ -161,12 +188,6 @@ forHTTPHeaderField:(NSString *)field;
|
|||
- (void)setAuthorizationHeaderFieldWithUsername:(NSString *)username
|
||||
password:(NSString *)password;
|
||||
|
||||
/**
|
||||
@deprecated This method has been deprecated. Use -setValue:forHTTPHeaderField: instead.
|
||||
*/
|
||||
- (void)setAuthorizationHeaderFieldWithToken:(NSString *)token DEPRECATED_ATTRIBUTE;
|
||||
|
||||
|
||||
/**
|
||||
Clears any existing value for the "Authorization" HTTP header.
|
||||
*/
|
||||
|
@ -179,7 +200,7 @@ forHTTPHeaderField:(NSString *)field;
|
|||
/**
|
||||
HTTP methods for which serialized requests will encode parameters as a query string. `GET`, `HEAD`, and `DELETE` by default.
|
||||
*/
|
||||
@property (nonatomic, strong) NSSet *HTTPMethodsEncodingParametersInURI;
|
||||
@property (nonatomic, strong) NSSet <NSString *> *HTTPMethodsEncodingParametersInURI;
|
||||
|
||||
/**
|
||||
Set the method of query string serialization according to one of the pre-defined styles.
|
||||
|
@ -201,13 +222,6 @@ forHTTPHeaderField:(NSString *)field;
|
|||
/// @name Creating Request Objects
|
||||
///-------------------------------
|
||||
|
||||
/**
|
||||
@deprecated This method has been deprecated. Use -requestWithMethod:URLString:parameters:error: instead.
|
||||
*/
|
||||
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
|
||||
URLString:(NSString *)URLString
|
||||
parameters:(id)parameters DEPRECATED_ATTRIBUTE;
|
||||
|
||||
/**
|
||||
Creates an `NSMutableURLRequest` object with the specified HTTP method and URL string.
|
||||
|
||||
|
@ -223,15 +237,7 @@ forHTTPHeaderField:(NSString *)field;
|
|||
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
|
||||
URLString:(NSString *)URLString
|
||||
parameters:(nullable id)parameters
|
||||
error:(NSError * __nullable __autoreleasing *)error;
|
||||
|
||||
/**
|
||||
@deprecated This method has been deprecated. Use -multipartFormRequestWithMethod:URLString:parameters:constructingBodyWithBlock:error: instead.
|
||||
*/
|
||||
- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method
|
||||
URLString:(NSString *)URLString
|
||||
parameters:(NSDictionary *)parameters
|
||||
constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block DEPRECATED_ATTRIBUTE;
|
||||
error:(NSError * _Nullable __autoreleasing *)error;
|
||||
|
||||
/**
|
||||
Creates an `NSMutableURLRequest` object with the specified HTTP method and URLString, and constructs a `multipart/form-data` HTTP body, using the specified parameters and multipart form data block. See http://www.w3.org/TR/html4/interact/forms.html#h-17.13.4.2
|
||||
|
@ -248,9 +254,9 @@ forHTTPHeaderField:(NSString *)field;
|
|||
*/
|
||||
- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method
|
||||
URLString:(NSString *)URLString
|
||||
parameters:(nullable NSDictionary *)parameters
|
||||
parameters:(nullable NSDictionary <NSString *, id> *)parameters
|
||||
constructingBodyWithBlock:(nullable void (^)(id <AFMultipartFormData> formData))block
|
||||
error:(NSError * __nullable __autoreleasing *)error;
|
||||
error:(NSError * _Nullable __autoreleasing *)error;
|
||||
|
||||
/**
|
||||
Creates an `NSMutableURLRequest` by removing the `HTTPBodyStream` from a request, and asynchronously writing its contents into the specified file, invoking the completion handler when finished.
|
||||
|
@ -265,7 +271,7 @@ forHTTPHeaderField:(NSString *)field;
|
|||
*/
|
||||
- (NSMutableURLRequest *)requestWithMultipartFormRequest:(NSURLRequest *)request
|
||||
writingStreamContentsToFile:(NSURL *)fileURL
|
||||
completionHandler:(nullable void (^)(NSError * __nullable error))handler;
|
||||
completionHandler:(nullable void (^)(NSError * _Nullable error))handler;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -289,7 +295,7 @@ forHTTPHeaderField:(NSString *)field;
|
|||
*/
|
||||
- (BOOL)appendPartWithFileURL:(NSURL *)fileURL
|
||||
name:(NSString *)name
|
||||
error:(NSError * __nullable __autoreleasing *)error;
|
||||
error:(NSError * _Nullable __autoreleasing *)error;
|
||||
|
||||
/**
|
||||
Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the encoded file data and the multipart form boundary.
|
||||
|
@ -306,7 +312,7 @@ forHTTPHeaderField:(NSString *)field;
|
|||
name:(NSString *)name
|
||||
fileName:(NSString *)fileName
|
||||
mimeType:(NSString *)mimeType
|
||||
error:(NSError * __nullable __autoreleasing *)error;
|
||||
error:(NSError * _Nullable __autoreleasing *)error;
|
||||
|
||||
/**
|
||||
Appends the HTTP header `Content-Disposition: file; filename=#{filename}; name=#{name}"` and `Content-Type: #{mimeType}`, followed by the data from the input stream and the multipart form boundary.
|
||||
|
@ -353,7 +359,7 @@ forHTTPHeaderField:(NSString *)field;
|
|||
@param headers The HTTP headers to be appended to the form data.
|
||||
@param body The data to be encoded and appended to the form data. This parameter must not be `nil`.
|
||||
*/
|
||||
- (void)appendPartWithHeaders:(nullable NSDictionary *)headers
|
||||
- (void)appendPartWithHeaders:(nullable NSDictionary <NSString *, NSString *> *)headers
|
||||
body:(NSData *)body;
|
||||
|
||||
/**
|
||||
|
@ -438,7 +444,7 @@ forHTTPHeaderField:(NSString *)field;
|
|||
`AFURLRequestSerializationErrorDomain`
|
||||
AFURLRequestSerializer errors. Error codes for `AFURLRequestSerializationErrorDomain` correspond to codes in `NSURLErrorDomain`.
|
||||
*/
|
||||
extern NSString * const AFURLRequestSerializationErrorDomain;
|
||||
FOUNDATION_EXPORT NSString * const AFURLRequestSerializationErrorDomain;
|
||||
|
||||
/**
|
||||
## User info dictionary keys
|
||||
|
@ -452,7 +458,7 @@ extern NSString * const AFURLRequestSerializationErrorDomain;
|
|||
`AFNetworkingOperationFailingURLRequestErrorKey`
|
||||
The corresponding value is an `NSURLRequest` containing the request of the operation associated with an error. This key is only present in the `AFURLRequestSerializationErrorDomain`.
|
||||
*/
|
||||
extern NSString * const AFNetworkingOperationFailingURLRequestErrorKey;
|
||||
FOUNDATION_EXPORT NSString * const AFNetworkingOperationFailingURLRequestErrorKey;
|
||||
|
||||
/**
|
||||
## Throttling Bandwidth for HTTP Request Input Streams
|
||||
|
@ -467,7 +473,7 @@ extern NSString * const AFNetworkingOperationFailingURLRequestErrorKey;
|
|||
`kAFUploadStream3GSuggestedDelay`
|
||||
Duration of delay each time a packet is read. Equal to 0.2 seconds.
|
||||
*/
|
||||
extern NSUInteger const kAFUploadStream3GSuggestedPacketSize;
|
||||
extern NSTimeInterval const kAFUploadStream3GSuggestedDelay;
|
||||
FOUNDATION_EXPORT NSUInteger const kAFUploadStream3GSuggestedPacketSize;
|
||||
FOUNDATION_EXPORT NSTimeInterval const kAFUploadStream3GSuggestedDelay;
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// AFURLRequestSerialization.m
|
||||
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
|
||||
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -21,7 +21,7 @@
|
|||
|
||||
#import "AFURLRequestSerialization.h"
|
||||
|
||||
#if __IPHONE_OS_VERSION_MIN_REQUIRED
|
||||
#if TARGET_OS_IOS || TARGET_OS_WATCH || TARGET_OS_TV
|
||||
#import <MobileCoreServices/MobileCoreServices.h>
|
||||
#else
|
||||
#import <CoreServices/CoreServices.h>
|
||||
|
@ -32,35 +32,6 @@ NSString * const AFNetworkingOperationFailingURLRequestErrorKey = @"com.alamofir
|
|||
|
||||
typedef NSString * (^AFQueryStringSerializationBlock)(NSURLRequest *request, id parameters, NSError *__autoreleasing *error);
|
||||
|
||||
static NSString * AFBase64EncodedStringFromString(NSString *string) {
|
||||
NSData *data = [NSData dataWithBytes:[string UTF8String] length:[string lengthOfBytesUsingEncoding:NSUTF8StringEncoding]];
|
||||
NSUInteger length = [data length];
|
||||
NSMutableData *mutableData = [NSMutableData dataWithLength:((length + 2) / 3) * 4];
|
||||
|
||||
uint8_t *input = (uint8_t *)[data bytes];
|
||||
uint8_t *output = (uint8_t *)[mutableData mutableBytes];
|
||||
|
||||
for (NSUInteger i = 0; i < length; i += 3) {
|
||||
NSUInteger value = 0;
|
||||
for (NSUInteger j = i; j < (i + 3); j++) {
|
||||
value <<= 8;
|
||||
if (j < length) {
|
||||
value |= (0xFF & input[j]);
|
||||
}
|
||||
}
|
||||
|
||||
static uint8_t const kAFBase64EncodingTable[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
NSUInteger idx = (i / 3) * 4;
|
||||
output[idx + 0] = kAFBase64EncodingTable[(value >> 18) & 0x3F];
|
||||
output[idx + 1] = kAFBase64EncodingTable[(value >> 12) & 0x3F];
|
||||
output[idx + 2] = (i + 1) < length ? kAFBase64EncodingTable[(value >> 6) & 0x3F] : '=';
|
||||
output[idx + 3] = (i + 2) < length ? kAFBase64EncodingTable[(value >> 0) & 0x3F] : '=';
|
||||
}
|
||||
|
||||
return [[NSString alloc] initWithData:mutableData encoding:NSASCIIStringEncoding];
|
||||
}
|
||||
|
||||
/**
|
||||
Returns a percent-escaped string following RFC 3986 for a query string key or value.
|
||||
RFC 3986 states that the following characters are "reserved" characters.
|
||||
|
@ -73,14 +44,36 @@ static NSString * AFBase64EncodedStringFromString(NSString *string) {
|
|||
- parameter string: The string to be percent-escaped.
|
||||
- returns: The percent-escaped string.
|
||||
*/
|
||||
static NSString * AFPercentEscapedStringFromString(NSString *string) {
|
||||
NSString * AFPercentEscapedStringFromString(NSString *string) {
|
||||
static NSString * const kAFCharactersGeneralDelimitersToEncode = @":#[]@"; // does not include "?" or "/" due to RFC 3986 - Section 3.4
|
||||
static NSString * const kAFCharactersSubDelimitersToEncode = @"!$&'()*+,;=";
|
||||
|
||||
NSMutableCharacterSet * allowedCharacterSet = [[NSCharacterSet URLQueryAllowedCharacterSet] mutableCopy];
|
||||
[allowedCharacterSet removeCharactersInString:[kAFCharactersGeneralDelimitersToEncode stringByAppendingString:kAFCharactersSubDelimitersToEncode]];
|
||||
|
||||
return [string stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];
|
||||
// FIXME: https://github.com/AFNetworking/AFNetworking/pull/3028
|
||||
// return [string stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];
|
||||
|
||||
static NSUInteger const batchSize = 50;
|
||||
|
||||
NSUInteger index = 0;
|
||||
NSMutableString *escaped = @"".mutableCopy;
|
||||
|
||||
while (index < string.length) {
|
||||
NSUInteger length = MIN(string.length - index, batchSize);
|
||||
NSRange range = NSMakeRange(index, length);
|
||||
|
||||
// To avoid breaking up character sequences such as 👴🏻👮🏽
|
||||
range = [string rangeOfComposedCharacterSequencesForRange:range];
|
||||
|
||||
NSString *substring = [string substringWithRange:range];
|
||||
NSString *encoded = [substring stringByAddingPercentEncodingWithAllowedCharacters:allowedCharacterSet];
|
||||
[escaped appendString:encoded];
|
||||
|
||||
index += range.length;
|
||||
}
|
||||
|
||||
return escaped;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
@ -89,14 +82,14 @@ static NSString * AFPercentEscapedStringFromString(NSString *string) {
|
|||
@property (readwrite, nonatomic, strong) id field;
|
||||
@property (readwrite, nonatomic, strong) id value;
|
||||
|
||||
- (id)initWithField:(id)field value:(id)value;
|
||||
- (instancetype)initWithField:(id)field value:(id)value;
|
||||
|
||||
- (NSString *)URLEncodedStringValue;
|
||||
@end
|
||||
|
||||
@implementation AFQueryStringPair
|
||||
|
||||
- (id)initWithField:(id)field value:(id)value {
|
||||
- (instancetype)initWithField:(id)field value:(id)value {
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return nil;
|
||||
|
@ -120,10 +113,10 @@ static NSString * AFPercentEscapedStringFromString(NSString *string) {
|
|||
|
||||
#pragma mark -
|
||||
|
||||
extern NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary);
|
||||
extern NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value);
|
||||
FOUNDATION_EXPORT NSArray * AFQueryStringPairsFromDictionary(NSDictionary *dictionary);
|
||||
FOUNDATION_EXPORT NSArray * AFQueryStringPairsFromKeyAndValue(NSString *key, id value);
|
||||
|
||||
static NSString * AFQueryStringFromParameters(NSDictionary *parameters) {
|
||||
NSString * AFQueryStringFromParameters(NSDictionary *parameters) {
|
||||
NSMutableArray *mutablePairs = [NSMutableArray array];
|
||||
for (AFQueryStringPair *pair in AFQueryStringPairsFromDictionary(parameters)) {
|
||||
[mutablePairs addObject:[pair URLEncodedStringValue]];
|
||||
|
@ -193,6 +186,7 @@ static void *AFHTTPRequestSerializerObserverContext = &AFHTTPRequestSerializerOb
|
|||
@interface AFHTTPRequestSerializer ()
|
||||
@property (readwrite, nonatomic, strong) NSMutableSet *mutableObservedChangedKeyPaths;
|
||||
@property (readwrite, nonatomic, strong) NSMutableDictionary *mutableHTTPRequestHeaders;
|
||||
@property (readwrite, nonatomic, strong) dispatch_queue_t requestHeaderModificationQueue;
|
||||
@property (readwrite, nonatomic, assign) AFHTTPRequestQueryStringSerializationStyle queryStringSerializationStyle;
|
||||
@property (readwrite, nonatomic, copy) AFQueryStringSerializationBlock queryStringSerialization;
|
||||
@end
|
||||
|
@ -212,6 +206,7 @@ static void *AFHTTPRequestSerializerObserverContext = &AFHTTPRequestSerializerOb
|
|||
self.stringEncoding = NSUTF8StringEncoding;
|
||||
|
||||
self.mutableHTTPRequestHeaders = [NSMutableDictionary dictionary];
|
||||
self.requestHeaderModificationQueue = dispatch_queue_create("requestHeaderModificationQueue", DISPATCH_QUEUE_CONCURRENT);
|
||||
|
||||
// Accept-Language HTTP Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.4
|
||||
NSMutableArray *acceptLanguagesComponents = [NSMutableArray array];
|
||||
|
@ -223,8 +218,6 @@ static void *AFHTTPRequestSerializerObserverContext = &AFHTTPRequestSerializerOb
|
|||
[self setValue:[acceptLanguagesComponents componentsJoinedByString:@", "] forHTTPHeaderField:@"Accept-Language"];
|
||||
|
||||
NSString *userAgent = nil;
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wgnu"
|
||||
#if TARGET_OS_IOS
|
||||
// User-Agent Header; see http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html#sec14.43
|
||||
userAgent = [NSString stringWithFormat:@"%@/%@ (%@; iOS %@; Scale/%0.2f)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[UIDevice currentDevice] model], [[UIDevice currentDevice] systemVersion], [[UIScreen mainScreen] scale]];
|
||||
|
@ -234,7 +227,6 @@ static void *AFHTTPRequestSerializerObserverContext = &AFHTTPRequestSerializerOb
|
|||
#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
|
||||
userAgent = [NSString stringWithFormat:@"%@/%@ (Mac OS X %@)", [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleExecutableKey] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleIdentifierKey], [[NSBundle mainBundle] infoDictionary][@"CFBundleShortVersionString"] ?: [[NSBundle mainBundle] infoDictionary][(__bridge NSString *)kCFBundleVersionKey], [[NSProcessInfo processInfo] operatingSystemVersionString]];
|
||||
#endif
|
||||
#pragma clang diagnostic pop
|
||||
if (userAgent) {
|
||||
if (![userAgent canBeConvertedToEncoding:NSASCIIStringEncoding]) {
|
||||
NSMutableString *mutableUserAgent = [userAgent mutableCopy];
|
||||
|
@ -310,32 +302,41 @@ static void *AFHTTPRequestSerializerObserverContext = &AFHTTPRequestSerializerOb
|
|||
#pragma mark -
|
||||
|
||||
- (NSDictionary *)HTTPRequestHeaders {
|
||||
return [NSDictionary dictionaryWithDictionary:self.mutableHTTPRequestHeaders];
|
||||
NSDictionary __block *value;
|
||||
dispatch_sync(self.requestHeaderModificationQueue, ^{
|
||||
value = [NSDictionary dictionaryWithDictionary:self.mutableHTTPRequestHeaders];
|
||||
});
|
||||
return value;
|
||||
}
|
||||
|
||||
- (void)setValue:(NSString *)value
|
||||
forHTTPHeaderField:(NSString *)field
|
||||
{
|
||||
[self.mutableHTTPRequestHeaders setValue:value forKey:field];
|
||||
dispatch_barrier_async(self.requestHeaderModificationQueue, ^{
|
||||
[self.mutableHTTPRequestHeaders setValue:value forKey:field];
|
||||
});
|
||||
}
|
||||
|
||||
- (NSString *)valueForHTTPHeaderField:(NSString *)field {
|
||||
return [self.mutableHTTPRequestHeaders valueForKey:field];
|
||||
NSString __block *value;
|
||||
dispatch_sync(self.requestHeaderModificationQueue, ^{
|
||||
value = [self.mutableHTTPRequestHeaders valueForKey:field];
|
||||
});
|
||||
return value;
|
||||
}
|
||||
|
||||
- (void)setAuthorizationHeaderFieldWithUsername:(NSString *)username
|
||||
password:(NSString *)password
|
||||
{
|
||||
NSString *basicAuthCredentials = [NSString stringWithFormat:@"%@:%@", username, password];
|
||||
[self setValue:[NSString stringWithFormat:@"Basic %@", AFBase64EncodedStringFromString(basicAuthCredentials)] forHTTPHeaderField:@"Authorization"];
|
||||
}
|
||||
|
||||
- (void)setAuthorizationHeaderFieldWithToken:(NSString *)token {
|
||||
[self setValue:[NSString stringWithFormat:@"Token token=\"%@\"", token] forHTTPHeaderField:@"Authorization"];
|
||||
NSData *basicAuthCredentials = [[NSString stringWithFormat:@"%@:%@", username, password] dataUsingEncoding:NSUTF8StringEncoding];
|
||||
NSString *base64AuthCredentials = [basicAuthCredentials base64EncodedStringWithOptions:(NSDataBase64EncodingOptions)0];
|
||||
[self setValue:[NSString stringWithFormat:@"Basic %@", base64AuthCredentials] forHTTPHeaderField:@"Authorization"];
|
||||
}
|
||||
|
||||
- (void)clearAuthorizationHeader {
|
||||
[self.mutableHTTPRequestHeaders removeObjectForKey:@"Authorization"];
|
||||
dispatch_barrier_async(self.requestHeaderModificationQueue, ^{
|
||||
[self.mutableHTTPRequestHeaders removeObjectForKey:@"Authorization"];
|
||||
});
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
@ -351,13 +352,6 @@ forHTTPHeaderField:(NSString *)field
|
|||
|
||||
#pragma mark -
|
||||
|
||||
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
|
||||
URLString:(NSString *)URLString
|
||||
parameters:(id)parameters
|
||||
{
|
||||
return [self requestWithMethod:method URLString:URLString parameters:parameters error:nil];
|
||||
}
|
||||
|
||||
- (NSMutableURLRequest *)requestWithMethod:(NSString *)method
|
||||
URLString:(NSString *)URLString
|
||||
parameters:(id)parameters
|
||||
|
@ -384,14 +378,6 @@ forHTTPHeaderField:(NSString *)field
|
|||
return mutableRequest;
|
||||
}
|
||||
|
||||
- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method
|
||||
URLString:(NSString *)URLString
|
||||
parameters:(NSDictionary *)parameters
|
||||
constructingBodyWithBlock:(void (^)(id <AFMultipartFormData> formData))block
|
||||
{
|
||||
return [self multipartFormRequestWithMethod:method URLString:URLString parameters:parameters constructingBodyWithBlock:block error:nil];
|
||||
}
|
||||
|
||||
- (NSMutableURLRequest *)multipartFormRequestWithMethod:(NSString *)method
|
||||
URLString:(NSString *)URLString
|
||||
parameters:(NSDictionary *)parameters
|
||||
|
@ -499,8 +485,8 @@ forHTTPHeaderField:(NSString *)field
|
|||
}
|
||||
}];
|
||||
|
||||
NSString *query = nil;
|
||||
if (parameters) {
|
||||
NSString *query = nil;
|
||||
if (self.queryStringSerialization) {
|
||||
NSError *serializationError;
|
||||
query = self.queryStringSerialization(request, parameters, &serializationError);
|
||||
|
@ -519,15 +505,21 @@ forHTTPHeaderField:(NSString *)field
|
|||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
|
||||
if ([self.HTTPMethodsEncodingParametersInURI containsObject:[[request HTTPMethod] uppercaseString]]) {
|
||||
if (query && query.length > 0) {
|
||||
mutableRequest.URL = [NSURL URLWithString:[[mutableRequest.URL absoluteString] stringByAppendingFormat:mutableRequest.URL.query ? @"&%@" : @"?%@", query]];
|
||||
} else {
|
||||
if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
|
||||
[mutableRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
|
||||
}
|
||||
[mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]];
|
||||
}
|
||||
} else {
|
||||
// #2864: an empty string is a valid x-www-form-urlencoded payload
|
||||
if (!query) {
|
||||
query = @"";
|
||||
}
|
||||
if (![mutableRequest valueForHTTPHeaderField:@"Content-Type"]) {
|
||||
[mutableRequest setValue:@"application/x-www-form-urlencoded" forHTTPHeaderField:@"Content-Type"];
|
||||
}
|
||||
[mutableRequest setHTTPBody:[query dataUsingEncoding:self.stringEncoding]];
|
||||
}
|
||||
|
||||
return mutableRequest;
|
||||
|
@ -563,28 +555,32 @@ forHTTPHeaderField:(NSString *)field
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder {
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder {
|
||||
self = [self init];
|
||||
if (!self) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
self.mutableHTTPRequestHeaders = [[decoder decodeObjectOfClass:[NSDictionary class] forKey:NSStringFromSelector(@selector(mutableHTTPRequestHeaders))] mutableCopy];
|
||||
self.queryStringSerializationStyle = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(queryStringSerializationStyle))] unsignedIntegerValue];
|
||||
self.queryStringSerializationStyle = (AFHTTPRequestQueryStringSerializationStyle)[[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(queryStringSerializationStyle))] unsignedIntegerValue];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)encodeWithCoder:(NSCoder *)coder {
|
||||
[coder encodeObject:self.mutableHTTPRequestHeaders forKey:NSStringFromSelector(@selector(mutableHTTPRequestHeaders))];
|
||||
dispatch_sync(self.requestHeaderModificationQueue, ^{
|
||||
[coder encodeObject:self.mutableHTTPRequestHeaders forKey:NSStringFromSelector(@selector(mutableHTTPRequestHeaders))];
|
||||
});
|
||||
[coder encodeInteger:self.queryStringSerializationStyle forKey:NSStringFromSelector(@selector(queryStringSerializationStyle))];
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
- (instancetype)copyWithZone:(NSZone *)zone {
|
||||
AFHTTPRequestSerializer *serializer = [[[self class] allocWithZone:zone] init];
|
||||
serializer.mutableHTTPRequestHeaders = [self.mutableHTTPRequestHeaders mutableCopyWithZone:zone];
|
||||
dispatch_sync(self.requestHeaderModificationQueue, ^{
|
||||
serializer.mutableHTTPRequestHeaders = [self.mutableHTTPRequestHeaders mutableCopyWithZone:zone];
|
||||
});
|
||||
serializer.queryStringSerializationStyle = self.queryStringSerializationStyle;
|
||||
serializer.queryStringSerialization = self.queryStringSerialization;
|
||||
|
||||
|
@ -614,7 +610,6 @@ static inline NSString * AFMultipartFormFinalBoundary(NSString *boundary) {
|
|||
}
|
||||
|
||||
static inline NSString * AFContentTypeForPathExtension(NSString *extension) {
|
||||
#ifdef __UTTYPE__
|
||||
NSString *UTI = (__bridge_transfer NSString *)UTTypeCreatePreferredIdentifierForTag(kUTTagClassFilenameExtension, (__bridge CFStringRef)extension, NULL);
|
||||
NSString *contentType = (__bridge_transfer NSString *)UTTypeCopyPreferredTagWithClass((__bridge CFStringRef)UTI, kUTTagClassMIMEType);
|
||||
if (!contentType) {
|
||||
|
@ -622,10 +617,6 @@ static inline NSString * AFContentTypeForPathExtension(NSString *extension) {
|
|||
} else {
|
||||
return contentType;
|
||||
}
|
||||
#else
|
||||
#pragma unused (extension)
|
||||
return @"application/octet-stream";
|
||||
#endif
|
||||
}
|
||||
|
||||
NSUInteger const kAFUploadStream3GSuggestedPacketSize = 1024 * 16;
|
||||
|
@ -656,7 +647,7 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
|
|||
@property (readonly, nonatomic, assign) unsigned long long contentLength;
|
||||
@property (readonly, nonatomic, assign, getter = isEmpty) BOOL empty;
|
||||
|
||||
- (id)initWithStringEncoding:(NSStringEncoding)encoding;
|
||||
- (instancetype)initWithStringEncoding:(NSStringEncoding)encoding;
|
||||
- (void)setInitialAndFinalBoundaries;
|
||||
- (void)appendHTTPBodyPart:(AFHTTPBodyPart *)bodyPart;
|
||||
@end
|
||||
|
@ -672,8 +663,8 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
|
|||
|
||||
@implementation AFStreamingMultipartFormData
|
||||
|
||||
- (id)initWithURLRequest:(NSMutableURLRequest *)urlRequest
|
||||
stringEncoding:(NSStringEncoding)encoding
|
||||
- (instancetype)initWithURLRequest:(NSMutableURLRequest *)urlRequest
|
||||
stringEncoding:(NSStringEncoding)encoding
|
||||
{
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
|
@ -856,16 +847,13 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
|
|||
@end
|
||||
|
||||
@implementation AFMultipartBodyStream
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wimplicit-atomic-properties"
|
||||
#if (defined(__IPHONE_OS_VERSION_MAX_ALLOWED) && __IPHONE_OS_VERSION_MAX_ALLOWED >= 80000) || (defined(__MAC_OS_X_VERSION_MAX_ALLOWED) && __MAC_OS_X_VERSION_MAX_ALLOWED >= 1100)
|
||||
@synthesize delegate;
|
||||
#endif
|
||||
@synthesize streamStatus;
|
||||
@synthesize streamError;
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
- (id)initWithStringEncoding:(NSStringEncoding)encoding {
|
||||
- (instancetype)initWithStringEncoding:(NSStringEncoding)encoding {
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return nil;
|
||||
|
@ -909,15 +897,13 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
|
|||
|
||||
NSInteger totalNumberOfBytesRead = 0;
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wgnu"
|
||||
while ((NSUInteger)totalNumberOfBytesRead < MIN(length, self.numberOfBytesInPacket)) {
|
||||
if (!self.currentHTTPBodyPart || ![self.currentHTTPBodyPart hasBytesAvailable]) {
|
||||
if (!(self.currentHTTPBodyPart = [self.HTTPBodyPartEnumerator nextObject])) {
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
NSUInteger maxLength = length - (NSUInteger)totalNumberOfBytesRead;
|
||||
NSUInteger maxLength = MIN(length, self.numberOfBytesInPacket) - (NSUInteger)totalNumberOfBytesRead;
|
||||
NSInteger numberOfBytesRead = [self.currentHTTPBodyPart read:&buffer[totalNumberOfBytesRead] maxLength:maxLength];
|
||||
if (numberOfBytesRead == -1) {
|
||||
self.streamError = self.currentHTTPBodyPart.inputStream.streamError;
|
||||
|
@ -931,7 +917,6 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
|
|||
}
|
||||
}
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
return totalNumberOfBytesRead;
|
||||
}
|
||||
|
@ -1008,7 +993,7 @@ NSTimeInterval const kAFUploadStream3GSuggestedDelay = 0.2;
|
|||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
-(id)copyWithZone:(NSZone *)zone {
|
||||
- (instancetype)copyWithZone:(NSZone *)zone {
|
||||
AFMultipartBodyStream *bodyStreamCopy = [[[self class] allocWithZone:zone] initWithStringEncoding:self.stringEncoding];
|
||||
|
||||
for (AFHTTPBodyPart *bodyPart in self.HTTPBodyParts) {
|
||||
|
@ -1045,7 +1030,7 @@ typedef enum {
|
|||
|
||||
@implementation AFHTTPBodyPart
|
||||
|
||||
- (id)init {
|
||||
- (instancetype)init {
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return nil;
|
||||
|
@ -1112,8 +1097,6 @@ typedef enum {
|
|||
return YES;
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wcovered-switch-default"
|
||||
switch (self.inputStream.streamStatus) {
|
||||
case NSStreamStatusNotOpen:
|
||||
case NSStreamStatusOpening:
|
||||
|
@ -1127,7 +1110,6 @@ typedef enum {
|
|||
default:
|
||||
return NO;
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
- (NSInteger)read:(uint8_t *)buffer
|
||||
|
@ -1172,11 +1154,8 @@ typedef enum {
|
|||
intoBuffer:(uint8_t *)buffer
|
||||
maxLength:(NSUInteger)length
|
||||
{
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wgnu"
|
||||
NSRange range = NSMakeRange((NSUInteger)_phaseReadOffset, MIN([data length] - ((NSUInteger)_phaseReadOffset), length));
|
||||
[data getBytes:buffer range:range];
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
_phaseReadOffset += range.length;
|
||||
|
||||
|
@ -1195,8 +1174,6 @@ typedef enum {
|
|||
return YES;
|
||||
}
|
||||
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wcovered-switch-default"
|
||||
switch (_phase) {
|
||||
case AFEncapsulationBoundaryPhase:
|
||||
_phase = AFHeaderPhase;
|
||||
|
@ -1216,14 +1193,13 @@ typedef enum {
|
|||
break;
|
||||
}
|
||||
_phaseReadOffset = 0;
|
||||
#pragma clang diagnostic pop
|
||||
|
||||
return YES;
|
||||
}
|
||||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
- (instancetype)copyWithZone:(NSZone *)zone {
|
||||
AFHTTPBodyPart *bodyPart = [[[self class] allocWithZone:zone] init];
|
||||
|
||||
bodyPart.stringEncoding = self.stringEncoding;
|
||||
|
@ -1278,7 +1254,21 @@ typedef enum {
|
|||
[mutableRequest setValue:@"application/json" forHTTPHeaderField:@"Content-Type"];
|
||||
}
|
||||
|
||||
[mutableRequest setHTTPBody:[NSJSONSerialization dataWithJSONObject:parameters options:self.writingOptions error:error]];
|
||||
if (![NSJSONSerialization isValidJSONObject:parameters]) {
|
||||
if (error) {
|
||||
NSDictionary *userInfo = @{NSLocalizedFailureReasonErrorKey: NSLocalizedStringFromTable(@"The `parameters` argument is not valid JSON.", @"AFNetworking", nil)};
|
||||
*error = [[NSError alloc] initWithDomain:AFURLRequestSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo];
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
NSData *jsonData = [NSJSONSerialization dataWithJSONObject:parameters options:self.writingOptions error:error];
|
||||
|
||||
if (!jsonData) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
[mutableRequest setHTTPBody:jsonData];
|
||||
}
|
||||
|
||||
return mutableRequest;
|
||||
|
@ -1286,7 +1276,7 @@ typedef enum {
|
|||
|
||||
#pragma mark - NSSecureCoding
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder {
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder {
|
||||
self = [super initWithCoder:decoder];
|
||||
if (!self) {
|
||||
return nil;
|
||||
|
@ -1305,7 +1295,7 @@ typedef enum {
|
|||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
- (instancetype)copyWithZone:(NSZone *)zone {
|
||||
AFJSONRequestSerializer *serializer = [super copyWithZone:zone];
|
||||
serializer.writingOptions = self.writingOptions;
|
||||
|
||||
|
@ -1357,7 +1347,13 @@ typedef enum {
|
|||
[mutableRequest setValue:@"application/x-plist" forHTTPHeaderField:@"Content-Type"];
|
||||
}
|
||||
|
||||
[mutableRequest setHTTPBody:[NSPropertyListSerialization dataWithPropertyList:parameters format:self.format options:self.writeOptions error:error]];
|
||||
NSData *plistData = [NSPropertyListSerialization dataWithPropertyList:parameters format:self.format options:self.writeOptions error:error];
|
||||
|
||||
if (!plistData) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
[mutableRequest setHTTPBody:plistData];
|
||||
}
|
||||
|
||||
return mutableRequest;
|
||||
|
@ -1365,13 +1361,13 @@ typedef enum {
|
|||
|
||||
#pragma mark - NSSecureCoding
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder {
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder {
|
||||
self = [super initWithCoder:decoder];
|
||||
if (!self) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
self.format = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(format))] unsignedIntegerValue];
|
||||
self.format = (NSPropertyListFormat)[[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(format))] unsignedIntegerValue];
|
||||
self.writeOptions = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(writeOptions))] unsignedIntegerValue];
|
||||
|
||||
return self;
|
||||
|
@ -1386,7 +1382,7 @@ typedef enum {
|
|||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
- (instancetype)copyWithZone:(NSZone *)zone {
|
||||
AFPropertyListRequestSerializer *serializer = [super copyWithZone:zone];
|
||||
serializer.format = self.format;
|
||||
serializer.writeOptions = self.writeOptions;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// AFURLResponseSerialization.h
|
||||
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
|
||||
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -42,7 +42,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
- (nullable id)responseObjectForResponse:(nullable NSURLResponse *)response
|
||||
data:(nullable NSData *)data
|
||||
error:(NSError * __nullable __autoreleasing *)error;
|
||||
error:(NSError * _Nullable __autoreleasing *)error NS_SWIFT_NOTHROW;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -57,10 +57,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
- (instancetype)init;
|
||||
|
||||
/**
|
||||
The string encoding used to serialize data received from the server, when no string encoding is specified by the response. `NSUTF8StringEncoding` by default.
|
||||
*/
|
||||
@property (nonatomic, assign) NSStringEncoding stringEncoding;
|
||||
@property (nonatomic, assign) NSStringEncoding stringEncoding DEPRECATED_MSG_ATTRIBUTE("The string encoding is never used. AFHTTPResponseSerializer only validates status codes and content types but does not try to decode the received data in any way.");
|
||||
|
||||
/**
|
||||
Creates and returns a serializer with default configuration.
|
||||
|
@ -81,7 +78,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
/**
|
||||
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.
|
||||
*/
|
||||
@property (nonatomic, copy, nullable) NSSet *acceptableContentTypes;
|
||||
@property (nonatomic, copy, nullable) NSSet <NSString *> *acceptableContentTypes;
|
||||
|
||||
/**
|
||||
Validates the specified response and data.
|
||||
|
@ -96,7 +93,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
- (BOOL)validateResponse:(nullable NSHTTPURLResponse *)response
|
||||
data:(nullable NSData *)data
|
||||
error:(NSError * __nullable __autoreleasing *)error;
|
||||
error:(NSError * _Nullable __autoreleasing *)error;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -235,7 +232,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
*/
|
||||
@interface AFImageResponseSerializer : AFHTTPResponseSerializer
|
||||
|
||||
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
|
||||
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
|
||||
/**
|
||||
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.
|
||||
*/
|
||||
|
@ -259,14 +256,14 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
/**
|
||||
The component response serializers.
|
||||
*/
|
||||
@property (readonly, nonatomic, copy) NSArray *responseSerializers;
|
||||
@property (readonly, nonatomic, copy) NSArray <id<AFURLResponseSerialization>> *responseSerializers;
|
||||
|
||||
/**
|
||||
Creates and returns a compound serializer comprised of the specified response serializers.
|
||||
|
||||
@warning Each response serializer specified must be a subclass of `AFHTTPResponseSerializer`, and response to `-validateResponse:data:error:`.
|
||||
*/
|
||||
+ (instancetype)compoundSerializerWithResponseSerializers:(NSArray *)responseSerializers;
|
||||
+ (instancetype)compoundSerializerWithResponseSerializers:(NSArray <id<AFURLResponseSerialization>> *)responseSerializers;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -286,7 +283,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
`AFURLResponseSerializationErrorDomain`
|
||||
AFURLResponseSerializer errors. Error codes for `AFURLResponseSerializationErrorDomain` correspond to codes in `NSURLErrorDomain`.
|
||||
*/
|
||||
extern NSString * const AFURLResponseSerializationErrorDomain;
|
||||
FOUNDATION_EXPORT NSString * const AFURLResponseSerializationErrorDomain;
|
||||
|
||||
/**
|
||||
## User info dictionary keys
|
||||
|
@ -304,8 +301,8 @@ extern NSString * const AFURLResponseSerializationErrorDomain;
|
|||
`AFNetworkingOperationFailingURLResponseDataErrorKey`
|
||||
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`.
|
||||
*/
|
||||
extern NSString * const AFNetworkingOperationFailingURLResponseErrorKey;
|
||||
FOUNDATION_EXPORT NSString * const AFNetworkingOperationFailingURLResponseErrorKey;
|
||||
|
||||
extern NSString * const AFNetworkingOperationFailingURLResponseDataErrorKey;
|
||||
FOUNDATION_EXPORT NSString * const AFNetworkingOperationFailingURLResponseDataErrorKey;
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// AFURLResponseSerialization.m
|
||||
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
|
||||
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -21,6 +21,8 @@
|
|||
|
||||
#import "AFURLResponseSerialization.h"
|
||||
|
||||
#import <TargetConditionals.h>
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
#import <UIKit/UIKit.h>
|
||||
#elif TARGET_OS_WATCH
|
||||
|
@ -95,8 +97,6 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
|
|||
return nil;
|
||||
}
|
||||
|
||||
self.stringEncoding = NSUTF8StringEncoding;
|
||||
|
||||
self.acceptableStatusCodes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(200, 100)];
|
||||
self.acceptableContentTypes = nil;
|
||||
|
||||
|
@ -113,7 +113,9 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
|
|||
NSError *validationError = nil;
|
||||
|
||||
if (response && [response isKindOfClass:[NSHTTPURLResponse class]]) {
|
||||
if (self.acceptableContentTypes && ![self.acceptableContentTypes containsObject:[response MIMEType]]) {
|
||||
if (self.acceptableContentTypes && ![self.acceptableContentTypes containsObject:[response MIMEType]] &&
|
||||
!([response MIMEType] == nil && [data length] == 0)) {
|
||||
|
||||
if ([data length] > 0 && [response URL]) {
|
||||
NSMutableDictionary *mutableUserInfo = [@{
|
||||
NSLocalizedDescriptionKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Request failed: unacceptable content-type: %@", @"AFNetworking", nil), [response MIMEType]],
|
||||
|
@ -171,7 +173,7 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder {
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder {
|
||||
self = [self init];
|
||||
if (!self) {
|
||||
return nil;
|
||||
|
@ -190,7 +192,7 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
|
|||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
- (instancetype)copyWithZone:(NSZone *)zone {
|
||||
AFHTTPResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
|
||||
serializer.acceptableStatusCodes = [self.acceptableStatusCodes copyWithZone:zone];
|
||||
serializer.acceptableContentTypes = [self.acceptableContentTypes copyWithZone:zone];
|
||||
|
@ -240,46 +242,26 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
|
|||
|
||||
// Workaround for behavior of Rails to return a single space for `head :ok` (a workaround for a bug in Safari), which is not interpreted as valid input by NSJSONSerialization.
|
||||
// See https://github.com/rails/rails/issues/1742
|
||||
NSStringEncoding stringEncoding = self.stringEncoding;
|
||||
if (response.textEncodingName) {
|
||||
CFStringEncoding encoding = CFStringConvertIANACharSetNameToEncoding((CFStringRef)response.textEncodingName);
|
||||
if (encoding != kCFStringEncodingInvalidId) {
|
||||
stringEncoding = CFStringConvertEncodingToNSStringEncoding(encoding);
|
||||
}
|
||||
BOOL isSpace = [data isEqualToData:[NSData dataWithBytes:" " length:1]];
|
||||
|
||||
if (data.length == 0 || isSpace) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
id responseObject = nil;
|
||||
|
||||
NSError *serializationError = nil;
|
||||
@autoreleasepool {
|
||||
NSString *responseString = [[NSString alloc] initWithData:data encoding:stringEncoding];
|
||||
if (responseString && ![responseString isEqualToString:@" "]) {
|
||||
// Workaround for a bug in NSJSONSerialization when Unicode character escape codes are used instead of the actual character
|
||||
// See http://stackoverflow.com/a/12843465/157142
|
||||
data = [responseString dataUsingEncoding:NSUTF8StringEncoding];
|
||||
|
||||
id responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];
|
||||
|
||||
if (data) {
|
||||
if ([data length] > 0) {
|
||||
responseObject = [NSJSONSerialization JSONObjectWithData:data options:self.readingOptions error:&serializationError];
|
||||
} else {
|
||||
return nil;
|
||||
}
|
||||
} else {
|
||||
NSDictionary *userInfo = @{
|
||||
NSLocalizedDescriptionKey: NSLocalizedStringFromTable(@"Data failed decoding as a UTF-8 string", @"AFNetworking", nil),
|
||||
NSLocalizedFailureReasonErrorKey: [NSString stringWithFormat:NSLocalizedStringFromTable(@"Could not decode string: %@", @"AFNetworking", nil), responseString]
|
||||
};
|
||||
|
||||
serializationError = [NSError errorWithDomain:AFURLResponseSerializationErrorDomain code:NSURLErrorCannotDecodeContentData userInfo:userInfo];
|
||||
}
|
||||
if (!responseObject)
|
||||
{
|
||||
if (error) {
|
||||
*error = AFErrorWithUnderlyingError(serializationError, *error);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (self.removesKeysWithNullValues && responseObject) {
|
||||
responseObject = AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions);
|
||||
}
|
||||
|
||||
if (error) {
|
||||
*error = AFErrorWithUnderlyingError(serializationError, *error);
|
||||
|
||||
if (self.removesKeysWithNullValues) {
|
||||
return AFJSONObjectByRemovingKeysWithNullValues(responseObject, self.readingOptions);
|
||||
}
|
||||
|
||||
return responseObject;
|
||||
|
@ -287,7 +269,7 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
|
|||
|
||||
#pragma mark - NSSecureCoding
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder {
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder {
|
||||
self = [super initWithCoder:decoder];
|
||||
if (!self) {
|
||||
return nil;
|
||||
|
@ -308,8 +290,8 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
|
|||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
AFJSONResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
|
||||
- (instancetype)copyWithZone:(NSZone *)zone {
|
||||
AFJSONResponseSerializer *serializer = [super copyWithZone:zone];
|
||||
serializer.readingOptions = self.readingOptions;
|
||||
serializer.removesKeysWithNullValues = self.removesKeysWithNullValues;
|
||||
|
||||
|
@ -399,16 +381,20 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
|
|||
NSError *serializationError = nil;
|
||||
NSXMLDocument *document = [[NSXMLDocument alloc] initWithData:data options:self.options error:&serializationError];
|
||||
|
||||
if (error) {
|
||||
*error = AFErrorWithUnderlyingError(serializationError, *error);
|
||||
if (!document)
|
||||
{
|
||||
if (error) {
|
||||
*error = AFErrorWithUnderlyingError(serializationError, *error);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
|
||||
return document;
|
||||
}
|
||||
|
||||
#pragma mark - NSSecureCoding
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder {
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder {
|
||||
self = [super initWithCoder:decoder];
|
||||
if (!self) {
|
||||
return nil;
|
||||
|
@ -427,8 +413,8 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
|
|||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
AFXMLDocumentResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
|
||||
- (instancetype)copyWithZone:(NSZone *)zone {
|
||||
AFXMLDocumentResponseSerializer *serializer = [super copyWithZone:zone];
|
||||
serializer.options = self.options;
|
||||
|
||||
return serializer;
|
||||
|
@ -479,15 +465,20 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
|
|||
}
|
||||
}
|
||||
|
||||
id responseObject;
|
||||
NSError *serializationError = nil;
|
||||
|
||||
if (data) {
|
||||
responseObject = [NSPropertyListSerialization propertyListWithData:data options:self.readOptions format:NULL error:&serializationError];
|
||||
if (!data) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
if (error) {
|
||||
*error = AFErrorWithUnderlyingError(serializationError, *error);
|
||||
|
||||
NSError *serializationError = nil;
|
||||
|
||||
id responseObject = [NSPropertyListSerialization propertyListWithData:data options:self.readOptions format:NULL error:&serializationError];
|
||||
|
||||
if (!responseObject)
|
||||
{
|
||||
if (error) {
|
||||
*error = AFErrorWithUnderlyingError(serializationError, *error);
|
||||
}
|
||||
return nil;
|
||||
}
|
||||
|
||||
return responseObject;
|
||||
|
@ -495,13 +486,13 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
|
|||
|
||||
#pragma mark - NSSecureCoding
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder {
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder {
|
||||
self = [super initWithCoder:decoder];
|
||||
if (!self) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
self.format = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(format))] unsignedIntegerValue];
|
||||
self.format = (NSPropertyListFormat)[[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(format))] unsignedIntegerValue];
|
||||
self.readOptions = [[decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(readOptions))] unsignedIntegerValue];
|
||||
|
||||
return self;
|
||||
|
@ -516,8 +507,8 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
|
|||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
AFPropertyListResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
|
||||
- (instancetype)copyWithZone:(NSZone *)zone {
|
||||
AFPropertyListResponseSerializer *serializer = [super copyWithZone:zone];
|
||||
serializer.format = self.format;
|
||||
serializer.readOptions = self.readOptions;
|
||||
|
||||
|
@ -528,8 +519,9 @@ static id AFJSONObjectByRemovingKeysWithNullValues(id JSONObject, NSJSONReadingO
|
|||
|
||||
#pragma mark -
|
||||
|
||||
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
|
||||
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
|
||||
#import <CoreGraphics/CoreGraphics.h>
|
||||
#import <UIKit/UIKit.h>
|
||||
|
||||
@interface UIImage (AFNetworkingSafeImageLoading)
|
||||
+ (UIImage *)af_safeImageWithData:(NSData *)data;
|
||||
|
@ -667,10 +659,10 @@ static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *r
|
|||
|
||||
self.acceptableContentTypes = [[NSSet alloc] initWithObjects:@"image/tiff", @"image/jpeg", @"image/gif", @"image/png", @"image/ico", @"image/x-icon", @"image/bmp", @"image/x-bmp", @"image/x-xbitmap", @"image/x-win-bitmap", nil];
|
||||
|
||||
#if TARGET_OS_IOS
|
||||
#if TARGET_OS_IOS || TARGET_OS_TV
|
||||
self.imageScale = [[UIScreen mainScreen] scale];
|
||||
self.automaticallyInflatesResponseImage = YES;
|
||||
#elif TARGET_OS_WATCH
|
||||
#elif TARGET_OS_WATCH
|
||||
self.imageScale = [[WKInterfaceDevice currentDevice] screenScale];
|
||||
self.automaticallyInflatesResponseImage = YES;
|
||||
#endif
|
||||
|
@ -690,13 +682,13 @@ static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *r
|
|||
}
|
||||
}
|
||||
|
||||
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
|
||||
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
|
||||
if (self.automaticallyInflatesResponseImage) {
|
||||
return AFInflatedImageFromResponseWithDataAtScale((NSHTTPURLResponse *)response, data, self.imageScale);
|
||||
} else {
|
||||
return AFImageWithDataAtScale(data, self.imageScale);
|
||||
}
|
||||
#elif defined(__MAC_OS_X_VERSION_MIN_REQUIRED)
|
||||
#else
|
||||
// Ensure that the image is set to it's correct pixel width and height
|
||||
NSBitmapImageRep *bitimage = [[NSBitmapImageRep alloc] initWithData:data];
|
||||
NSImage *image = [[NSImage alloc] initWithSize:NSMakeSize([bitimage pixelsWide], [bitimage pixelsHigh])];
|
||||
|
@ -710,13 +702,13 @@ static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *r
|
|||
|
||||
#pragma mark - NSSecureCoding
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder {
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder {
|
||||
self = [super initWithCoder:decoder];
|
||||
if (!self) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
|
||||
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
|
||||
NSNumber *imageScale = [decoder decodeObjectOfClass:[NSNumber class] forKey:NSStringFromSelector(@selector(imageScale))];
|
||||
#if CGFLOAT_IS_DOUBLE
|
||||
self.imageScale = [imageScale doubleValue];
|
||||
|
@ -733,7 +725,7 @@ static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *r
|
|||
- (void)encodeWithCoder:(NSCoder *)coder {
|
||||
[super encodeWithCoder:coder];
|
||||
|
||||
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
|
||||
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
|
||||
[coder encodeObject:@(self.imageScale) forKey:NSStringFromSelector(@selector(imageScale))];
|
||||
[coder encodeBool:self.automaticallyInflatesResponseImage forKey:NSStringFromSelector(@selector(automaticallyInflatesResponseImage))];
|
||||
#endif
|
||||
|
@ -741,10 +733,10 @@ static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *r
|
|||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
AFImageResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
|
||||
- (instancetype)copyWithZone:(NSZone *)zone {
|
||||
AFImageResponseSerializer *serializer = [super copyWithZone:zone];
|
||||
|
||||
#if defined(__IPHONE_OS_VERSION_MIN_REQUIRED)
|
||||
#if TARGET_OS_IOS || TARGET_OS_TV || TARGET_OS_WATCH
|
||||
serializer.imageScale = self.imageScale;
|
||||
serializer.automaticallyInflatesResponseImage = self.automaticallyInflatesResponseImage;
|
||||
#endif
|
||||
|
@ -796,7 +788,7 @@ static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *r
|
|||
|
||||
#pragma mark - NSSecureCoding
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder {
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder {
|
||||
self = [super initWithCoder:decoder];
|
||||
if (!self) {
|
||||
return nil;
|
||||
|
@ -815,8 +807,8 @@ static UIImage * AFInflatedImageFromResponseWithDataAtScale(NSHTTPURLResponse *r
|
|||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
AFCompoundResponseSerializer *serializer = [[[self class] allocWithZone:zone] init];
|
||||
- (instancetype)copyWithZone:(NSZone *)zone {
|
||||
AFCompoundResponseSerializer *serializer = [super copyWithZone:zone];
|
||||
serializer.responseSerializers = self.responseSerializers;
|
||||
|
||||
return serializer;
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// AFURLSessionManager.h
|
||||
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
|
||||
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -19,6 +19,7 @@
|
|||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
|
||||
#import <Foundation/Foundation.h>
|
||||
|
||||
#import "AFURLResponseSerialization.h"
|
||||
|
@ -28,14 +29,6 @@
|
|||
#import "AFNetworkReachabilityManager.h"
|
||||
#endif
|
||||
|
||||
#ifndef NS_DESIGNATED_INITIALIZER
|
||||
#if __has_attribute(objc_designated_initializer)
|
||||
#define NS_DESIGNATED_INITIALIZER __attribute__((objc_designated_initializer))
|
||||
#else
|
||||
#define NS_DESIGNATED_INITIALIZER
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/**
|
||||
`AFURLSessionManager` creates and manages an `NSURLSession` object based on a specified `NSURLSessionConfiguration` object, which conforms to `<NSURLSessionTaskDelegate>`, `<NSURLSessionDataDelegate>`, `<NSURLSessionDownloadDelegate>`, and `<NSURLSessionDelegate>`.
|
||||
|
||||
|
@ -58,6 +51,7 @@
|
|||
- `URLSession:willPerformHTTPRedirection:newRequest:completionHandler:`
|
||||
- `URLSession:task:didReceiveChallenge:completionHandler:`
|
||||
- `URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:`
|
||||
- `URLSession:task:needNewBodyStream:`
|
||||
- `URLSession:task:didCompleteWithError:`
|
||||
|
||||
### `NSURLSessionDataDelegate`
|
||||
|
@ -93,8 +87,6 @@
|
|||
|
||||
NS_ASSUME_NONNULL_BEGIN
|
||||
|
||||
#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) || TARGET_OS_WATCH
|
||||
|
||||
@interface AFURLSessionManager : NSObject <NSURLSessionDelegate, NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate, NSSecureCoding, NSCopying>
|
||||
|
||||
/**
|
||||
|
@ -119,7 +111,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
///-------------------------------
|
||||
|
||||
/**
|
||||
The security policy used by created request operations to evaluate server trust for secure connections. `AFURLSessionManager` uses the `defaultPolicy` unless otherwise specified.
|
||||
The security policy used by created session to evaluate server trust for secure connections. `AFURLSessionManager` uses the `defaultPolicy` unless otherwise specified.
|
||||
*/
|
||||
@property (nonatomic, strong) AFSecurityPolicy *securityPolicy;
|
||||
|
||||
|
@ -141,22 +133,22 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
/**
|
||||
The data, upload, and download tasks currently run by the managed session.
|
||||
*/
|
||||
@property (readonly, nonatomic, strong) NSArray *tasks;
|
||||
@property (readonly, nonatomic, strong) NSArray <NSURLSessionTask *> *tasks;
|
||||
|
||||
/**
|
||||
The data tasks currently run by the managed session.
|
||||
*/
|
||||
@property (readonly, nonatomic, strong) NSArray *dataTasks;
|
||||
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDataTask *> *dataTasks;
|
||||
|
||||
/**
|
||||
The upload tasks currently run by the managed session.
|
||||
*/
|
||||
@property (readonly, nonatomic, strong) NSArray *uploadTasks;
|
||||
@property (readonly, nonatomic, strong) NSArray <NSURLSessionUploadTask *> *uploadTasks;
|
||||
|
||||
/**
|
||||
The download tasks currently run by the managed session.
|
||||
*/
|
||||
@property (readonly, nonatomic, strong) NSArray *downloadTasks;
|
||||
@property (readonly, nonatomic, strong) NSArray <NSURLSessionDownloadTask *> *downloadTasks;
|
||||
|
||||
///-------------------------------
|
||||
/// @name Managing Callback Queues
|
||||
|
@ -165,20 +157,12 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
/**
|
||||
The dispatch queue for `completionBlock`. If `NULL` (default), the main queue is used.
|
||||
*/
|
||||
#if OS_OBJECT_HAVE_OBJC_SUPPORT
|
||||
@property (nonatomic, strong, nullable) dispatch_queue_t completionQueue;
|
||||
#else
|
||||
@property (nonatomic, assign, nullable) dispatch_queue_t completionQueue;
|
||||
#endif
|
||||
|
||||
/**
|
||||
The dispatch group for `completionBlock`. If `NULL` (default), a private dispatch group is used.
|
||||
*/
|
||||
#if OS_OBJECT_HAVE_OBJC_SUPPORT
|
||||
@property (nonatomic, strong, nullable) dispatch_group_t completionGroup;
|
||||
#else
|
||||
@property (nonatomic, assign, nullable) dispatch_group_t completionGroup;
|
||||
#endif
|
||||
|
||||
///---------------------------------
|
||||
/// @name Working Around System Bugs
|
||||
|
@ -224,7 +208,20 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
@param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any.
|
||||
*/
|
||||
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
|
||||
completionHandler:(nullable void (^)(NSURLResponse *response, id __nullable responseObject, NSError * __nullable error))completionHandler;
|
||||
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler DEPRECATED_ATTRIBUTE;
|
||||
|
||||
/**
|
||||
Creates an `NSURLSessionDataTask` with the specified request.
|
||||
|
||||
@param request The HTTP request for the request.
|
||||
@param uploadProgressBlock A block object to be executed when the upload progress is updated. Note this block is called on the session queue, not the main queue.
|
||||
@param downloadProgressBlock A block object to be executed when the download progress is updated. Note this block is called on the session queue, not the main queue.
|
||||
@param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any.
|
||||
*/
|
||||
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
|
||||
uploadProgress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
|
||||
downloadProgress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
|
||||
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
|
||||
|
||||
///---------------------------
|
||||
/// @name Running Upload Tasks
|
||||
|
@ -235,39 +232,39 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@param request The HTTP request for the request.
|
||||
@param fileURL A URL to the local file to be uploaded.
|
||||
@param progress A progress object monitoring the current upload progress.
|
||||
@param uploadProgressBlock A block object to be executed when the upload progress is updated. Note this block is called on the session queue, not the main queue.
|
||||
@param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any.
|
||||
|
||||
@see `attemptsToRecreateUploadTasksForBackgroundSessions`
|
||||
*/
|
||||
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
|
||||
fromFile:(NSURL *)fileURL
|
||||
progress:(NSProgress * __nullable __autoreleasing * __nullable)progress
|
||||
completionHandler:(nullable void (^)(NSURLResponse *response, id __nullable responseObject, NSError * __nullable error))completionHandler;
|
||||
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
|
||||
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
|
||||
|
||||
/**
|
||||
Creates an `NSURLSessionUploadTask` with the specified request for an HTTP body.
|
||||
|
||||
@param request The HTTP request for the request.
|
||||
@param bodyData A data object containing the HTTP body to be uploaded.
|
||||
@param progress A progress object monitoring the current upload progress.
|
||||
@param uploadProgressBlock A block object to be executed when the upload progress is updated. Note this block is called on the session queue, not the main queue.
|
||||
@param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any.
|
||||
*/
|
||||
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
|
||||
fromData:(nullable NSData *)bodyData
|
||||
progress:(NSProgress * __nullable __autoreleasing * __nullable)progress
|
||||
completionHandler:(nullable void (^)(NSURLResponse *response, id __nullable responseObject, NSError * __nullable error))completionHandler;
|
||||
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
|
||||
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
|
||||
|
||||
/**
|
||||
Creates an `NSURLSessionUploadTask` with the specified streaming request.
|
||||
|
||||
@param request The HTTP request for the request.
|
||||
@param progress A progress object monitoring the current upload progress.
|
||||
@param uploadProgressBlock A block object to be executed when the upload progress is updated. Note this block is called on the session queue, not the main queue.
|
||||
@param completionHandler A block object to be executed when the task finishes. This block has no return value and takes three arguments: the server response, the response object created by that serializer, and the error that occurred, if any.
|
||||
*/
|
||||
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
|
||||
progress:(NSProgress * __nullable __autoreleasing * __nullable)progress
|
||||
completionHandler:(nullable void (^)(NSURLResponse *response, id __nullable responseObject, NSError * __nullable error))completionHandler;
|
||||
progress:(nullable void (^)(NSProgress *uploadProgress))uploadProgressBlock
|
||||
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler;
|
||||
|
||||
///-----------------------------
|
||||
/// @name Running Download Tasks
|
||||
|
@ -277,29 +274,29 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
Creates an `NSURLSessionDownloadTask` with the specified request.
|
||||
|
||||
@param request The HTTP request for the request.
|
||||
@param progress A progress object monitoring the current download progress.
|
||||
@param downloadProgressBlock A block object to be executed when the download progress is updated. Note this block is called on the session queue, not the main queue.
|
||||
@param destination A block object to be executed in order to determine the destination of the downloaded file. This block takes two arguments, the target path & the server response, and returns the desired file URL of the resulting download. The temporary file used during the download will be automatically deleted after being moved to the returned URL.
|
||||
@param completionHandler A block to be executed when a task finishes. This block has no return value and takes three arguments: the server response, the path of the downloaded file, and the error describing the network or parsing error that occurred, if any.
|
||||
|
||||
@warning If using a background `NSURLSessionConfiguration` on iOS, these blocks will be lost when the app is terminated. Background sessions may prefer to use `-setDownloadTaskDidFinishDownloadingBlock:` to specify the URL for saving the downloaded file, rather than the destination block of this method.
|
||||
*/
|
||||
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
|
||||
progress:(NSProgress * __nullable __autoreleasing * __nullable)progress
|
||||
progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
|
||||
destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
|
||||
completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * __nullable filePath, NSError * __nullable error))completionHandler;
|
||||
completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler;
|
||||
|
||||
/**
|
||||
Creates an `NSURLSessionDownloadTask` with the specified resume data.
|
||||
|
||||
@param resumeData The data used to resume downloading.
|
||||
@param progress A progress object monitoring the current download progress.
|
||||
@param downloadProgressBlock A block object to be executed when the download progress is updated. Note this block is called on the session queue, not the main queue.
|
||||
@param destination A block object to be executed in order to determine the destination of the downloaded file. This block takes two arguments, the target path & the server response, and returns the desired file URL of the resulting download. The temporary file used during the download will be automatically deleted after being moved to the returned URL.
|
||||
@param completionHandler A block to be executed when a task finishes. This block has no return value and takes three arguments: the server response, the path of the downloaded file, and the error describing the network or parsing error that occurred, if any.
|
||||
*/
|
||||
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData
|
||||
progress:(NSProgress * __nullable __autoreleasing * __nullable)progress
|
||||
progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock
|
||||
destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
|
||||
completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * __nullable filePath, NSError * __nullable error))completionHandler;
|
||||
completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler;
|
||||
|
||||
///---------------------------------
|
||||
/// @name Getting Progress for Tasks
|
||||
|
@ -308,20 +305,20 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
/**
|
||||
Returns the upload progress of the specified task.
|
||||
|
||||
@param uploadTask The session upload task. Must not be `nil`.
|
||||
@param task The session task. Must not be `nil`.
|
||||
|
||||
@return An `NSProgress` object reporting the upload progress of a task, or `nil` if the progress is unavailable.
|
||||
*/
|
||||
- (nullable NSProgress *)uploadProgressForTask:(NSURLSessionUploadTask *)uploadTask;
|
||||
- (nullable NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task;
|
||||
|
||||
/**
|
||||
Returns the download progress of the specified task.
|
||||
|
||||
@param downloadTask The session download task. Must not be `nil`.
|
||||
@param task The session task. Must not be `nil`.
|
||||
|
||||
@return An `NSProgress` object reporting the download progress of a task, or `nil` if the progress is unavailable.
|
||||
*/
|
||||
- (nullable NSProgress *)downloadProgressForTask:(NSURLSessionDownloadTask *)downloadTask;
|
||||
- (nullable NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task;
|
||||
|
||||
///-----------------------------------------
|
||||
/// @name Setting Session Delegate Callbacks
|
||||
|
@ -339,7 +336,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@param block A block object to be executed when a connection level authentication challenge has occurred. The block returns the disposition of the authentication challenge, and takes three arguments: the session, the authentication challenge, and a pointer to the credential that should be used to resolve the challenge.
|
||||
*/
|
||||
- (void)setSessionDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __nullable __autoreleasing * __nullable credential))block;
|
||||
- (void)setSessionDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block;
|
||||
|
||||
///--------------------------------------
|
||||
/// @name Setting Task Delegate Callbacks
|
||||
|
@ -364,7 +361,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@param block A block object to be executed when a session task has received a request specific authentication challenge. The block returns the disposition of the authentication challenge, and takes four arguments: the session, the task, the authentication challenge, and a pointer to the credential that should be used to resolve the challenge.
|
||||
*/
|
||||
- (void)setTaskDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * __nullable __autoreleasing * __nullable credential))block;
|
||||
- (void)setTaskDidReceiveAuthenticationChallengeBlock:(nullable NSURLSessionAuthChallengeDisposition (^)(NSURLSession *session, NSURLSessionTask *task, NSURLAuthenticationChallenge *challenge, NSURLCredential * _Nullable __autoreleasing * _Nullable credential))block;
|
||||
|
||||
/**
|
||||
Sets a block to be executed periodically to track upload progress, as handled by the `NSURLSessionTaskDelegate` method `URLSession:task:didSendBodyData:totalBytesSent:totalBytesExpectedToSend:`.
|
||||
|
@ -378,7 +375,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@param block A block object to be executed when a session task is completed. The block has no return value, and takes three arguments: the session, the task, and any error that occurred in the process of executing the task.
|
||||
*/
|
||||
- (void)setTaskDidCompleteBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, NSError * __nullable error))block;
|
||||
- (void)setTaskDidCompleteBlock:(nullable void (^)(NSURLSession *session, NSURLSessionTask *task, NSError * _Nullable error))block;
|
||||
|
||||
///-------------------------------------------
|
||||
/// @name Setting Data Task Delegate Callbacks
|
||||
|
@ -428,7 +425,7 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@param block A block object to be executed when a download task has completed. The block returns the URL the download should be moved to, and takes three arguments: the session, the download task, and the temporary location of the downloaded file. If the file manager encounters an error while attempting to move the temporary file to the destination, an `AFURLSessionDownloadTaskDidFailToMoveFileNotification` will be posted, with the download task as its object, and the user info of the error.
|
||||
*/
|
||||
- (void)setDownloadTaskDidFinishDownloadingBlock:(nullable NSURL * (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location))block;
|
||||
- (void)setDownloadTaskDidFinishDownloadingBlock:(nullable NSURL * _Nullable (^)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location))block;
|
||||
|
||||
/**
|
||||
Sets a block to be executed periodically to track download progress, as handled by the `NSURLSessionDownloadDelegate` method `URLSession:downloadTask:didWriteData:totalBytesWritten:totalBytesWritten:totalBytesExpectedToWrite:`.
|
||||
|
@ -446,109 +443,58 @@ NS_ASSUME_NONNULL_BEGIN
|
|||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
||||
///--------------------
|
||||
/// @name Notifications
|
||||
///--------------------
|
||||
|
||||
/**
|
||||
Posted when a task begins executing.
|
||||
|
||||
@deprecated Use `AFNetworkingTaskDidResumeNotification` instead.
|
||||
*/
|
||||
extern NSString * const AFNetworkingTaskDidStartNotification DEPRECATED_ATTRIBUTE;
|
||||
|
||||
/**
|
||||
Posted when a task resumes.
|
||||
*/
|
||||
extern NSString * const AFNetworkingTaskDidResumeNotification;
|
||||
|
||||
/**
|
||||
Posted when a task finishes executing. Includes a userInfo dictionary with additional information about the task.
|
||||
|
||||
@deprecated Use `AFNetworkingTaskDidCompleteNotification` instead.
|
||||
*/
|
||||
extern NSString * const AFNetworkingTaskDidFinishNotification DEPRECATED_ATTRIBUTE;
|
||||
FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidResumeNotification;
|
||||
|
||||
/**
|
||||
Posted when a task finishes executing. Includes a userInfo dictionary with additional information about the task.
|
||||
*/
|
||||
extern NSString * const AFNetworkingTaskDidCompleteNotification;
|
||||
FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteNotification;
|
||||
|
||||
/**
|
||||
Posted when a task suspends its execution.
|
||||
*/
|
||||
extern NSString * const AFNetworkingTaskDidSuspendNotification;
|
||||
FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidSuspendNotification;
|
||||
|
||||
/**
|
||||
Posted when a session is invalidated.
|
||||
*/
|
||||
extern NSString * const AFURLSessionDidInvalidateNotification;
|
||||
FOUNDATION_EXPORT NSString * const AFURLSessionDidInvalidateNotification;
|
||||
|
||||
/**
|
||||
Posted when a session download task encountered an error when moving the temporary download file to a specified destination.
|
||||
*/
|
||||
extern NSString * const AFURLSessionDownloadTaskDidFailToMoveFileNotification;
|
||||
FOUNDATION_EXPORT NSString * const AFURLSessionDownloadTaskDidFailToMoveFileNotification;
|
||||
|
||||
/**
|
||||
The raw response data of the task. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if response data exists for the task.
|
||||
|
||||
@deprecated Use `AFNetworkingTaskDidCompleteResponseDataKey` instead.
|
||||
The raw response data of the task. Included in the userInfo dictionary of the `AFNetworkingTaskDidCompleteNotification` if response data exists for the task.
|
||||
*/
|
||||
extern NSString * const AFNetworkingTaskDidFinishResponseDataKey DEPRECATED_ATTRIBUTE;
|
||||
FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteResponseDataKey;
|
||||
|
||||
/**
|
||||
The raw response data of the task. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if response data exists for the task.
|
||||
The serialized response object of the task. Included in the userInfo dictionary of the `AFNetworkingTaskDidCompleteNotification` if the response was serialized.
|
||||
*/
|
||||
extern NSString * const AFNetworkingTaskDidCompleteResponseDataKey;
|
||||
FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteSerializedResponseKey;
|
||||
|
||||
/**
|
||||
The serialized response object of the task. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if the response was serialized.
|
||||
|
||||
@deprecated Use `AFNetworkingTaskDidCompleteSerializedResponseKey` instead.
|
||||
The response serializer used to serialize the response. Included in the userInfo dictionary of the `AFNetworkingTaskDidCompleteNotification` if the task has an associated response serializer.
|
||||
*/
|
||||
extern NSString * const AFNetworkingTaskDidFinishSerializedResponseKey DEPRECATED_ATTRIBUTE;
|
||||
FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteResponseSerializerKey;
|
||||
|
||||
/**
|
||||
The serialized response object of the task. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if the response was serialized.
|
||||
The file path associated with the download task. Included in the userInfo dictionary of the `AFNetworkingTaskDidCompleteNotification` if an the response data has been stored directly to disk.
|
||||
*/
|
||||
extern NSString * const AFNetworkingTaskDidCompleteSerializedResponseKey;
|
||||
FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteAssetPathKey;
|
||||
|
||||
/**
|
||||
The response serializer used to serialize the response. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if the task has an associated response serializer.
|
||||
|
||||
@deprecated Use `AFNetworkingTaskDidCompleteResponseSerializerKey` instead.
|
||||
Any error associated with the task, or the serialization of the response. Included in the userInfo dictionary of the `AFNetworkingTaskDidCompleteNotification` if an error exists.
|
||||
*/
|
||||
extern NSString * const AFNetworkingTaskDidFinishResponseSerializerKey DEPRECATED_ATTRIBUTE;
|
||||
|
||||
/**
|
||||
The response serializer used to serialize the response. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if the task has an associated response serializer.
|
||||
*/
|
||||
extern NSString * const AFNetworkingTaskDidCompleteResponseSerializerKey;
|
||||
|
||||
/**
|
||||
The file path associated with the download task. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if an the response data has been stored directly to disk.
|
||||
|
||||
@deprecated Use `AFNetworkingTaskDidCompleteAssetPathKey` instead.
|
||||
*/
|
||||
extern NSString * const AFNetworkingTaskDidFinishAssetPathKey DEPRECATED_ATTRIBUTE;
|
||||
|
||||
/**
|
||||
The file path associated with the download task. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if an the response data has been stored directly to disk.
|
||||
*/
|
||||
extern NSString * const AFNetworkingTaskDidCompleteAssetPathKey;
|
||||
|
||||
/**
|
||||
Any error associated with the task, or the serialization of the response. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if an error exists.
|
||||
|
||||
@deprecated Use `AFNetworkingTaskDidCompleteErrorKey` instead.
|
||||
*/
|
||||
extern NSString * const AFNetworkingTaskDidFinishErrorKey DEPRECATED_ATTRIBUTE;
|
||||
|
||||
/**
|
||||
Any error associated with the task, or the serialization of the response. Included in the userInfo dictionary of the `AFNetworkingTaskDidFinishNotification` if an error exists.
|
||||
*/
|
||||
extern NSString * const AFNetworkingTaskDidCompleteErrorKey;
|
||||
FOUNDATION_EXPORT NSString * const AFNetworkingTaskDidCompleteErrorKey;
|
||||
|
||||
NS_ASSUME_NONNULL_END
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
// AFURLSessionManager.m
|
||||
// Copyright (c) 2011–2015 Alamofire Software Foundation (http://alamofire.org/)
|
||||
// Copyright (c) 2011–2016 Alamofire Software Foundation ( http://alamofire.org/ )
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -22,7 +22,11 @@
|
|||
#import "AFURLSessionManager.h"
|
||||
#import <objc/runtime.h>
|
||||
|
||||
#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)
|
||||
#ifndef NSFoundationVersionNumber_iOS_8_0
|
||||
#define NSFoundationVersionNumber_With_Fixed_5871104061079552_bug 1140.11
|
||||
#else
|
||||
#define NSFoundationVersionNumber_With_Fixed_5871104061079552_bug NSFoundationVersionNumber_iOS_8_0
|
||||
#endif
|
||||
|
||||
static dispatch_queue_t url_session_manager_creation_queue() {
|
||||
static dispatch_queue_t af_url_session_manager_creation_queue;
|
||||
|
@ -34,6 +38,17 @@ static dispatch_queue_t url_session_manager_creation_queue() {
|
|||
return af_url_session_manager_creation_queue;
|
||||
}
|
||||
|
||||
static void url_session_manager_create_task_safely(dispatch_block_t block) {
|
||||
if (NSFoundationVersionNumber < NSFoundationVersionNumber_With_Fixed_5871104061079552_bug) {
|
||||
// Fix of bug
|
||||
// Open Radar:http://openradar.appspot.com/radar?id=5871104061079552 (status: Fixed in iOS8)
|
||||
// Issue about:https://github.com/AFNetworking/AFNetworking/issues/2093
|
||||
dispatch_sync(url_session_manager_creation_queue(), block);
|
||||
} else {
|
||||
block();
|
||||
}
|
||||
}
|
||||
|
||||
static dispatch_queue_t url_session_manager_processing_queue() {
|
||||
static dispatch_queue_t af_url_session_manager_processing_queue;
|
||||
static dispatch_once_t onceToken;
|
||||
|
@ -60,27 +75,16 @@ NSString * const AFNetworkingTaskDidSuspendNotification = @"com.alamofire.networ
|
|||
NSString * const AFURLSessionDidInvalidateNotification = @"com.alamofire.networking.session.invalidate";
|
||||
NSString * const AFURLSessionDownloadTaskDidFailToMoveFileNotification = @"com.alamofire.networking.session.download.file-manager-error";
|
||||
|
||||
NSString * const AFNetworkingTaskDidStartNotification = @"com.alamofire.networking.task.resume"; // Deprecated
|
||||
NSString * const AFNetworkingTaskDidFinishNotification = @"com.alamofire.networking.task.complete"; // Deprecated
|
||||
|
||||
NSString * const AFNetworkingTaskDidCompleteSerializedResponseKey = @"com.alamofire.networking.task.complete.serializedresponse";
|
||||
NSString * const AFNetworkingTaskDidCompleteResponseSerializerKey = @"com.alamofire.networking.task.complete.responseserializer";
|
||||
NSString * const AFNetworkingTaskDidCompleteResponseDataKey = @"com.alamofire.networking.complete.finish.responsedata";
|
||||
NSString * const AFNetworkingTaskDidCompleteErrorKey = @"com.alamofire.networking.task.complete.error";
|
||||
NSString * const AFNetworkingTaskDidCompleteAssetPathKey = @"com.alamofire.networking.task.complete.assetpath";
|
||||
|
||||
NSString * const AFNetworkingTaskDidFinishSerializedResponseKey = @"com.alamofire.networking.task.complete.serializedresponse"; // Deprecated
|
||||
NSString * const AFNetworkingTaskDidFinishResponseSerializerKey = @"com.alamofire.networking.task.complete.responseserializer"; // Deprecated
|
||||
NSString * const AFNetworkingTaskDidFinishResponseDataKey = @"com.alamofire.networking.complete.finish.responsedata"; // Deprecated
|
||||
NSString * const AFNetworkingTaskDidFinishErrorKey = @"com.alamofire.networking.task.complete.error"; // Deprecated
|
||||
NSString * const AFNetworkingTaskDidFinishAssetPathKey = @"com.alamofire.networking.task.complete.assetpath"; // Deprecated
|
||||
|
||||
static NSString * const AFURLSessionManagerLockName = @"com.alamofire.networking.session.manager.lock";
|
||||
|
||||
static NSUInteger const AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask = 3;
|
||||
|
||||
static void * AFTaskStateChangedContext = &AFTaskStateChangedContext;
|
||||
|
||||
typedef void (^AFURLSessionDidBecomeInvalidBlock)(NSURLSession *session, NSError *error);
|
||||
typedef NSURLSessionAuthChallengeDisposition (^AFURLSessionDidReceiveAuthenticationChallengeBlock)(NSURLSession *session, NSURLAuthenticationChallenge *challenge, NSURLCredential * __autoreleasing *credential);
|
||||
|
||||
|
@ -100,53 +104,89 @@ typedef NSCachedURLResponse * (^AFURLSessionDataTaskWillCacheResponseBlock)(NSUR
|
|||
typedef NSURL * (^AFURLSessionDownloadTaskDidFinishDownloadingBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, NSURL *location);
|
||||
typedef void (^AFURLSessionDownloadTaskDidWriteDataBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t bytesWritten, int64_t totalBytesWritten, int64_t totalBytesExpectedToWrite);
|
||||
typedef void (^AFURLSessionDownloadTaskDidResumeBlock)(NSURLSession *session, NSURLSessionDownloadTask *downloadTask, int64_t fileOffset, int64_t expectedTotalBytes);
|
||||
typedef void (^AFURLSessionTaskProgressBlock)(NSProgress *);
|
||||
|
||||
typedef void (^AFURLSessionTaskCompletionHandler)(NSURLResponse *response, id responseObject, NSError *error);
|
||||
|
||||
|
||||
#pragma mark -
|
||||
|
||||
@interface AFURLSessionManagerTaskDelegate : NSObject <NSURLSessionTaskDelegate, NSURLSessionDataDelegate, NSURLSessionDownloadDelegate>
|
||||
- (instancetype)initWithTask:(NSURLSessionTask *)task;
|
||||
@property (nonatomic, weak) AFURLSessionManager *manager;
|
||||
@property (nonatomic, strong) NSMutableData *mutableData;
|
||||
@property (nonatomic, strong) NSProgress *progress;
|
||||
@property (nonatomic, strong) NSProgress *uploadProgress;
|
||||
@property (nonatomic, strong) NSProgress *downloadProgress;
|
||||
@property (nonatomic, copy) NSURL *downloadFileURL;
|
||||
@property (nonatomic, copy) AFURLSessionDownloadTaskDidFinishDownloadingBlock downloadTaskDidFinishDownloading;
|
||||
@property (nonatomic, copy) AFURLSessionTaskProgressBlock uploadProgressBlock;
|
||||
@property (nonatomic, copy) AFURLSessionTaskProgressBlock downloadProgressBlock;
|
||||
@property (nonatomic, copy) AFURLSessionTaskCompletionHandler completionHandler;
|
||||
@end
|
||||
|
||||
@implementation AFURLSessionManagerTaskDelegate
|
||||
|
||||
- (instancetype)init {
|
||||
- (instancetype)initWithTask:(NSURLSessionTask *)task {
|
||||
self = [super init];
|
||||
if (!self) {
|
||||
return nil;
|
||||
}
|
||||
|
||||
self.mutableData = [NSMutableData data];
|
||||
|
||||
self.progress = [NSProgress progressWithTotalUnitCount:0];
|
||||
|
||||
|
||||
_mutableData = [NSMutableData data];
|
||||
_uploadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
|
||||
_downloadProgress = [[NSProgress alloc] initWithParent:nil userInfo:nil];
|
||||
|
||||
__weak __typeof__(task) weakTask = task;
|
||||
for (NSProgress *progress in @[ _uploadProgress, _downloadProgress ])
|
||||
{
|
||||
progress.totalUnitCount = NSURLSessionTransferSizeUnknown;
|
||||
progress.cancellable = YES;
|
||||
progress.cancellationHandler = ^{
|
||||
[weakTask cancel];
|
||||
};
|
||||
progress.pausable = YES;
|
||||
progress.pausingHandler = ^{
|
||||
[weakTask suspend];
|
||||
};
|
||||
if ([progress respondsToSelector:@selector(setResumingHandler:)]) {
|
||||
progress.resumingHandler = ^{
|
||||
[weakTask resume];
|
||||
};
|
||||
}
|
||||
[progress addObserver:self
|
||||
forKeyPath:NSStringFromSelector(@selector(fractionCompleted))
|
||||
options:NSKeyValueObservingOptionNew
|
||||
context:NULL];
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)dealloc {
|
||||
[self.downloadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))];
|
||||
[self.uploadProgress removeObserver:self forKeyPath:NSStringFromSelector(@selector(fractionCompleted))];
|
||||
}
|
||||
|
||||
#pragma mark - NSProgress Tracking
|
||||
|
||||
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context {
|
||||
if ([object isEqual:self.downloadProgress]) {
|
||||
if (self.downloadProgressBlock) {
|
||||
self.downloadProgressBlock(object);
|
||||
}
|
||||
}
|
||||
else if ([object isEqual:self.uploadProgress]) {
|
||||
if (self.uploadProgressBlock) {
|
||||
self.uploadProgressBlock(object);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark - NSURLSessionTaskDelegate
|
||||
|
||||
- (void)URLSession:(__unused NSURLSession *)session
|
||||
task:(__unused NSURLSessionTask *)task
|
||||
didSendBodyData:(__unused int64_t)bytesSent
|
||||
totalBytesSent:(int64_t)totalBytesSent
|
||||
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
|
||||
{
|
||||
self.progress.totalUnitCount = totalBytesExpectedToSend;
|
||||
self.progress.completedUnitCount = totalBytesSent;
|
||||
}
|
||||
|
||||
- (void)URLSession:(__unused NSURLSession *)session
|
||||
task:(NSURLSessionTask *)task
|
||||
didCompleteWithError:(NSError *)error
|
||||
{
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wgnu"
|
||||
__strong AFURLSessionManager *manager = self.manager;
|
||||
|
||||
__block id responseObject = nil;
|
||||
|
@ -208,57 +248,66 @@ didCompleteWithError:(NSError *)error
|
|||
});
|
||||
});
|
||||
}
|
||||
#pragma clang diagnostic pop
|
||||
}
|
||||
|
||||
#pragma mark - NSURLSessionDataTaskDelegate
|
||||
#pragma mark - NSURLSessionDataDelegate
|
||||
|
||||
- (void)URLSession:(__unused NSURLSession *)session
|
||||
dataTask:(__unused NSURLSessionDataTask *)dataTask
|
||||
didReceiveData:(NSData *)data
|
||||
{
|
||||
self.downloadProgress.totalUnitCount = dataTask.countOfBytesExpectedToReceive;
|
||||
self.downloadProgress.completedUnitCount = dataTask.countOfBytesReceived;
|
||||
|
||||
[self.mutableData appendData:data];
|
||||
}
|
||||
|
||||
#pragma mark - NSURLSessionDownloadTaskDelegate
|
||||
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
|
||||
didSendBodyData:(int64_t)bytesSent
|
||||
totalBytesSent:(int64_t)totalBytesSent
|
||||
totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend{
|
||||
|
||||
self.uploadProgress.totalUnitCount = task.countOfBytesExpectedToSend;
|
||||
self.uploadProgress.completedUnitCount = task.countOfBytesSent;
|
||||
}
|
||||
|
||||
#pragma mark - NSURLSessionDownloadDelegate
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
|
||||
didWriteData:(int64_t)bytesWritten
|
||||
totalBytesWritten:(int64_t)totalBytesWritten
|
||||
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite{
|
||||
|
||||
self.downloadProgress.totalUnitCount = totalBytesExpectedToWrite;
|
||||
self.downloadProgress.completedUnitCount = totalBytesWritten;
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask
|
||||
didResumeAtOffset:(int64_t)fileOffset
|
||||
expectedTotalBytes:(int64_t)expectedTotalBytes{
|
||||
|
||||
self.downloadProgress.totalUnitCount = expectedTotalBytes;
|
||||
self.downloadProgress.completedUnitCount = fileOffset;
|
||||
}
|
||||
|
||||
- (void)URLSession:(NSURLSession *)session
|
||||
downloadTask:(NSURLSessionDownloadTask *)downloadTask
|
||||
didFinishDownloadingToURL:(NSURL *)location
|
||||
{
|
||||
NSError *fileManagerError = nil;
|
||||
self.downloadFileURL = nil;
|
||||
|
||||
if (self.downloadTaskDidFinishDownloading) {
|
||||
self.downloadFileURL = self.downloadTaskDidFinishDownloading(session, downloadTask, location);
|
||||
if (self.downloadFileURL) {
|
||||
[[NSFileManager defaultManager] moveItemAtURL:location toURL:self.downloadFileURL error:&fileManagerError];
|
||||
NSError *fileManagerError = nil;
|
||||
|
||||
if (fileManagerError) {
|
||||
if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:self.downloadFileURL error:&fileManagerError]) {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:fileManagerError.userInfo];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)URLSession:(__unused NSURLSession *)session
|
||||
downloadTask:(__unused NSURLSessionDownloadTask *)downloadTask
|
||||
didWriteData:(__unused int64_t)bytesWritten
|
||||
totalBytesWritten:(int64_t)totalBytesWritten
|
||||
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
|
||||
{
|
||||
self.progress.totalUnitCount = totalBytesExpectedToWrite;
|
||||
self.progress.completedUnitCount = totalBytesWritten;
|
||||
}
|
||||
|
||||
- (void)URLSession:(__unused NSURLSession *)session
|
||||
downloadTask:(__unused NSURLSessionDownloadTask *)downloadTask
|
||||
didResumeAtOffset:(int64_t)fileOffset
|
||||
expectedTotalBytes:(int64_t)expectedTotalBytes {
|
||||
self.progress.totalUnitCount = expectedTotalBytes;
|
||||
self.progress.completedUnitCount = fileOffset;
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#pragma mark -
|
||||
|
@ -272,14 +321,14 @@ expectedTotalBytes:(int64_t)expectedTotalBytes {
|
|||
* - https://github.com/AFNetworking/AFNetworking/pull/2702
|
||||
*/
|
||||
|
||||
static inline void af_swizzleSelector(Class class, SEL originalSelector, SEL swizzledSelector) {
|
||||
Method originalMethod = class_getInstanceMethod(class, originalSelector);
|
||||
Method swizzledMethod = class_getInstanceMethod(class, swizzledSelector);
|
||||
static inline void af_swizzleSelector(Class theClass, SEL originalSelector, SEL swizzledSelector) {
|
||||
Method originalMethod = class_getInstanceMethod(theClass, originalSelector);
|
||||
Method swizzledMethod = class_getInstanceMethod(theClass, swizzledSelector);
|
||||
method_exchangeImplementations(originalMethod, swizzledMethod);
|
||||
}
|
||||
|
||||
static inline BOOL af_addMethod(Class class, SEL selector, Method method) {
|
||||
return class_addMethod(class, selector, method_getImplementation(method), method_getTypeEncoding(method));
|
||||
static inline BOOL af_addMethod(Class theClass, SEL selector, Method method) {
|
||||
return class_addMethod(theClass, selector, method_getImplementation(method), method_getTypeEncoding(method));
|
||||
}
|
||||
|
||||
static NSString * const AFNSURLSessionTaskDidResumeNotification = @"com.alamofire.networking.nsurlsessiontask.resume";
|
||||
|
@ -324,11 +373,13 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|||
7) If the current class implementation of `resume` is not equal to the super class implementation of `resume` AND the current implementation of `resume` is not equal to the original implementation of `af_resume`, THEN swizzle the methods
|
||||
8) Set the current class to the super class, and repeat steps 3-8
|
||||
*/
|
||||
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration ephemeralSessionConfiguration];
|
||||
NSURLSession * session = [NSURLSession sessionWithConfiguration:configuration];
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wnonnull"
|
||||
NSURLSessionDataTask *localDataTask = [[NSURLSession sessionWithConfiguration:nil] dataTaskWithURL:nil];
|
||||
NSURLSessionDataTask *localDataTask = [session dataTaskWithURL:nil];
|
||||
#pragma clang diagnostic pop
|
||||
IMP originalAFResumeIMP = method_getImplementation(class_getInstanceMethod([_AFURLSessionTaskSwizzling class], @selector(af_resume)));
|
||||
IMP originalAFResumeIMP = method_getImplementation(class_getInstanceMethod([self class], @selector(af_resume)));
|
||||
Class currentClass = [localDataTask class];
|
||||
|
||||
while (class_getInstanceMethod(currentClass, @selector(resume))) {
|
||||
|
@ -343,18 +394,21 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|||
}
|
||||
|
||||
[localDataTask cancel];
|
||||
[session finishTasksAndInvalidate];
|
||||
}
|
||||
}
|
||||
|
||||
+ (void)swizzleResumeAndSuspendMethodForClass:(Class)class {
|
||||
+ (void)swizzleResumeAndSuspendMethodForClass:(Class)theClass {
|
||||
Method afResumeMethod = class_getInstanceMethod(self, @selector(af_resume));
|
||||
Method afSuspendMethod = class_getInstanceMethod(self, @selector(af_suspend));
|
||||
|
||||
af_addMethod(class, @selector(af_resume), afResumeMethod);
|
||||
af_addMethod(class, @selector(af_suspend), afSuspendMethod);
|
||||
|
||||
af_swizzleSelector(class, @selector(resume), @selector(af_resume));
|
||||
af_swizzleSelector(class, @selector(suspend), @selector(af_suspend));
|
||||
|
||||
if (af_addMethod(theClass, @selector(af_resume), afResumeMethod)) {
|
||||
af_swizzleSelector(theClass, @selector(resume), @selector(af_resume));
|
||||
}
|
||||
|
||||
if (af_addMethod(theClass, @selector(af_suspend), afSuspendMethod)) {
|
||||
af_swizzleSelector(theClass, @selector(suspend), @selector(af_suspend));
|
||||
}
|
||||
}
|
||||
|
||||
- (NSURLSessionTaskState)state {
|
||||
|
@ -447,7 +501,7 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|||
|
||||
[self.session getTasksWithCompletionHandler:^(NSArray *dataTasks, NSArray *uploadTasks, NSArray *downloadTasks) {
|
||||
for (NSURLSessionDataTask *task in dataTasks) {
|
||||
[self addDelegateForDataTask:task completionHandler:nil];
|
||||
[self addDelegateForDataTask:task uploadProgress:nil downloadProgress:nil completionHandler:nil];
|
||||
}
|
||||
|
||||
for (NSURLSessionUploadTask *uploadTask in uploadTasks) {
|
||||
|
@ -459,9 +513,6 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|||
}
|
||||
}];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidResume:) name:AFNSURLSessionTaskDidResumeNotification object:nil];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidSuspend:) name:AFNSURLSessionTaskDidSuspendNotification object:nil];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
@ -518,64 +569,47 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|||
|
||||
[self.lock lock];
|
||||
self.mutableTaskDelegatesKeyedByTaskIdentifier[@(task.taskIdentifier)] = delegate;
|
||||
[self addNotificationObserverForTask:task];
|
||||
[self.lock unlock];
|
||||
}
|
||||
|
||||
- (void)addDelegateForDataTask:(NSURLSessionDataTask *)dataTask
|
||||
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
|
||||
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
|
||||
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
|
||||
{
|
||||
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
|
||||
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:dataTask];
|
||||
delegate.manager = self;
|
||||
delegate.completionHandler = completionHandler;
|
||||
|
||||
dataTask.taskDescription = self.taskDescriptionForSessionTasks;
|
||||
[self setDelegate:delegate forTask:dataTask];
|
||||
|
||||
delegate.uploadProgressBlock = uploadProgressBlock;
|
||||
delegate.downloadProgressBlock = downloadProgressBlock;
|
||||
}
|
||||
|
||||
- (void)addDelegateForUploadTask:(NSURLSessionUploadTask *)uploadTask
|
||||
progress:(NSProgress * __autoreleasing *)progress
|
||||
progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
|
||||
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
|
||||
{
|
||||
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
|
||||
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:uploadTask];
|
||||
delegate.manager = self;
|
||||
delegate.completionHandler = completionHandler;
|
||||
|
||||
int64_t totalUnitCount = uploadTask.countOfBytesExpectedToSend;
|
||||
if(totalUnitCount == NSURLSessionTransferSizeUnknown) {
|
||||
NSString *contentLength = [uploadTask.originalRequest valueForHTTPHeaderField:@"Content-Length"];
|
||||
if(contentLength) {
|
||||
totalUnitCount = (int64_t)[contentLength longLongValue];
|
||||
}
|
||||
}
|
||||
|
||||
if (delegate.progress) {
|
||||
delegate.progress.totalUnitCount = totalUnitCount;
|
||||
} else {
|
||||
delegate.progress = [NSProgress progressWithTotalUnitCount:totalUnitCount];
|
||||
}
|
||||
|
||||
delegate.progress.pausingHandler = ^{
|
||||
[uploadTask suspend];
|
||||
};
|
||||
delegate.progress.cancellationHandler = ^{
|
||||
[uploadTask cancel];
|
||||
};
|
||||
|
||||
if (progress) {
|
||||
*progress = delegate.progress;
|
||||
}
|
||||
|
||||
uploadTask.taskDescription = self.taskDescriptionForSessionTasks;
|
||||
|
||||
[self setDelegate:delegate forTask:uploadTask];
|
||||
|
||||
delegate.uploadProgressBlock = uploadProgressBlock;
|
||||
}
|
||||
|
||||
- (void)addDelegateForDownloadTask:(NSURLSessionDownloadTask *)downloadTask
|
||||
progress:(NSProgress * __autoreleasing *)progress
|
||||
progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock
|
||||
destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
|
||||
completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
|
||||
{
|
||||
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] init];
|
||||
AFURLSessionManagerTaskDelegate *delegate = [[AFURLSessionManagerTaskDelegate alloc] initWithTask:downloadTask];
|
||||
delegate.manager = self;
|
||||
delegate.completionHandler = completionHandler;
|
||||
|
||||
|
@ -585,29 +619,22 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|||
};
|
||||
}
|
||||
|
||||
if (progress) {
|
||||
*progress = delegate.progress;
|
||||
}
|
||||
|
||||
downloadTask.taskDescription = self.taskDescriptionForSessionTasks;
|
||||
|
||||
[self setDelegate:delegate forTask:downloadTask];
|
||||
|
||||
delegate.downloadProgressBlock = downloadProgressBlock;
|
||||
}
|
||||
|
||||
- (void)removeDelegateForTask:(NSURLSessionTask *)task {
|
||||
NSParameterAssert(task);
|
||||
|
||||
[self.lock lock];
|
||||
[self removeNotificationObserverForTask:task];
|
||||
[self.mutableTaskDelegatesKeyedByTaskIdentifier removeObjectForKey:@(task.taskIdentifier)];
|
||||
[self.lock unlock];
|
||||
}
|
||||
|
||||
- (void)removeAllDelegates {
|
||||
[self.lock lock];
|
||||
[self.mutableTaskDelegatesKeyedByTaskIdentifier removeAllObjects];
|
||||
[self.lock unlock];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (NSArray *)tasksForKeyPath:(NSString *)keyPath {
|
||||
|
@ -651,13 +678,11 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|||
#pragma mark -
|
||||
|
||||
- (void)invalidateSessionCancelingTasks:(BOOL)cancelPendingTasks {
|
||||
dispatch_async(dispatch_get_main_queue(), ^{
|
||||
if (cancelPendingTasks) {
|
||||
[self.session invalidateAndCancel];
|
||||
} else {
|
||||
[self.session finishTasksAndInvalidate];
|
||||
}
|
||||
});
|
||||
if (cancelPendingTasks) {
|
||||
[self.session invalidateAndCancel];
|
||||
} else {
|
||||
[self.session finishTasksAndInvalidate];
|
||||
}
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
@ -668,17 +693,36 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|||
_responseSerializer = responseSerializer;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
- (void)addNotificationObserverForTask:(NSURLSessionTask *)task {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidResume:) name:AFNSURLSessionTaskDidResumeNotification object:task];
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(taskDidSuspend:) name:AFNSURLSessionTaskDidSuspendNotification object:task];
|
||||
}
|
||||
|
||||
- (void)removeNotificationObserverForTask:(NSURLSessionTask *)task {
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:AFNSURLSessionTaskDidSuspendNotification object:task];
|
||||
[[NSNotificationCenter defaultCenter] removeObserver:self name:AFNSURLSessionTaskDidResumeNotification object:task];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
|
||||
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
|
||||
{
|
||||
return [self dataTaskWithRequest:request uploadProgress:nil downloadProgress:nil completionHandler:completionHandler];
|
||||
}
|
||||
|
||||
- (NSURLSessionDataTask *)dataTaskWithRequest:(NSURLRequest *)request
|
||||
uploadProgress:(nullable void (^)(NSProgress *uploadProgress)) uploadProgressBlock
|
||||
downloadProgress:(nullable void (^)(NSProgress *downloadProgress)) downloadProgressBlock
|
||||
completionHandler:(nullable void (^)(NSURLResponse *response, id _Nullable responseObject, NSError * _Nullable error))completionHandler {
|
||||
|
||||
__block NSURLSessionDataTask *dataTask = nil;
|
||||
dispatch_sync(url_session_manager_creation_queue(), ^{
|
||||
url_session_manager_create_task_safely(^{
|
||||
dataTask = [self.session dataTaskWithRequest:request];
|
||||
});
|
||||
|
||||
[self addDelegateForDataTask:dataTask completionHandler:completionHandler];
|
||||
[self addDelegateForDataTask:dataTask uploadProgress:uploadProgressBlock downloadProgress:downloadProgressBlock completionHandler:completionHandler];
|
||||
|
||||
return dataTask;
|
||||
}
|
||||
|
@ -687,54 +731,51 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|||
|
||||
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
|
||||
fromFile:(NSURL *)fileURL
|
||||
progress:(NSProgress * __autoreleasing *)progress
|
||||
progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
|
||||
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
|
||||
{
|
||||
__block NSURLSessionUploadTask *uploadTask = nil;
|
||||
dispatch_sync(url_session_manager_creation_queue(), ^{
|
||||
url_session_manager_create_task_safely(^{
|
||||
uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
|
||||
});
|
||||
|
||||
// uploadTask may be nil on iOS7 because uploadTaskWithRequest:fromFile: may return nil despite being documented as nonnull (https://devforums.apple.com/message/926113#926113)
|
||||
if (!uploadTask && self.attemptsToRecreateUploadTasksForBackgroundSessions && self.session.configuration.identifier) {
|
||||
for (NSUInteger attempts = 0; !uploadTask && attempts < AFMaximumNumberOfAttemptsToRecreateBackgroundSessionUploadTask; attempts++) {
|
||||
uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
|
||||
}
|
||||
}
|
||||
|
||||
if (!uploadTask) {
|
||||
uploadTask = [self.session uploadTaskWithRequest:request fromFile:fileURL];
|
||||
}
|
||||
|
||||
[self addDelegateForUploadTask:uploadTask progress:progress completionHandler:completionHandler];
|
||||
|
||||
[self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];
|
||||
|
||||
return uploadTask;
|
||||
}
|
||||
|
||||
- (NSURLSessionUploadTask *)uploadTaskWithRequest:(NSURLRequest *)request
|
||||
fromData:(NSData *)bodyData
|
||||
progress:(NSProgress * __autoreleasing *)progress
|
||||
progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
|
||||
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
|
||||
{
|
||||
__block NSURLSessionUploadTask *uploadTask = nil;
|
||||
dispatch_sync(url_session_manager_creation_queue(), ^{
|
||||
url_session_manager_create_task_safely(^{
|
||||
uploadTask = [self.session uploadTaskWithRequest:request fromData:bodyData];
|
||||
});
|
||||
|
||||
[self addDelegateForUploadTask:uploadTask progress:progress completionHandler:completionHandler];
|
||||
[self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];
|
||||
|
||||
return uploadTask;
|
||||
}
|
||||
|
||||
- (NSURLSessionUploadTask *)uploadTaskWithStreamedRequest:(NSURLRequest *)request
|
||||
progress:(NSProgress * __autoreleasing *)progress
|
||||
progress:(void (^)(NSProgress *uploadProgress)) uploadProgressBlock
|
||||
completionHandler:(void (^)(NSURLResponse *response, id responseObject, NSError *error))completionHandler
|
||||
{
|
||||
__block NSURLSessionUploadTask *uploadTask = nil;
|
||||
dispatch_sync(url_session_manager_creation_queue(), ^{
|
||||
url_session_manager_create_task_safely(^{
|
||||
uploadTask = [self.session uploadTaskWithStreamedRequest:request];
|
||||
});
|
||||
|
||||
[self addDelegateForUploadTask:uploadTask progress:progress completionHandler:completionHandler];
|
||||
[self addDelegateForUploadTask:uploadTask progress:uploadProgressBlock completionHandler:completionHandler];
|
||||
|
||||
return uploadTask;
|
||||
}
|
||||
|
@ -742,43 +783,42 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
|
|||
#pragma mark -
|
||||
|
||||
- (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request
|
||||
progress:(NSProgress * __autoreleasing *)progress
|
||||
progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock
|
||||
destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
|
||||
completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
|
||||
{
|
||||
__block NSURLSessionDownloadTask *downloadTask = nil;
|
||||
dispatch_sync(url_session_manager_creation_queue(), ^{
|
||||
url_session_manager_create_task_safely(^{
|
||||
downloadTask = [self.session downloadTaskWithRequest:request];
|
||||
});
|
||||
|
||||
[self addDelegateForDownloadTask:downloadTask progress:progress destination:destination completionHandler:completionHandler];
|
||||
[self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler];
|
||||
|
||||
return downloadTask;
|
||||
}
|
||||
|
||||
- (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData
|
||||
progress:(NSProgress * __autoreleasing *)progress
|
||||
progress:(void (^)(NSProgress *downloadProgress)) downloadProgressBlock
|
||||
destination:(NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination
|
||||
completionHandler:(void (^)(NSURLResponse *response, NSURL *filePath, NSError *error))completionHandler
|
||||
{
|
||||
__block NSURLSessionDownloadTask *downloadTask = nil;
|
||||
dispatch_sync(url_session_manager_creation_queue(), ^{
|
||||
url_session_manager_create_task_safely(^{
|
||||
downloadTask = [self.session downloadTaskWithResumeData:resumeData];
|
||||
});
|
||||
|
||||
[self addDelegateForDownloadTask:downloadTask progress:progress destination:destination completionHandler:completionHandler];
|
||||
[self addDelegateForDownloadTask:downloadTask progress:downloadProgressBlock destination:destination completionHandler:completionHandler];
|
||||
|
||||
return downloadTask;
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
||||
- (NSProgress *)uploadProgressForTask:(NSURLSessionUploadTask *)uploadTask {
|
||||
return [[self delegateForTask:uploadTask] progress];
|
||||
- (NSProgress *)uploadProgressForTask:(NSURLSessionTask *)task {
|
||||
return [[self delegateForTask:task] uploadProgress];
|
||||
}
|
||||
|
||||
- (NSProgress *)downloadProgressForTask:(NSURLSessionDownloadTask *)downloadTask {
|
||||
return [[self delegateForTask:downloadTask] progress];
|
||||
- (NSProgress *)downloadProgressForTask:(NSURLSessionTask *)task {
|
||||
return [[self delegateForTask:task] downloadProgress];
|
||||
}
|
||||
|
||||
#pragma mark -
|
||||
|
@ -878,7 +918,6 @@ didBecomeInvalidWithError:(NSError *)error
|
|||
self.sessionDidBecomeInvalid(session, error);
|
||||
}
|
||||
|
||||
[self removeAllDelegates];
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDidInvalidateNotification object:session];
|
||||
}
|
||||
|
||||
|
@ -991,9 +1030,12 @@ totalBytesExpectedToSend:(int64_t)totalBytesExpectedToSend
|
|||
totalUnitCount = (int64_t) [contentLength longLongValue];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:task];
|
||||
[delegate URLSession:session task:task didSendBodyData:bytesSent totalBytesSent:totalBytesSent totalBytesExpectedToSend:totalUnitCount];
|
||||
|
||||
if (delegate) {
|
||||
[delegate URLSession:session task:task didSendBodyData:bytesSent totalBytesSent:totalBytesSent totalBytesExpectedToSend:totalBytesExpectedToSend];
|
||||
}
|
||||
|
||||
if (self.taskDidSendBodyData) {
|
||||
self.taskDidSendBodyData(session, task, bytesSent, totalBytesSent, totalUnitCount);
|
||||
|
@ -1016,7 +1058,6 @@ didCompleteWithError:(NSError *)error
|
|||
if (self.taskDidComplete) {
|
||||
self.taskDidComplete(session, task, error);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#pragma mark - NSURLSessionDataDelegate
|
||||
|
@ -1056,6 +1097,7 @@ didBecomeDownloadTask:(NSURLSessionDownloadTask *)downloadTask
|
|||
dataTask:(NSURLSessionDataTask *)dataTask
|
||||
didReceiveData:(NSData *)data
|
||||
{
|
||||
|
||||
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:dataTask];
|
||||
[delegate URLSession:session dataTask:dataTask didReceiveData:data];
|
||||
|
||||
|
@ -1100,8 +1142,8 @@ didFinishDownloadingToURL:(NSURL *)location
|
|||
if (fileURL) {
|
||||
delegate.downloadFileURL = fileURL;
|
||||
NSError *error = nil;
|
||||
[[NSFileManager defaultManager] moveItemAtURL:location toURL:fileURL error:&error];
|
||||
if (error) {
|
||||
|
||||
if (![[NSFileManager defaultManager] moveItemAtURL:location toURL:fileURL error:&error]) {
|
||||
[[NSNotificationCenter defaultCenter] postNotificationName:AFURLSessionDownloadTaskDidFailToMoveFileNotification object:downloadTask userInfo:error.userInfo];
|
||||
}
|
||||
|
||||
|
@ -1120,8 +1162,12 @@ didFinishDownloadingToURL:(NSURL *)location
|
|||
totalBytesWritten:(int64_t)totalBytesWritten
|
||||
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
|
||||
{
|
||||
|
||||
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];
|
||||
[delegate URLSession:session downloadTask:downloadTask didWriteData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite];
|
||||
|
||||
if (delegate) {
|
||||
[delegate URLSession:session downloadTask:downloadTask didWriteData:bytesWritten totalBytesWritten:totalBytesWritten totalBytesExpectedToWrite:totalBytesExpectedToWrite];
|
||||
}
|
||||
|
||||
if (self.downloadTaskDidWriteData) {
|
||||
self.downloadTaskDidWriteData(session, downloadTask, bytesWritten, totalBytesWritten, totalBytesExpectedToWrite);
|
||||
|
@ -1133,8 +1179,12 @@ totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
|
|||
didResumeAtOffset:(int64_t)fileOffset
|
||||
expectedTotalBytes:(int64_t)expectedTotalBytes
|
||||
{
|
||||
|
||||
AFURLSessionManagerTaskDelegate *delegate = [self delegateForTask:downloadTask];
|
||||
[delegate URLSession:session downloadTask:downloadTask didResumeAtOffset:fileOffset expectedTotalBytes:expectedTotalBytes];
|
||||
|
||||
if (delegate) {
|
||||
[delegate URLSession:session downloadTask:downloadTask didResumeAtOffset:fileOffset expectedTotalBytes:expectedTotalBytes];
|
||||
}
|
||||
|
||||
if (self.downloadTaskDidResume) {
|
||||
self.downloadTaskDidResume(session, downloadTask, fileOffset, expectedTotalBytes);
|
||||
|
@ -1147,7 +1197,7 @@ expectedTotalBytes:(int64_t)expectedTotalBytes
|
|||
return YES;
|
||||
}
|
||||
|
||||
- (id)initWithCoder:(NSCoder *)decoder {
|
||||
- (instancetype)initWithCoder:(NSCoder *)decoder {
|
||||
NSURLSessionConfiguration *configuration = [decoder decodeObjectOfClass:[NSURLSessionConfiguration class] forKey:@"sessionConfiguration"];
|
||||
|
||||
self = [self initWithSessionConfiguration:configuration];
|
||||
|
@ -1164,10 +1214,8 @@ expectedTotalBytes:(int64_t)expectedTotalBytes
|
|||
|
||||
#pragma mark - NSCopying
|
||||
|
||||
- (id)copyWithZone:(NSZone *)zone {
|
||||
- (instancetype)copyWithZone:(NSZone *)zone {
|
||||
return [[[self class] allocWithZone:zone] initWithSessionConfiguration:self.session.configuration];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
|
Loading…
Add table
Reference in a new issue